call,apply,bind实现原理

304 阅读2分钟

JavaScript中的每一个function对象的原型上都会有call,apply和bind方法.都是用于改变函数运行时上下文,最终的返回值是你调用的方法的返回值,若该方法没有返回值,则返回undefined。

call()的理解 B.call(A, args1,args2)

call:调用一个对象的一个方法,用另一个对象替换当前对象。例如:B.call(A, args1,args2);即A对象调用B对象的方法. 上代码

let cat = {
    name: 'cat',
}
let dog = {
    name: 'dog',
    eat(a,b){
        console.log(this.name+`在吃${a}在喝${b}`);    
    }
}

两种动物都有吃这个行为,要用cat调用dog上的方法.

dog.eat.call(cat,'猫粮','水');
Math.max.call(null,1,2,3,4,5);

此时我们就cat对象调用dog对象上的方法完成了. 实现一个自己封装的call.

Function.prototype.myCall = function(context){
    console.log(context)         // 相当于传进来的 cat对象
    context = context || window; // 有可能传进来null
    
    // 这里的this相当于dog.eat,相当于在cat对象上创建了一个方法
    context.fn = this;           // 
    
    var args = [];              // 接收其余的参数
    var res;                    // 返回结果  
    
    // 通过arguments接收其余传进来的参数
    for (var i = 1;i<arguments.length;i++){
        args.push(arguments[i])
    }
    
    res = context.fn(...args);   // 执行函数
    delete context.fn;
    return res;
}
dog.eat.myCall(cat,'猫粮','水');

apply()的理解 B.apply(A,[args1,args2]);

apply()本质上跟call()的区别不大,只是传参的时候,call()可以多个传参,而apply()的第二个参数为数组或类数组. 直接来封装的源码解析

Function.prototype.myApply = function(context,argsArr){
    context || context || window;
    context.fn = this;
    var args = [];
    var res;
    for(var i = 0;i<argsArr.length;i++){
        args.push(argsArr[i])
    }
    res = context.fn(...args)
    delete context.fn
    return res;
}
dog.eat.myApply(cat,'猫粮','水');

apply和call的区别:

在于将参数传递给函数。 call():使用其自有的实参列表作为函数的参数; apply():要求以数组的形式传入参数

bind B.bind(A, args1,args2)(args3)

let catEat = dog.eat.bind(cat,"猫粮","水")
catEat("哈哈哈  哈");

bind的不是立即执行,bind会返回一个函数,(柯理化函数思想)

Function.prototype.myBind = function(context,...args){
        // =>THIS: FN(当前需要处理的函数)
	// => CONTEXT: OBJ(需要把FN中的THIS改为谁就传递谁);
	// => ARG: 传递哥FN的实参(数组); ["猫粮","水"]
	// 返回一个匿名函数
	
	/*
	 * 每次执行BIND,都形成一个不销毁的私有栈内存,返回一个新的匿名函数(每一次返回的不一样:不是相同的堆内存)
	 * 存储内容
	 * =>THIS: FN(当前需要处理的函数)
	 * => CONTEXT: OBJ(需要把FN中的THIS改为谁就传递谁);
	 * => ARG: 传递哥FN的实参(数组);	[ev]
	 *
	 * dog.eat = function anonymous(){    }
	*/ 
	
    let that = this;        // 此时的this相当于是当前需要处理的函数
    return function anonymous(...innerArg){
        that.apply(context,args.concat(innerArg)) 
    }
}

bind()和apply(),call()的区别

bind()返回一个函数,不会立即执行

apply(),call()会立即执行.