'js难点之call,apply和bind的区别'

call,apply和bind

三者都是为了改变当前作用域的this的指向。

区别

call和apply的区别

call(thisObj,arg1,arg2…)
apply(thisObj,[obj1,obj2…])
call方法中传入的参数是是一个个列举出来的,而apply方法中的参数二是一个数组

1
2
3
4
5
6
7
8
9
10
window.color='red';
var o={color:"blue"};
function sayColor(){
console.log(this.color);
};
sayColor(); //red(全局函数,this是window)
sayColor.call(this);//red(调用call方法,指定对象是this,这里的this是window,没什么意义)
sayColor.call(window);//red(调用call方法,指定对象是window,没什么意义)
sayColor.call(o); //blue (调用call方法,指定对象是o,所以this指代对象o,这里由原来的window指向了o)
sayColor.apply(o);//blue (调用call方法,指定对象是o,所以this指代对象o,这里由原来的window指向了o)

bind

ECMAScript5中的bind()方法和前二种方法相似,bind()这个方法会创建一个函数的实例,这个实例的this值会被绑定到传递给bind()函数的值.

1
2
3
4
5
6
function a(y){
return this.x+y;
};
var o={x:1};
var g=a.bind(o);
g(2);//3

从例子中可以看出函数a绑定到对象o上了,并且返回了新的函数g,调用g时,a函数会当作对象o的方法来调用
bind()这个方法是将函数绑定到某个对象上,并且返回一个新的函数,这个新函数中传入的参数都将传入被绑定的函数上。

一句话

bind: 不立即执行函数,一般用在异步调用和事件; call/apply: 立即执行函数。 call是一个一个传参,apply通过数组传参。

应用

1.数组之间的追加

1
2
3
4
var a = [1,2,3];
var b = [4,5,6];
a.push.apply(a, b)
console.log(a) //数组[ 1, 2, 3, 4, 5, 6 ]

//有个注意点就是数组太大的时候不适合,具体请查看关于JS数组追加数组采用push.apply的问题
2.获取数组中的最大值和最小值,利用他们扩充作用域拥有Math的min和max方法;
由于没有什么对象调用这个方法,所以第一个参数可以写作null或者本身;

1
2
3
var  numbers = [5, 458 , 120 , -215 ]; 
var maxInNumbers = Math.max.apply(Math, numbers), //458
maxInNumbers = Math.max.call(Math,5, 458 , 120 , -215); //458

3.验证是否是数组(前提是toString()方法没有被重写过)

1
2
3
4
5
6
7
function   isArray(obj){ 
return Object.prototype.toString.call(obj) === '[object Array]' ;
}
//同理 可以判断是否为对象
function isObj(obj){
return Object.prototype.toString.call(obj) === '[object Object]' ;
}

4.让类数组拥有数组的方法 这个比较重点
比如arguments对象,获取到的文档节点等,并没有数组的那些方法:

1
2
3
Array.prototype.slice.apply(argument); //理论上来说这个比较快,直接在原型上查找slice方法.但实际上比较慢   
或者
[].slice.apply(arguments); //理论上来说这个比较慢,因为要Array做一个实例化再查找slice方法。实际上比较快,因为现在的各种自动化工具会把上一种方法转换为这种,而第二种代码比较简洁,所以会比较快;