1. 程式人生 > >Array.prototype.slice.call()方法的理解

Array.prototype.slice.call()方法的理解

在看別人程式碼時,發現有這麼個寫法:[].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);