javascript必备面试题:手撕call、apply、bind以及他们之间的区别

手撕call、apply、bind以及他们之间的区别

为什么要改变this指向?

bind,call,apply三者都是用来改变this的指向,那为何要改变呢

var name="tom";
let obj={
 name:"tory",
 sayHello:function () {
 	console.log(this.name);
 }
};
obj.sayHello(); //tory,this指向obj对象
setTimeout(obj.sayHello,0); //tom,this指向window对象

可以观察到,正常情况下 sayHello方法中的 this 是指向调用它的 obj 对象的,而定时器 setTimeout 中的 say 方法中的 this 是指向window对象的(在浏览器中),这是因为 say 方法在定时器中是作为回调函数来执行的,因此回到主栈执行时是在全局执行上下文的环境中执行的,但我们需要的是 say 方法中 this 指向obj对象,因此我们需要修改 this 的指向。

call apply bind 的作用与区别?

  • 相同点:call 和 apply 和 bind 都可以改变this指向,都可以传参
  • 不同点call apply自动调用,bind需要再调一次,bind的返回的是对应函数
  • call apply 如果第一个参数指定了 null 或者 undefined 则内部 this 指向 window

1、call()方法

 	function fn(a, b) {
        console.log(this);
        console.log(this.name, a, b);
        return this.name
    }
    let obj = {
        name: 123
    }
    
    Function.prototype.mycall = function (o, ...args) {
        o = o || window  // 为了防止在第一参数传入null underfind时指向window
        o.fn = this
        // 第一种方案
        // let res = o.fn(...args)
        // 第二种方案  采用eval
        let newArr = []
        for (let i = 1; i < arguments.length; i++) {
            newArr.push(`arguments[${i}]`)
        }
        console.log('arguments',newArr);
        // .join(',') 加与不加都行 数组转换成字符串本来就会分割
        let res = eval(`o.fn(${newArr.join(',')})`)
        delete o.fn
        return res
    }
    let res = fn.mycall(obj, 1, 2)
    console.log("####",res);
    // fn.mycall(null, 1, 2)
    fn.mycall(obj,1,{})

2、bind()方法

	function fn(a, b) {
        console.log(this.name, a, b);
        return this.name
    }
    let obj = {
        name: 123
    }
    Function.prototype.myapply = function (o, args) {
        o = o || window
        o.fn = this
        let res = null
        if (!args) {
            res = o.fn()
        } else {
            // 第一种方案
             res = o.fn(...args)
            // 第二种方案  采用eval
            // let newArr = []
            // for (let i = 0; i < args.length; i++) {
            //     newArr.push(`args[${i}]`)
            // }
            // console.log('args', newArr);
            // // .join(',') 加与不加都行 数组转换成字符串本来就会分割
            // res = eval(`o.fn(${newArr.join(',')})`)
        }
        delete o.fn
        return res
    }
    // fn.myapply(obj, [1, 2])
    // console.log("####", res);
    fn.myapply(null, [1, 2])
    // fn.myapply(obj, 1, {})

3、bind()方法

	function fn(a,b,c){
        console.log("$$$",this.name,a,b,c);
    }
    let o ={
        name:"你好"
    }
    Function.prototype.myBind = function(o){
        let that = this;
        console.log(arguments);
        let args1 = Array.prototype.slice.call(arguments,1)
        return function(){
            let args2 = Array.prototype.slice.call(arguments)
            console.log(args2);
            // 第一种方案
            // that.apply(o,args1.concat(args2))  
            console.log("$$$",args1.push.apply(args1,args2));
            // 第二种方案
            that.apply(o,args1.push.apply(args1,args2) && args1)
        }
    }

    fn.myBind(o,1,2)(123)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值