手写 call

2020-03-13  本文已影响0人  弹指一挥间_e5a3

call 的功能

var obj = {
    value:1
}
function foo(){
    console.log(this.value)
}
foo.call(obj)  //1

上段代码可以看出 call的功能:

基于此,我们可以这么写:

第一版:

Function.prototype.call2 = function(context){
      context.fn = this;
      context.fn();
      delete context.fn;
}
foo.call2(obj); // 1

上面代码中的 this 就是被执行的函数 foo(); context 就是传入的对象 obj. 不信你可以自行打印一下.

等同于, 这里需要细品:

var obj = {
    value:1,
    foo:function(){
        console.log(this.value)
  }
}
obj.foo() //1

第二版

第二版解决的问题是 call 能够传入参数的问题,而上一版写的没有这个功能.
例如:

var obj = {
  value:1
}
function foo(name,age){
  console.log(name)
  console.log(age)
  console.log(this.value)
}
foo.call(obj,'wuxuwei',18)  // 1 'wuxuwei' 18

这个其实简单,因为函数有个 arguments . 写法如下

Function.prototype.call2 = function(context){
  context.fn = this;
  const args = [];
  for(let i = 1, len = arguments.length; i < len ; i++){
    args.push(arguments[i]);
  };
  context.fn(...args);
  delete context.fn
}
foo.call2(obj,'wuxuwei',18)  // 1 'wuxuwei' 18

第三版(终极版)

这一版需要解决两个问题

1.this 参数可以传 null,当为 null 的时候,视为指向 window

var value = 2;

function bar() {
    console.log(this.value);
}

bar.call(null); // 2
2.函数是可以有返回值的!
var obj = {
    value: 1
}

function foo(name, age) {
    return {
        value: this.value,
        name: name,
        age: age
    }
}

console.log(foo.call(obj, 'wuxuwei', 18));
// Object {
//    value: 1,
//    name: 'wuxuwei',
//    age: 18
// }

基于此,我们这么写:

  var context = context || window;
  context.fn = this;
  console.log(context);
  const args = [];
  for(var i = 1, len = arguments.length; i < len; i++) {
        args.push( arguments[i]);
  }
  var result = context.fn(...args);
  delete context.fn
  return result
foo.call2(null)
console.log(foo.call2(obj,'wuxuwei',18))
// 2
// Object {
//    value: 1,
//    name: 'kevin',
//    age: 18
// }
上一篇下一篇

猜你喜欢

热点阅读