call、apply、bind三者之间的用法和区别,并手写实现

call、apply、bind 的用法

1. 调用方法
let xw = {
    name : '小王',
    gender : '男',
    age : 24 ,
    say : function() {
        console.log(this.name + ',性别' + this.gender + ',年龄' + this.age);
    }
}
let xh = {
    name : '小红',
    gender : '女',
    age : 20
}
let xl = {
    name : '小蓝',
    gender : '男',
    age : 22
}
xw.say();  // this还是原来的xw的
xw.say.call(xh);   // this指向xh
xw.say.apply(xl);  // this指向xl
xw.say.bind(xh)(); // this指向xh
2. 传参方法
let xw = {
    name : '小王',
    gender : '男',
    age : 24 ,
    say : function(school , grade) {
        console.log(this.name + ',性别' + this.gender + ',年龄' + this.age + ',在' + school + "上" + grade);
    }
}
let xh = {
    name : '小红',
    gender : '女',
    age : 20
}
let xl = {
    name : '小蓝',
    gender : '男',
    age : 22
}
xw.say("实验小学","六年级");
xw.say.call(xh , "实验小学","六年级");
xw.say.apply(xl , ["实验小学","六年级"]);
xw.say.bind(xh,"实验小学","六年级")();
xw.say.bind(xl)("实验小学","六年级");

call、apply、bind 的区别

callapplybind 的共同点都是为了解决改变 this 的指向。作用都是相同的,只是传参的方式不同。

不同点:

  • call()apply() 是立即执行的,而 bind() 是返回一个函数。
  • call() 可以传递多个参数,第一个参数和 apply() 一样,是用来替换的对象,后面是参数列表。
  • apply() 最多只能有两个参数 —— 新this 对象和一个参数数组 argArray
  • bind() 和其他两个方法的作用也是一致的,只是该方法会返回一个函数,并且可以通过bind() 实现 柯里化

柯里化会在下一篇文章进行较为详细的介绍。

手写实现call()、apply()、bind() 函数

对于实现以下三个函数,可以从这几个方面进行考虑:

  • 不传入第一个参数,那么默认为 window
  • 改变了 this 指向,让新的对象可以执行该函数。那么思路就可以变成给新的对象添加一个函数,然后在执行完以后删除。
手写实现 call()
Function.prototype.myCall = function( context ){
    // 1. 判断有没有传入要绑定的对象,没有默认为window;如果是基本类型的话通过Object()方法进行转换
    var context = Object(context) || window;

    // 2. 给context添加一个fn属性,值为this,也就是fn()
    context.fn = this;

    // 3. 保存返回值
    let result = '';

    // 4. 取出传递的参数,第一个参数是this
    // 截取除第一个参数外剩余参数的方法
    const args = [...arguments].slice(1);
    // const args = Array.prototype.slice.call(arguments , 1);
    // const args = Array.from(arguments).slice(1);

    // 5. 执行方法,传入参数
    // ... 是es6的展开数组
    result = context.fn(...args);

    // 6. 删除该属性
    delete context.fn;

    // 7. 返回结果
    return result;
}

// 测试用例
const obj = {
    value :'hello'
}
function fn(name , age){
    return {
        value : this.value ,
        name , 
        age
    }
}
let res = fn.myCall(obj , 'LL' , 25);
console.log(res) // { value: 'hello', name: 'LL', age: 25 }
手写实现 apply()
Function.prototype.myApply = function( context , args ){
    var context = Object(context) || window;
    context.fn = this;
    let result = '';

    // 4. 判断有没有传入第二个参数 args,如果传入就将第二个参数展开
    if(!args){
        // 没有传入,直接返回该函数
        result = context.fn();
    }else{
        // 传入了,将参数展开
        result = context.fn(...args);
    }

    delete context.fn;
    return result;
}

// 测试用例
const obj = {
    value :'hello'
}
function fn(name , age){
    return {
        value :this.value ,
        name , 
        age
    }
}
let res = fn.myApply(obj ,[ 'LL' , 25]);
console.log(res) // { value: 'hello', name: 'LL', age: 25 }
手写实现 bind()
Function.prototype.myBind = function( context ){
    // 1. 判断this是不是一个函数
    if(typeof this !== 'function'){
        // 不是函数,抛出错误
        throw new Error('不是一个函数');
    }
    // 2. 暂存this
    const self = this;

    // 3. 获取传入的参数
    // 拿到第一组参数,如果没传,是一个空数组
    const args1 = [...arguments].slice(1);

    // 第二次调用bindFn
    const bindFn = function(){
        // 获取第二个参数
        const args2 = [...arguments];
        // 将第一部分参数和第二部分参数合并到一起,进行返回
        return self.apply(context , args1.concat(args2));
    }
    return bindFn
}

// 测试用例
const obj = {
    value :'hello'
}

function fn(name , age){
    return {
        value :this.value ,
        name , 
        age
    }
}
let res = fn.myBind(obj)('HH' , 30);
console.log(res)
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
call、applybind都是用来改变函数中的this指向的方法。其中,call和apply可以直接调用函数并传递参数,而bind则返回一个新的函数,需要手动调用。 具体实现方案如下: - call的实现: 1. 给想要绑定的对象设置一个属性,并将该属性指向需要调用的函数。 2. 使用该对象调用函数,并传递参数。 3. 结束调用后,删除该属性。 - apply实现: 1. 给想要绑定的对象设置一个属性,并将该属性指向需要调用的函数。 2. 使用该对象调用函数,并传递参数数组。 3. 结束调用后,删除该属性。 - bind实现: 1. 创建一个新的函数,并将原函数作为其中的属性保存起来。 2. 当新函数被调用时,将之前绑定的对象作为this,并传递参数。 3. 返回新函数供后续调用。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *3* [如何实现call、applybind](https://blog.csdn.net/XIAO_A_fighting/article/details/116701887)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] - *2* [原生JS实现 call apply bind](https://download.csdn.net/download/weixin_38628990/14046564)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 50%"] [ .reference_list ]

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值