Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

call / apply实现 #19

Open
songning0605 opened this issue Jul 30, 2020 · 0 comments
Open

call / apply实现 #19

songning0605 opened this issue Jul 30, 2020 · 0 comments
Labels

Comments

@songning0605
Copy link
Owner

songning0605 commented Jul 30, 2020

参考:

callapply 的作用

  • call() 的调用者应该是一个函数,call 会执行它的调用者,并且把接收到的第一个参数指定为调用者的 this 对象,其余参数会传递给 call() 的调用者。
  • apply() 的调用者应该是一个函数,apply 会执行它的调用者,并且把接收到的第一个参数指定为调用者的 this 对象,apply 接受两个参数,第二个是数组,会展开传递给 apply() 调用者。

举个例子:

var obj = {
  value: 1
}

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

test.call(foo); // 1

注意两点:

  1. call 改变了test 函数中 this 的指向,指向到 obj
  2. test 函数执行了

所以,如果要自己实现一个callapply 函数,关键要围绕这两步进行

自定义实现 call 函数,称为 customCall

  • 函数自身可以调用 customCall,所以customCall应该挂载载函数的原型上
Function.prototype.customCall = function(context) {
  // 函数调用customCall时,customCall中的this对象就是调用者
}

模拟实现

那么我们该怎么设计customCall的内部逻辑,模拟实现这两个效果呢?

试想当调用 customCall 的时候,把 this对象obj 改造成如下:

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

obj.customCall (); // 1

这个时候 this 就指向了 obj,是不是很简单呢?

但是这样却给 obj 对象本身添加了一个属性,需要用delete再删除它。

所以我们模拟的步骤可以分为:

  1. 将函数设为对象的属性
  2. 执行该函数
  3. 删除该函数

以上个例子为例,就是:

// 第一步
obj.fn = customCall 
// 第二步
obj.fn()
// 第三步
delete obj.fn

fn 是对象的属性名,反正最后也要删除它,所以起成什么都无所谓。

根据这个思路,我们可以尝试着去写 customCall 函数:

Function.prototype.customCall = function(context) {
  // customCall中的this对象,指向customCall的调用者,也就是要执行的函数
  context = context || window
  var contextType = typeof context;
  if (contextType  === 'number' || contextType  === 'string' || contextType   === 'boolean') {
    context = new 对应基本类型(context)
  }

  // 实现第一步,把函数设为context的属性,context涉及原始类型,如果context是基本类型,需要用对应的对象类型包装一下

  context.fn = this

  // 实现第二步,执行fn
  var args = [];
  for(var i = 1, len = arguments.length; i < len; i++) {
    args.push('arguments[' + i + ']');
  }

  context.fn(...args)

  // 模拟实现第三步
  delete context.fn
}
@songning0605 songning0605 changed the title call / apply / bind 的实现 call / apply实现 Aug 12, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant