手写call、apply、bind函数以及他们的区别

他们都是JS中改变this指向的方法,区别在于:

call和apply都是立即执行函数,他们的第一个参数都是函数调用时this的值,但是call的剩余参数为多个,依次传入,apply的剩余参数为一个数组;

bind和call的用法基本一样,但是bind会返回一个新的函数,所以bind不是立即执行函数,它的作用是延迟调用,可以用一个方法x来接受函数调用的bind函数,而且这个x方法也可以传入参数。

1.实现一个call函数:

function person() {
    console.log(this.name);
}
let egg = {
    name: 'hhh',
}
Function.prototype.newCall = function(obj) {
    obj.p = this;  // 将调用 newCall 的函数(即 person 函数)赋值给 obj 的 p 属性,
                   //此时p属性就相当于person函数了。
    obj.p();       // 调用 obj 的 p 方法(即 person 函数),此时 this 指向 obj。
                   //这时立即执行了obj.p(),也就是egg.p(),也就是egg.person()。
                   //此时相当于person 函数被egg对象调用,所以其中的 this 指向是 egg 对象
    delete obj.p;  // 删除 obj 上的 p 属性,清理环境
};
person.newCall(egg);//输出hhh

但是真正的call函数是可以传入多个参数的,再加以修改:

function person() {
    console.log(this.name);
}

let egg = {
    name: 'hhh',
};

Function.prototype.newCall = function(obj, ...args) {
    obj.p = this;
    obj.p(...args);
    delete obj.p;
};

// 测试示例
person.newCall(egg); // 输出:hhh

// 传递多个参数的示例
//call函数传入多个参数,本质上是调用call函数的那个函数需要接受多个参数
function greet(a, b) {
    console.log(`${a}, ${this.name}${b}`);
}

greet.newCall(egg, 'Hello', '!'); // 输出:Hello, hhh!

2.实现一个apply函数:

//apply和call函数只是传参有所区别,所以只改传参的方式即可
//call第二个参数为多个,apply第二个参数为一个数组

function person() {
    console.log(this.name);
}

let egg = {
    name: 'hhh',
};

Function.prototype.newApply = function(obj, argsArray) {
    obj.p = this;
    obj.p(...argsArray);
    delete obj.p;
};

// 测试示例
person.newApply(egg, []); // 输出:hhh

// 传递多个参数的示例
function greet(a, b) {
    console.log(`${a}, ${this.name}${b}`);
}

greet.newApply(egg, ['Hello', '!']); // 输出:Hello, hhh!

3.实现一个bind函数:

Function.prototype.newBind = function(obj, ...args) {
    // 保存当前函数的引用
    // 此时fn就是sayHello函数
    let fn = this;
    // 返回一个新的函数
    // innerArgs 是指绑定后返回的新函数(即闭包)的参数列表
    //这里也就是sayHello的参数列表
    return function(...innerArgs) {
        // 在新函数中调用原函数,并指定 this 和参数
        // this指向为第一个参数
        // 这时候相当于返回的是person调用的sayHello函数的apply执行
        return fn.apply(obj, [...args, ...innerArgs]);
    };
};

let person = {
    name: 'hhh'
};

function sayHello(a,b) {
    //this指向此时为person
    console.log(`${a}, ${this.name}!,${b}`);
}

// 使用 bind 方法将 sayHello 函数绑定到 person 对象上
// args参数此时是'Hi'
let boundFunction = sayHello.newBind(person, 'Hi');

// 调用绑定后的函数
// 'kkkkk'就是innerArgs参数
boundFunction('kkkkk'); // 输出: Hi, hhh!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值