call,apply,bind的区别
面试经常被问到call,apply,bind的区别
call:
上代码!!!
1 function Person(name,age){ 2 this.name = name; 3 this.age = age; 4 } 5 var person = new Person('Tom',100) 6 var obj = {} 7 Person.call(obj)
上面代码的意思是什么?Person.call(obj)就是让person里面所有的this,变成obj。
Person构造函数里面有this,如果不new的话,就是指向window。现在把call里面放一个obj进去,Person执行的时候就不再是默认值了。也可以说是打针,把obj的this打到Person里面去,让Person的this指向obj。
也就是说Person在执行的时候是下面这样:
1 function Person(name,age){
// this == obj 2 obj.name = name; 3 obj.age = age; 4 }
在Person里面有一条变化,this == obj。如果要传参数的话,可以这样:
Person.call(obj,'jack',80),执行后显示下图:
这是为什么呢?
Person执行的时候按照正常的方法执行,.call的方法第一个参数会改变this的指向,第二位以后的参数会当作实参传到形参里面去,call的根本作用就是改变this指向。也就是说,我借用你的方法来改变this指向,Person这个方法本来是一个构造函数,构造函数里面有this,只要有this就能改变this指向,我通过call的方法借用你的方法来实现共用。利用Person的方法来对obj重写,所以obj又有name又有age。
Function.call,任何一个方法都可以.call,例如:
function test(){
}
执行test(),和执行test.call()是一样的。
再举个粟子:
建一个造车工厂,有的人造轮子,有的人造座位...
1 // 造轮子 2 function Wheel(wheelSize,style){ 3 this.style = style; 4 this.wheelSize = wheelSize; 5 } 6 // 造座位 7 function Sit(c,sitColor){ 8 this.c = c; 9 this.sitColor = sitColor; 10 } 11 12 function Model(height, width, len){ 13 this.height = height; 14 this.width = width; 15 this.len = len; 16 } 17 // 内部工厂,大车间 18 function Car(wheelSize,style,c,sitColor,height, width, len){ 19 Wheel.call(this,wheelSize,style); 20 Sit.call(this,c,sitColor); 21 Model.call(this,height, width, len) 22 } 23 var car = new Car(100,'五颜六色','真皮','red',1800,1900,4900)
跟父母教育孩子一样,找个钢琴老师,唰地把钢琴知识教过去,然后找个小学老师,刷地又把小学知识教过去这样。
apply:
call和apply几乎没区别,唯一的区别是传参列表不同。call可以一位一位地传实参进去,apply只能传一个实参,并且这个实参只能是数组形式。
call:需要把实参按照形参的个数传进去。
apply:需要传一个arguments。
小技巧:
利用Math.max.apply获取数组最大/最小值
1 // 如果一个数组我们已知里面全都是数字,想要知道最大的那个数,由于Array没有max方法,Math对象上有 2 // 我们可以根据apply传递参数的特性将这个数组当成参数传入 3 // 最终Math.max函数调用的时候会将apply的数组里面的参数一个一个传入,恰好符合Math.max的参数传递方式 4 // 这样变相的实现了数组的max方法。min方法也同理 5 // 有两种情况需要注意,传null或undefined时,将是JS执行环境的全局变量。浏览器中是window,其它环境(如node)则是global。 6 const arr = [1,2,3,4,5,6] 7 const max = Math.max.apply(null, arr) 8 console.log(max) // 6
1 fun.call(null); // window or global 2 fun.call(undefined); // window or global
严格模式下情况又有所不同,ES3比较宽容尽量去揣测代码意图。ES5严格模式(ie6/7/8/9除外)则不再揣测,给call/apply传入的任何参数不再转换。
'use strict' function fun() { alert(this); } fun.call(null) // null fun.call(undefined) // undefined
将类数组转为数组:
1 var arr = Array.prototype.slice.call(arrayLike)
数组追加:
1 var arr1 = [1,2,3]; 2 var arr2 = [4,5,6]; 3 var total = [].push.apply(arr1, arr2);//6 4 // arr1 [1, 2, 3, 4, 5, 6] 5 // arr2 [4,5,6]
判断变量类型:
1 // toString方法返回反映这个对象的字符串(返回对象的具体类型) 2 // console.log(Object.prototype.toString.call(null));//[object Null] 3 // console.log(Object.prototype.toString.call({name: "jerry"}));//[object Object] 4 // console.log(Object.prototype.toString.call(function(){}));//[object Function] 5 6 7 function isArray(obj){ 8 return Object.prototype.toString.call(obj) == '[object Array]'; 9 } 10 isArray([]) // true 11 isArray('dot') // false
bind:
第一个参数是this的指向,从第二个参数开始是接收的参数列表。区别在于bind方法返回值是函数以及bind接收的参数列表的使用。
总结:
call和apply相同的地方是改变this指向,不同是传参列表不同。