1. 首先,我们都理解在js中改变this引用有三种方法,call(), apply(), bind();
2. bind方法是改变函数内this引用,简单不再描述;
3. 至于 call() 和 apply() 两个方法,区别在于,前者是不定长的入参,后者是一个数组;下边重点说apply方法使用;
原理:
我们知道js中存在一种类数组对象,比如 {0:1,length:1}
或者 DOM 对象,或者 arguments 对象;
数组只是一种特殊的对象,数组的特殊性体现在,它的键默认是按次序排列的整数(0,1,2...),所以数组不用为每个元素指定键名,而对象的每个成员都必须指定键名。
所以 JavaScript中的数组也可以看成是这样的对象
var array = [1, 2, 3];
var obj = {
0: 1,
1: 2,
2: 3,
length:3
}
注意了,这个length属性很重要,有了length就可以像数组一样遍历这个对象了。
再来实现一个简单的slice方法,
function slice(start, end) {
var array = [];
start = start ? start : 0;
end = end ? end : this.length;
for (var i = start, j = 0; i < end; i++, j++) {
array[j] = this[i];
}
return array;
}
举例:Array.prototype.slice.apply({0:1,length:1});
通过apply,将slice方法中的this指向该对象,遍历生成新的数组对象。
注意点:
1. 使用apply 时要注意:apply或call 只是切换了函数内部 this 的调用,但是执行的方法依然是原始对象上的方法, 即使你在
Array.prototype.slice.call(obj)的 obj 上 覆盖了slice 方法 ,依然会执行 Array 上的 slice 方法;
2. 由于apply方法(或者call方法)也可以绑定函数执行时所在的对象,但是会立即执行函数,因此不得不把绑定语句写在一个函数体内。建议使用函数改变this指向时使用 bind 方法。
3.
bind方法每运行一次,就返回一个新函数,这会产生一些问题。比如,监听事件的时候,不能写成下面这样。
element.addEventListener(‘click‘, o.m.bind(o));
上面代码表示,click事件绑定bind方法生成的一个匿名函数。这样会导致无法取消绑定,所以,下面的代码是无效的。
element.removeEventListener(‘click‘, o.m.bind(o));
正确的方法是写成下面这样:
var listener = o.m.bind(o);
element.addEventListener(‘click‘, listener);
// ...
element.removeEventListener(‘click‘, listener);