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:

callapply几乎没区别,唯一的区别是传参列表不同。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指向,不同是传参列表不同。

posted @ 2019-01-18 17:22  soso辉  阅读(1130)  评论(0编辑  收藏  举报