在看别⼈代码时,发现有这么个写法:[].slice.call(arguments, 0),这到底是什么意思呢?
1、基础
1)slice() ⽅法可从已有的数组中返回选定的元素。
start:必需。规定从何处开始选取。如果是负数,那么它规定从数组尾部开始算起的位置。也就是说,-1 指最后⼀个元素,-2 指倒数第⼆个元素,以此类推。 end:可选。规定从何处结束选取。该参数是数组⽚断结束处的数组下标。如果没有指定该参数,那么切分的数组包含从 start 到数组结束的所有元素。如果这个参数是负数,那么它规定的是从数组尾部开始算起的元素。 返回⼀个新的数组,包含从 start 到 end (不包括该元素)的 arrayObject 中的元素。该⽅法并不会修改数组,⽽是返回⼀个⼦数组。
2)call()和apply()⽅法都是在特定的作⽤域中调⽤函数,实际上等于设置函数体内this对象的值。apply和call⽅法的第⼀个参数都是 特定的作⽤域第⼆个参数不同,apply第⼆个参数可以是Array的实例,也可以是arguments对象。call⽅法需要逐个列出需要传递的参数。
3)arguments对象指数与数组类似(它并不是Array的实例),但是可以使⽤⽅括号语法访问每⼀个元素,使⽤length来确定传递进来多少个参数。
4)Array.prototype.slice.call()可以理解为:改变数组的slice⽅法的作⽤域,在特定作⽤域中去调⽤slice⽅法,call()⽅法的第⼆个参数表⽰传递给slice的参数即截取数组的起始位置。
2、原理
Array.prototype.slice.call(arguments)能将具有length属性的对象(key值为数字)转成数组。[]是Array的⽰例,所以可以直接使⽤[].slice()⽅法。
var obj = {0:'hello',1:'world',length:2};
console.log(Array.prototype.slice.call(obj,0));//["hello", "world"]
没有length属性的对象
var obj = {0:'hello',1:'world'};//没有length属性
console.log(Array.prototype.slice.call(obj,0));//[]
注意点:
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);