面试题 手写call apply bind 详细解析

1.apply

apply()方法指定this值参数(参数以数组或者类数组对象的形式存在)的情况下调用某个函数,意思是它可以改变一个函数的执行环境,语法:

fn.apply(thisArg[, argsArray])
  • thisArg: 在fn函数运行时指定的this值。需要注意的是,指定的this值并不一定是该函数执行时真正的this值,如果这个函数处于非严格模式下,则指定null或undefined时会自动指向全局对象(浏览器中就是window对象),同时值为原始值(数字,字符串,布尔值)的this会指向该原始值的自动包装对象。
  • argsArray: 一个数组或者类数组对象,其中的数组元素作为单独的参数传给fn函数。如果该参数为null或undefined,则表示不传入任何参数。从ECMAScript 5开始可以使用类数组对象。
function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '李华'}
fn.apply(obj, [1,2,3])
// 输出结果:
//李华 
//1 2 3

2.call

call和apply作用一样,不同的是两者的参数传入不一样,apply第一个参数和call没有区别,但是第二个参数就不同了,apply是以数组或者类数组的形式传入的,而call是将这个数组展开,一个一个的形式传入的,说的比较绕,下面我们看一下代码示例就能理解了。语法:(注意:中括号表示可选,不是数组的意思)

fn.call(thisArg[,arg1,arg2...]);

  • thisArg: 和apply第一个参数一样
  • arg1:作为第一个参数传给fn函数
  • arg2:作为第二个参数传给fn函数
  • ......依此类推
function fn (a,b,c) {
    console.log(this.name)
    console.log(a, b, c)
}
let obj = {name: '李华'}
fn.call(obj, 1, 2, 3)
// 输出  
//李华  
//1 2 3

 3.bind

bind() 方法会创建一个新函数,当这个新函数被调用时,它的 this 值是传递给 bind() 的第一个参数, 它的参数是 bind() 的其他参数和其原本的参数。 (这里需要注意bind返回的是一个函数,bind自身不会立即执行这个函数;而apply和call立即执行这个函数,返回执行后的结果) 语法:

fn.bind(thisArg[, arg1[, arg2[, ...]]])

  • thisArg 当绑定函数被调用时,该参数会作为原函数运行时的 this 指向。当使用 new 操作符调用绑定函数时,该参数无效。
  • arg1, arg2, … (可选)当绑定函数被调用时,这些参数加上绑定函数本身的参数会按照顺序作为原函数运行时的参数。

function fn(a, b, c) {
  console.log(this);
}

var fn1 = fn.bind({a:123});
fn(); // 输出:window
fn1(); // 输出:{a:123}

 

手写实现

1.手写call

    function foo(name, age) {
      console.log(this, name, age)
    }



Function.prototype.myCall = function(thisArg, ...thisArgs){

        // this -> 调用的函数对象
      // thisArg -> 传入的第一个参数, 要绑定的this
      // console.log(this) // -> 当前调用的函数对象
      // this.apply(thisArg)
      // console.log(this)
      // console.log(thisArg)
      // thisArg.fn = this
                    
  // 判断 thisArg是不是一个对象  如果不是 需要包装成对象
    thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)
         
    // 给这个 thisArg  对象 添加一个 属性  fn   然后执行这个fn
      //  这个时候的 fn的this 指向就是  当前函数
    Object.defineProperty(thisArg,fn,{
        
    configurable:true,
    enumerable:false,
    value:this
//thisArg.fn = this = foo
})

          thisArg.fn(...otherArgs) //执行

      delete thisArg.fn  //删除
  }

foo.myCall({ name: "why" }, 123, 456)
    //   foo调用myCall()的时候 foo成了myCall()的this   所以代码里 foo= this = thisArg.fn

  2. 手写apply

    function foo(name, age) {
      console.log(this, name, age)
    }



Function.prototype.myCall = function(thisArg, ...thisArgs){

       // this -> 调用的函数对象
      // thisArg -> 传入的第一个参数, 要绑定的this
      // console.log(this) // -> 当前调用的函数对象
      // this.apply(thisArg)
      // console.log(this)
      // console.log(thisArg)
      // thisArg.fn = this
                    
  // 判断 thisArg是不是一个对象  如果不是 需要包装成对象
    thisArg = (thisArg === null || thisArg === undefined) ? window : Object(thisArg)
         
    // 给这个 thisArg  对象 添加一个 属性  fn   然后执行这个fn
      //  这个时候的 fn的this 指向就是  当前函数
    Object.defineProperty(thisArg,fn,{
        
    configurable:true,
    enumerable:false,
    value:this
//thisArg.fn = this = foo
})

          thisArg.fn(...otherArgs) //执行

      delete thisArg.fn  //删除
  }

foo.myCall({ name: "why" }, 123, 456)
    //   foo调用myCall()的时候 foo成了myCall()的this   所以代码里 foo= this = thisArg.fn

3. 手写bind

    function foo(name, age, height, address) {
      console.log(this, name, age, height, address)
    }


// 实现hybind函数
    Function.prototype.hybind = function(thisArg, ...otherArgs) {
      // console.log(this) // -> foo函数对象
      thisArg = thisArg === null || thisArg === undefined ? window: Object(thisArg)
      Object.defineProperty(thisArg, "fn", {
        enumerable: false,
        configurable: true,
        writable: false,
        value: this
      })

      return (...newArgs) => {
        // var allArgs = otherArgs.concat(newArgs)
        var allArgs = [...otherArgs, ...newArgs]
        thisArg.fn(...allArgs)
      }
    }

    var newFoo = foo.hybind("abc", "kobe", 30)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值