笔记——call、apply、bind函数实现

51 阅读1分钟

call函数

原理解析:

(1)利用原型链,在Function上定义callFun函数,函数调用时通过原型链在Function的prototype上找到callFun方法。

(2)利用this指向调用者,由于this指向调用者,当mbs.say.callFun调用时,say为调用者,此时call中的this指向say函数,通过给传入对象target新增对象属性,为对象添加say函数;执行时由于调用者是target对象,此时say函数中的this指向了target,从而实现改变this指向的功能。

(3)执行完成后,删除新增的属性。

实现:

Function.prototype.callFun = function (target, ...args) {
    const sKey = Symbol()
    target = target || window
    target[sKey] = this
    const result = target[sKey](...args)
    delete target[sKey]
    return result
}

const obj = {
    base: 'MT',
    keep(args) {
        console.log(`args : ${args}, base : ${this.base}`)
    }
}

const A = {
    base: 'XBLL'
}

obj.keep(3);
obj.keep.callFun(A, 9);

apply函数

原理解析:

同call函数,只是把参数换成了数组,其他都一样;

实现:

Function.prototype.applyFun = function (target, args) {
    const sKey = Symbol()
    target = target || window
    target[sKey] = this
    const result = target[sKey](...args)
    delete target[sKey]
    return result;
}

const obj = {
    base: 'MT',
    keep(args) {
        console.log(`args : ${args}, ${this.base}`)
    }
}

const A = {
    base: 'XBLL'
}

obj.keep(9);
obj.keep.applyFun(A, [9]);

bind函数

原理解析:

(1)按照已经实现的call和aplly方法,bind的原理是一样的。首先通过在Function的prototype中添加属性bindFun。然后利用this指向调用者的特性将方法转移到目标对象上,再利用目标对象执行函数,此时由于this指向的是执行者,从而将调用函数中的this指向目标对象,完成this的指向转移。

(2)但是bind返回的并不是执行结果,而是一个函数。如果直接把函数作为返回值。 例如:

Function.prototype.bindFun = function(target) {
    const sKey = Symbol()
    target = target || {}
    target[sKey] = this
    return target[sKey];
}

const obj = {
    base: 'MT',
    keep() {
        console.log(`base : ${this.base}`);
    }
}

const B = {
    base: 'XBLL'
}

obj.keep()

const keepB = obj.keep.bindFun(B);
keepB();

结果是并没有拿到B中的name。

image.png

因为此时函数内部this指向的是全局的window对象,可以在window上挂载一个base属性,会发现这时会获取到window对象上的name(因为此时没有像之前call那样通过target对象直接去执行,this指向的是调用者,所以单纯执行函数时this就指向了全局的windowd对象)。

(3)这时我们可以利用闭包的特性,返回函数时将target对象捕获,然后再将函数返回。例如:

Function.prototype.bindFun = function(target) {
    const sKey = Symbol();
    target = target || {};
    target[sKey] = this;
    return function() {
        target[sKey]();
    }
}

image.png

完整的实现:

Function.prototype.bindFun = function (target, ...param1) {
    const sKey = Symbol()
    target = target || {}
    target[sKey] = this
    return function (...param2) {
        target[sKey](...param1, ...param2);
    }
}

const obj = {
    base: 'MT',
    keep(args1, args2) {
        console.log(`args1 : ${args1}, args2: ${args2}, base: ${this.base}`)
    }
}

const B = {
    base: 'XBLL',
}

obj.keep('hello', 6);

const keepB = obj.keep.bindFun(B, 'hello');
keepB(9);