手写call 和apply

我心飞翔 分类:javascript

apply,call,bind之间的相同点与区别

c5.image.png

apply、call、bind共同点

apply 、 call 、bind 三者都是用来改变函数的this对象的指向的;

apply 、 call 、bind 三者第一个参数都是this要指向的对象,也就是想指定的上下文;

apply 、 call 、bind 三者都可以利用后续参数传参;

apply、call、bind不同点

bind是偏函数型,返回对应函数,便于稍后调用,

apply、call则是立即调用,不同的是需要把参数按顺序传递进去,例如:func.call(this, arg1, arg2);。(非严格模式下)当参数数量不确定时,函数内部也可以通过 arguments 这个数组来遍历所有的参数。

而 apply 则是把参数放在数组里,例如:func.apply(this, [arg1, arg2])。

Call来实现改变this指向

 Function.prototype.myCall = function (context){
    var context = context || window;
    context.fn = this;
    var args = [];
    for(let i = 0,len = arguments.length;i<len;i++){
        args.push(i)
    }
    var result  = context.fn()
    delete context.fn
    return result
}
var a = {
    name:'xiaomin',
    getname:function(){
        console.log(this.name)
    }
}
var obj= {
    name:'xiaohong'
}
let c = a.getname
c.myCall(obj);
 

QQ截图20210407223534.png

这样利用了this的隐式绑定方法,当c在调用myCall时,myCall里面的this发生隐式绑定在了c这个函数上面,
在用我们接收到的对象生成这个方法即:

context.fn = this;
 

来实现在obj上面调用getname方法,自然里面的this也会指向我们传入得到的obj

当然这样做存在缺陷

即当我们传入得obj里面也有fn属性时会发生一些微小的差异:一把原先的值替换,二然后再删除这个属性

var obj = {
    name:'xiaohong',
    fn:'exact'
}
console.log(obj)
a.getname()
let c = a.getname
c.myCall(obj);
console.log(obj)
 

QQ截图20210407224807.png
所以一定要注意这个属性唯一且原对象没有这个属性

所以有如下改动

Function.prototype.call = function (context) {
    let context = context || window;
    // 合理使用symbol 生成一个独一无二的值
    let fn = Symbol('fn');
    context.fn = this;

    let args = [];
    for(let i = 1, len = arguments.length; i < len; i++) {
        args.push('arguments[' + i + ']');
    }

    let result = eval('context.fn(' + args +')');

    delete context.fn
    return result;
}
 

引自神三元大佬的代码

类似的实现apply函数

Function.prototype.apply = function (context, args) {
  let context = context || window;
  context.fn = this;
  let result = eval('context.fn(...args)');

  delete context.fn
  return result;
}
 

回复

我来回复
  • 暂无回复内容