改变this指向实现call, apply, bind

call

fun.call(thisArg, arg1, arg2, …)

Function.prototype.myCall = function (obj, ...rest) {
    var context = obj || window;

    context.fn = this;

    var result = context.fn(...rest);

    delete context.fn;

    return result;
}

apply

func.apply(thisArg, [argsArray])

Function.prototype.myApply = function (obj, rest) {
    var context = obj || window;

    context.fn = this;

    var result = context.fn(...rest);

    delete context.fn;

    return result;
}

bind

fun.call(thisArg, arg1, arg2, …)
返回一个原函数的拷贝,并拥有指定的this值和初始参数。

只有参数列表会叠加

Function.prototype.myBind = function (obj, ...rest) {
    var context = obj || window;

    context.fn= this;

    return function() {
        var result = context.fn(...rest, ...arguments);

        delete context.fn;

        return result;
    }
}

let obj = {
    name: "lala",
    age: this.age,
    show: function() {
        console.log(this.name, this.age);
        return [...arguments].reduce((a,b) => {
            return a+b;
        }, 0)
    }
}

obj.show();
obj.show.myCall({name: "nene", age: 12}, 1,2,3,4);
obj.show.myApply({name: "nene", age: 12}, [1,2,3,4]);
obj.show.myBind({name: "nene", age: 12}, 1,2,3,4)(5,6);

依赖call || apply实现(参数处理的不同啦)

Function.prototype.myBind = function (obj, ...rest) {
    const self = this;
	const context = obj || window;
	
    return function() {
        return self.call(obj, ...rest, ...arguments);
    }
}

考虑bind返回的函数用作构造函数

Function.prototype.myBind = function (obj, ...rest) {
    var self = this;
    const context = obj || window;

    return function F() {
        if (this instanceof F) {
            return new self(...rest, ...arguments);
        }

        return self.call(context, ...rest, ...arguments);
    }
}

es5

function bind(obj) {
    if (typeof obj === "object") {
        obj = obj || window;
    } else {
        obj = Object.create(null);
    }
    let rest = [];
    // call, bind
    for(let i = 1; i < arguments.length; i++) {
        rest.push(arguments[i]);
    }
    let self = this;
    let F = function() {};
    let bound = function () {
        let finalArgs = [...rest, ...arguments];
        let result = self.call((this instanceof F ? this : obj), ...finalArgs);
        return result;
    };
    F.prototype = self.prototype;
    bound.prototype = new F();
    return bound;
}
new func('4th'); //undefined 100 1st 4th

// 从 ES5 的 bind 函数说明中我们知道,当我们用一个函数调用 bind 的时候,
// 返回的函数中会保存这三个参数。所以最后调用 call 的时候执行的函数是目标函数,
// 也就是调用了 bind 的函数,传入的 this 也是 bind 调用时传入的,这些都是无法被修改的了,
// 但是参数是调用 bind 和 call 时的叠加,这是我们唯一可以修改的地方。
// 执行两次 bind 的原理可以参考 bind 的源码,和 call 的差不多,也是目标函数和 this 是被固定的了,只有参数列表会叠加
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值