call()与apply()的用法

1.call()

语法:obj1.call(obj2[,param1,param2,...])
定义:用obj2对象来代替obj1,调用obj1的方法。即将obj1应用到obj2上。
说明:call 方法可以用来代替另一个对象调用一个方法。call 方法可将一个函数的对象上下文从初始的上下文改变为由 obj2 指定的新对象。 如果没有提供 obj2参数,那么 Global 对象被用作 obj2。 

原理

Function.prototype.imitateCall = function (context) {
    // 赋值作用域参数,如果没有则默认为 window,即访问全局作用域对象
    context = context || window    
    // 绑定调用函数(.call之前的方法即this,前面提到过调用call方法会调用一遍自身,所以这里要存下来)
    context.invokFn = this    
    // 截取作用域对象参数后面的参数
    let args = [...arguments].slice(1)
    // 执行调用函数,记录拿取返回值
    let result = context.invokFn(...args)
    // 销毁调用函数,以免作用域污染
    Reflect.deleteProperty(context, 'invokFn')
    return result
}

 

2.apply()

语法:obj1.call(obj2[,arrArg])定义:用obj2对象来代替obj1,调用obj1的方法。即将obj1应用到obj2上。

说明:call ()和apply()作用一样,但是call()可以接收任何类型的参数,而apply()只能接收数组参数。

 

作用:这两个函数都是在特定的作用域中调用函数,能改变函数的作用域,实际上是改变函数体内 this 的值 。

Function.prototype.imitateApply = function (context) {
    // 赋值作用域参数,如果没有则默认为 window,即访问全局作用域对象
    context = context || window
    // 绑定调用函数(.call之前的方法即this,前面提到过调用call方法会调用一遍自身,所以这里要存下来)
    context.invokFn = this
    // 执行调用函数,需要对是否有参数做判断,记录拿取返回值
    let result
    if (arguments[1]) {
        result = context.invokFn(...arguments[1])
    } else {
        result = context.invokFn()
    }
    // 销毁调用函数,以免作用域污染
    Reflect.deleteProperty(context, 'invokFn')
    return result
}

 

3.基本用法:

function add(a,b){
        return a+b;
    }
    function sub(c,d){
        return c-d;
    }
    function result(){
        this.addValue = null;
        this.subValue = null;
        this.showResult=function(){
            alert(this.addValue);
            alert(this.subValue);
        }
    }   
    function myCallTest(){//此处this指向了add,如果不使用call则this指向window对象
            return add.call(this,7,2);
    }
    var r = new result();
    console.log(myCallTest());//9
    r.addValue = add.call(sub,4,2); //6,将add方法应用到sub上,即sub的指针指向add方法
    r.subValue = sub.call(add,4,2); //2,用add对象替换sub对象,并调用sub对象的方法
    r.showResult(); //在js中函数也是一个Function对象,函数名即是对象引用

 

4.继承特性

function add(a,b){
    return a+b;
}
function sub(c,d){
    return c-d;
}
function result(){
    this.addValue = null;
    this.subValue = null;
    this.showResult=function(){
        alert(this.addValue);
        alert(this.subValue);
    }
}
var r = new result();
r.addValue = add.call(r,4,2);    //6,r继承add函数的所有特性
r.subValue = sub.call(r,4,2);    //2,r集成sub函数的所有特性

 

5.bind()

bind()函数也可以改变this指向,但是该函数返回了一个新的函数(绑定函数),当调用绑定函数时,会以bind的第一个参数作为当前作用域的上下文(this),之后的参数则作为原函数的属性。

var write = document.write;
write.bind(document)("hello!");

这里write的this指向global或window,如果直接用write("hello!"),则非法调用(Illegal invocation),因为write的内部指向被修改为了window。所以需要bind重新调整索引,当然用call也可以。

var write = document.write;
write.call(document,"hello!");

call()、apply()都是立即执行的,bind()则是返回了一个函数,需再次调用才会执行。

原理:

Function.prototype.imitateBind = function (context) {
    // 获取绑定时的传参
    let args = [...arguments].slice(1),
        // 定义中转构造函数,用于通过原型连接绑定后的函数和调用bind的函数
        F = function () {},
        // 记录调用函数,生成闭包,用于返回函数被调用时执行
        self = this,
        // 定义返回(绑定)函数
        bound = function () {
            // 合并参数,绑定时和调用时分别传入的
            let finalArgs = [...args, ...arguments]
            
            // 改变作用域,注:aplly/call是立即执行函数,即绑定会直接调用
            // 这里之所以要使用instanceof做判断,是要区分是不是new xxx()调用的bind方法
            return self.call((this instanceof F ? this : context), ...finalArgs)
        }
    
    // 将调用函数的原型赋值到中转函数的原型上
    F.prototype = self.prototype
    // 通过原型的方式继承调用函数的原型
    bound.prototype = new F()
    
    return bound
}

 

 

————————————————
原文链接:https://blog.csdn.net/mafan121/article/details/52922149

上一篇:kubernetes资源类型和kubectl命令总结


下一篇:js批量添加数组,2个数组合并