解析Array.prototype.slice.call(argume

Jack2k發表於2021-09-09

在es5標準中,我們經常需要把arguments物件轉換成真正的陣列

圖片描述

1 // 你可以這樣寫2 var arr = Array.prototype.slice.call(arguments)3 4 // 你還可以這樣寫5 var arr = [].slice.call(arguments)6 7 // 你要是不怕麻煩,你還可以這樣寫8 var arr = [].__proto__.slice.call(arguments)

圖片描述

以上三種寫法是等價的。

1 // 當你瞭解原型鏈,你就知道2 Array.prototype === [].__proto__  // true3  4 // [].slice呼叫的是例項[]的原型物件中的slice方法5 [].slice === [].__proto__.slice  // true

Array.prototype.slice.call(arguments)原本呼叫slice的是Array.prototype,而call(arguments)使得呼叫slice方法的物件改成arguments,你可以想象成

Array.prototype.slice.call(arguments) ~ arguments.slice()

Array.prototype.slice.call(arguments, [begin[, end]]) ~ arguments.slice([begin [, end]])

我們可能會想arguments原型物件是Object.prototype,並沒有slice方法,slice方法從哪裡來?

這是因為call(arguments)不僅是改變了this的指向,還使得arguments物件繼承了Array.prototype中的slice方法。

下面是Array.prototype.slice()原始碼: 587行

圖片描述

function ArraySlice(start, end) {
  CHECK_OBJECT_COERCIBLE(this, "Array.prototype.slice");  var array = TO_OBJECT(this);  var len = TO_LENGTH(array.length);  var start_i = TO_INTEGER(start);  var end_i = len;  if (!IS_UNDEFINED(end)) end_i = TO_INTEGER(end);  if (start_i < 0) {
    start_i += len;    if (start_i < 0) start_i = 0;
  } else {    if (start_i > len) start_i = len;
  }  if (end_i < 0) {
    end_i += len;    if (end_i < 0) end_i = 0;
  } else {    if (end_i > len) end_i = len;
  }  var result = ArraySpeciesCreate(array, MaxSimple(end_i - start_i, 0));  if (end_i < start_i) return result;  if (UseSparseVariant(array, len, IS_ARRAY(array), end_i - start_i)) {    %NormalizeElements(array);    if (IS_ARRAY(result)) %NormalizeElements(result);
    SparseSlice(array, start_i, end_i - start_i, len, result);
  } else {
    SimpleSlice(array, start_i, end_i - start_i, len, result);
  }

  result.length = end_i - start_i;  return result;
}

圖片描述

arguments可以轉換為陣列物件也是因為

圖片描述

我們可以看到arguments物件成員屬性類似陣列,且有length屬性,那是不是這樣類似的物件都可以呼叫slice呢,我們試驗一下

圖片描述

1 var obj = {2     0: 'foo',3     1: 'bar',4     2: 'arg',5     length: 36 }7 console.log(Array.prototype.slice.call(obj))8 //  ["foo", "bar", "arg"]

圖片描述

這是可以的!

*PS:es6語法中新增了Array.from(),所以上述型別的物件可以Array.from(obj)就直接轉化成陣列!

 作者:

原文出處:https://www.cnblogs.com/threeEyes/p/10478762.html  


來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/36/viewspace-2821979/,如需轉載,請註明出處,否則將追究法律責任。