闲来无事,来总结一波call,apply和call | 青训营笔记

34 阅读3分钟

call, apply, 和 bindJavaScript 中用于控制函数执行时 this 值的方法。

这其中,callapply 非常相似,它们的第一个参数都是要绑定的 this 值,接下来的参数则是传入函数的参数。它们的区别在于传入的参数的形式不同。

对于 call 方法,之后的参数是要传递给函数的参数列表。

下面是call的例子:

function greet(name,age) {
    console.log(`Hello, ${name}!Your number is ${age}`);
}


greet.call(null,' Alice',13); // Hello, join!Your number is 13

而对于 apply 方法,之后的参数需要以数组的形式传递。

相同的例子,使用apply的话就是:

function greet(name,age) {
    console.log(`Hello, ${name}!Your number is ${age}`);
}


greet.apply(null,[' Alice',13]); // Hello, join!Your number is 13

无论是 call 还是 apply,它们的作用都是调用函数,并将指定的 this 值和参数传递给函数。它们之间的主要区别在于参数的传递方式。

现在说bindbindcall的传参方式是一样的,区别是bind不会像call一样当即调用,而是返回一个全新的函数,待你想调用的时候再调用。

下面是例子:

function greet(name,age) {
    console.log(`Hello, ${name}!Your number is ${age}`);
}


const hello = greet.bind(null,' Alice',13); // 这里是不会调用的
hello()//Hello,  Alice!Your number is 13

接下来便是大伙喜闻乐见的手写call,applybind

首先是手写call:

function类的原型链上添加自己写的call给别的函数调用

Function.prototype.myCall = function(target,...args){
  target = target || window //当target不存在时,给个window
  const symbolKey = Symbol();//创造独一无二的变量
  target[symbolKey] = this;//这里的this其实就是函数,将函数加到调用的对象身上去
  //例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上
  const res = target[symbolKey](...args)//调用函数
  delete target[symbolKey];//调用完了立马删掉
  return res;//返回结果
}

难点就是这里this赋值的理解,实际上就是把函数(this)当成个对象,然后赋值给target

例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上

apply也是一样的:

Function.prototype.myApply = function(target,...args){
  target = target || window //当target不存在时,给个window
  const symbolKey = Symbol();//创造独一无二的变量
  target[symbolKey] = this;//这里的this其实就是函数,将函数加到调用的对象身上去
  //例如 Person.say.myCall(Person2)时,myCall的this其实就是say,就比如obj.say()的this是obj一样,就近原则myCall的this就是函数,这里把函数赋值到调用的对象的身上
  const res = target[symbolKey](...args)//调用函数
  delete target[symbolKey];//调用完了立马删掉
  return res;//返回结果
}

完全套用

接下来是bind:

这里困难一点,因为涉及到了闭包

Function.prototype.myBind = function(target,...outArgs){
  target = target || {} //如果没有传入target的话,那调用的可不就是个空对象嘛
  const symbolKey = Symbol();
  target[symbolKey] = this;//再说一次,将调用的函数添加到target身上
  return function(...innerArgs){
    const res = target[symbolKey](...outArgs,...innerArgs);
    //这里传入的参数说下,第一次用bind的时候可以传一次参数,返回的函数调用时也可以再传一次参数
    //不需要delect这个函数,必须保证第二次调用时不出问题
    return res
  }
}

总结到这里就结束了,有什么不明白的可以找我一起探讨