call,apply与bind

181 阅读5分钟
这是一篇纯属小菜级别的关于知识点的记录,受juejin.cn/post/684490…这篇文章的启发,不算时文章,其实我并不会写文章,身为前端技术也很匮乏,看到别人写的文章也很羡慕,第一篇就是关于call,apply,bind这三个方法的知识点的记录,大部分的讲解来源于MDN上的文档说明,各种大牛的文章都是把各种知识点串联起来进行讲解,自己目前还没有那么强的基础功底与写作能力,我会一步一个脚印,慢慢的把这些基础知识像那些优秀的文章一样能够关联起来,也希望路过的有缘的小伙伴有好的建议和批评欢迎随时指正。

func.apply(thisArg, [argsArray])

参数

thisArg:可选参数,在函数func运行时的this值。请注意,this可能不是该方法下看到的实际值,如果这个函数处于非严格模式下,则指定为null或undefined时会自动替换为指向全局对象,原始值(类似字符串,数字,布尔值)会自动替换为原始值被包装的对象(例如布尔值则会指向Boolean的封装对象)

,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 nullundefined,则表示不需要传入任何参数。从ECMAScript 5 开始可以使用类数组对象。

argsArray:可选参数。一个数组或者类似数组的对象,其中数组元素将作为单独的参数传给func函数。如果该参数的值为null或undefined,则表示不需要传入任何参数。从ECMAScript5开始可以数组对象。

返回值

调用有指定有指定this值和参数的函数的结果。

实例1

描述:目的使用apply将数组arryA添加到另一个数组ArryB

var arryA = [1,2,3];
var arryB = ['a','b','c'];
arryB.push.apply(arryB,arryA);
console.log(arryB); //["a", "b", "c", 1, 2, 3]

实例2

描述:es5中this指向最后正在调用这个函数的对象

var objectA = {
  name:"a",
  test:function(){
    console.log(this.name)//"a"
  }
}
objectA.test();//最后调用时对象是 objectA

var objectA = {
  name:"a",
  test:function(){
    setTimeout(function(){
     console.log(this.name)//undefined,匿名函数的对象指向全局对象window,window中没有定义name变量非严格模式下输出undefined,严格模式下会报错    },100)
   
  }
}
objectA.test();//最后调用时对象是window

描述:用apply改变this指向

var objectA = {
  name:"a",
  test:function(){
    setTimeout(function(){
      
     console.log(this.name)"a"
    }.apply(objectA),100)//用apply 方法改变匿名函数中this的指向
   
  }
}
objectA.test();//"a"

func.call(thisArg, arg1, arg2, ..)

参数

thisArg:在fun函数运行时指定的 this 值。需要注意的是,指定的 this 值并不一定是该函数执行时真正的 this 值,如果这个函数在非严格模式下运行,则指定为 nullundefinedthis 值会自动指向全局对象(浏览器中就是 window 对象),同时值为原始值(数字,字符串,布尔值)的 this 会指向该原始值的自动包装对象。

arg1, arg2, ..:指定的参数列表。

返回值

使用调用者提供的 this 值和参数调用该函数的返回值。若该方法没有返回值,则返回 undefined

使用调用者提供的this值和调用该函数的返回值。若该方法没有返回值,则返回undefined

实例1

描述:用call方法实现继承

function Product(name, price) {
  this.name = name;
  this.price = price;
}

function Food(name, price) {
  Product.call(this, name, price);
  this.category = 'food';
}

console.log(new Food('cheese', 5).name);
// expected output: "cheese"

(其实可以理解为,Product把自身原有的属性附加给Food对象,机Food继承Product)

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

参数

thisArg:调用绑定函数时作为this参数传递给目标函数的值。 如果使用new运算符构造绑定函数,则忽略该值。当使用bindsetTimeout中创建一个函数(作为回调提供)时,作为thisArg传递的任何原始值都将转换为object。如果bind函数的参数列表为空,执行作用域的this将被视为新函数的thisArg

arg1,arg2……:当新的函数被调用时,预先添加到绑定的函数参数列表中的参数

返回值

返回一个新的函数的拷贝,并拥有指定的this值和初始参数

function list() {
  return Array.prototype.slice.call(arguments);
}

function addArguments(arg1, arg2) {
    return arg1 + arg2
}

var list1 = list(1, 2, 3); // [1, 2, 3]

var result1 = addArguments(1, 2); // 3

// 创建一个函数,它拥有预设参数列表。
var leadingThirtysevenList = list.bind(null, 37);

// 创建一个函数,它拥有预设的第一个参数
var addThirtySeven = addArguments.bind(null, 37); 

var list2 = leadingThirtysevenList(); 
// [37]

var list3 = leadingThirtysevenList(1, 2, 3); 
// [37, 1, 2, 3]

var result2 = addThirtySeven(5); 
// 37 + 5 = 42 

var result3 = addThirtySeven(5, 10);
// 37 + 5 = 42 ,第二个参数被忽略

总结

相同点:

call,apply,bind都是函数的预设方法,都能把一个函数的相关属性绑定到指定的第一个参数,即改变this的指向,实现继承,this所传递的就是参数列表中的第一个参数,

不同点:

call与apply的参数有所差异,第一个参数都是this关键字所传递的对象指向,而apply方法的第二个参数时数组对象,即所调用方法对应的参数列表形成的数组,call的参数的第一个参数也是this关键字所传递的指向,后面的第二个参数起则是所调用参数相对应的实参列表;二者都返回所调用函数的返回值。bind方法则返回所调用函数的拷贝,即返回一个函数对象,需进行第二次调用才返回所调用函数的返回值,即func.bind(obj)()