深入學習js之——類陣列物件與arguments #11

MagicalLouis發表於2019-05-07

深入學習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系列目錄

歡迎新增我的個人微信討論技術和個體成長。

深入學習js之——類陣列物件與arguments #11
歡迎關注我的個人微信公眾號——指尖的宇宙,更多優質思考乾貨

深入學習js之——類陣列物件與arguments #11

相關文章