深入學習js系列是自己階段性成長的見證,希望通過文章的形式更加嚴謹、客觀地梳理js的相關知識,也希望能夠幫助更多的前端開發的朋友解決問題,期待我們的共同進步。
如果覺得本系列不錯,歡迎點贊、評論、轉發,您的支援就是我堅持的最大動力。
類陣列物件
所謂的類陣列物件:
擁有一個 length 屬性和若干索引屬性的物件
舉個例子:
var array = ['name','age','sex'];
var arrayLike ={
0: 'name',
1:'age',
2: 'sex',
length: 3
}
複製程式碼
即便如此,為什麼叫做類陣列物件呢?
那讓我們從讀寫、獲取長度、遍歷這三個方面看看這兩個物件:
讀寫
console.log(array.length); // 3
console.log(arrayLike.ength); // 3
複製程式碼
遍歷
for(var i = 0,len = array.length;i<len;i++){
……
}
for(var i = 0,len = arrayLike.length;i<len;i++){
……
}
複製程式碼
是不是很像 那類陣列物件可以使用陣列的方法嗎?比如:
arrayLike.push("4");
複製程式碼
然而 上述程式碼會報錯: arrayLike.push is not a function
所以終歸還是類陣列,哈哈哈
呼叫陣列的方法
如果類陣列就是任性的想要使用陣列的方法怎麼辦呢?
既然無法直接的呼叫,我們可以使用 Function.call 間接呼叫:
var arrayLike ={ 0: 'name',1:'age',2: 'sex',length: 3 }
Array.prototype.join.call(arrayLike,'&'); // name&age&sex
Array.prototype.slice.call(arrayLike, 0); // ["name", "age", "sex"]
// slice可以做到類陣列轉陣列
Array.prototype.map.call(arrayLike, function(item){
return item.toUpperCase();
});
// ["NAME", "AGE", "SEX"]
複製程式碼
類陣列轉陣列
在上面的例子中已經提到了一種類陣列轉陣列的方法,再補充三個:
var arrayLike ={ 0: 'name',1:'age',2: 'sex',length: 3 }
// 1. slice
Array.prototype.slice.call(arrayLike); // ["name", "age", "sex"]
// 2. splice
Array.prototype.splice.call(arrayLike, 0); // ["name", "age", "sex"]
// 3. ES6 Array.from
Array.from(arrayLike); // ["name", "age", "sex"]
// 4. apply
Array.prototype.concat.apply([], arrayLike)
複製程式碼
那麼為什麼要講到類陣列物件呢?以及類陣列物件有什麼作用嗎?
要說到類陣列物件,Arguments 物件就是一個類陣列物件。在客戶端 JavaScript 這種,一些 DOM 方法
document.getElementsByTagName();
複製程式碼
等也返回類陣列物件。
Arguments 物件
接下來重點講講 Arguments 物件
Arguments 物件只定義在函式體中,包括了函式的引數和其他屬性,在函式體中,arguments 指代該函式的 Arguments 物件
舉一個例子:
function foo(name, age, sex) {
console.log(arguments);
}
foo("name", "age", "sex");
複製程式碼
列印結果如下:
我們可以看到除了類陣列的索引屬性和 length 屬性之外,還有一個 callee 屬性,接下來我們一個一個介紹。
length 屬性
Arguments 物件的 length 屬性,表示實參的長度,舉個例子:
function foo(b, c, d) {
console.log("實參的長度為:" + arguments.length);
}
console.log("形參的長度為:" + foo.length);
foo(1);
// 形參長度為 3
// 實參的長度為:1
複製程式碼
callee 屬性
Arguments 物件的 callee 屬性,通過它可以呼叫函式自身。 講一個閉包經典米娜會題中使用 callee 的解決方法:
var data = [];
for (var i = 0; i < 3; i++) {
(data[i] = function() {
console.log(arguments.callee.i);
}).i = i;
}
data[0]();
data[1]();
data[2]();
// 0
// 1
// 2
複製程式碼
接下來講講 arguments 物件的幾個注意要點:
arguments 和對應引數的繫結
function foo(name, age, sex, hobbit) {
console.log(name, arguments[0]); // name name
// 改變形參
name = "new name";
console.log(name, arguments[0]); // new name new name
// 改變arguments
arguments[1] = "new age";
console.log(age, arguments[1]); // new age new age
// 測試未傳入的是否會繫結
console.log(sex); // undefined
sex = "new sex";
console.log(sex, arguments[2]); // new sex undefined
arguments[3] = "new hobbit";
console.log(hobbit, arguments[3]); // undefined new hobbit
}
foo("name", "age");
複製程式碼
傳入的引數,實參和 arguments 的值會共享,當沒有傳入時,實參與 arguments 值不會共享
除此之外,以上是在非嚴格模式下,如果是在嚴格模式下,實參和 arguments 是不會共享的。
傳遞引數
將引數從一個函式傳遞到另外一個函式
// 使用apply 將foo 的引數傳遞給bar
function foo() {
bar.apply(this, arguments);
}
function bar(a, b, c) {
console.log(a, b, c);
}
foo(1, 2, 3);
複製程式碼
強大的 ES6
使用 ES6 的 ... 運算子,我們可以輕鬆的轉成陣列
function func(...arguments) {
console.log(arguments); // [1,2,3]
}
func(1, 2, 3);
複製程式碼
應用
arguments的應用其實很多,如果要總結這些場景的話,暫時能想到的包括:
引數不定長 函式柯里化 遞迴呼叫 函式過載 ...
深入學習JavaScript系列目錄
- #1 【深入學習js之——原型和原型鏈】
- #2 【深入學習js之——詞法作用域和動態作用域】
- #3 【深入學習js之——執行山下文棧】
- #4 【深入學習js之——變數物件】
- #5 【深入學習js之——作用域鏈】
- #6 【深入學習js之——實際開發場景中的this指向】
- #7 【深入學習js之——執行上下文】
- #8 【深入學習js之——閉包】
- #9 【深入學習js之——引數按值傳遞】
- #10 【深入學習js之——call和apply】
- #11 【深入學習js之——類陣列物件與arguments】
- #12 【深入學習js之——建立物件的各種方式以及優缺點】
歡迎新增我的個人微信討論技術和個體成長。
歡迎關注我的個人微信公眾號——指尖的宇宙,更多優質思考乾貨