[].slice.call的理解


首先要說明[].slice.call()Array.prototype.slice.call() 有什么區別?

[].slice === Array.prototype.slice
true

[]為創建數組,當[].slice的時候,自然會去找原型鏈

[].__proto__.slice === Array.prototype.slice
true

Array.prototype.slice是定義的方法,可以被重寫

[].silce是使用定義的方法

  1. 自身的屬性不同(因為原型與[]的區別)
Object.getOwnPropertyNames(Array.prototype)
(37) ["length", "constructor", "concat", "pop", "push", "shift", "unshift", "slice", "splice", "includes", "indexOf", "keys", "entries", "forEach", "filter", "map", "every", "some", "reduce", "reduceRight", "toString", "toLocaleString", "join", "reverse", "sort", "lastIndexOf", "copyWithin", "find", "findIndex", "fill", "remove", "removeFirstIf", "removeIf", "repeat", "last", "lastDef", "clone"]

Object.getOwnPropertyNames([])
["length"]

所以在本質上[]和Array.prototype沒有本質區別,但是調用上是有區別的,但是根據專業檢測,[]要更快一點

在MDN上 slice的解釋是

slice()方法返回一個從開始到結束(不包括結束)選擇的數組的一部分進行淺拷貝到一個新的數組對象,並且原對象不會被修改

var animals = ['ant', 'bison', 'camel', 'duck', 'elephant'];

console.log(animals.slice(2));
// expected output: Array ["camel", "duck", "elephant"]

console.log(animals.slice(2, 4));
// expected output: Array ["camel", "duck"]

console.log(animals.slice(1, 5));
// expected output: Array ["bison", "camel", "duck", "elephant"]

參數有兩個slice(begin,end)

begin :

  • 如果沒有參數那就從0開始
  • 有就從索引處來時(第一位為0)
  • 如果該參數為負數,則表示從原數組中的倒數第幾個元素開始提取,slice(-2)表示提取原數組中的倒數第二個元素到最后一個元素 (包含最后一個元素)

end :

  • 如果沒有參數,默認取到數組末尾
  • 如果大於數組長度,取到數組末尾
  • slice(1,4) 提取原數組中的第二個元素開始直到第四個元素的所有元素 (索引為 1, 2, 3的元素)
  • 如果該參數為負數, 則它表示在原數組中的倒數第幾個元素結束抽取
var a = [1,2,3,4,5,6,7,8];
a.slice(3,-2)
(3) [4, 5, 6]

返回值

一個含有提取元素的新數組

slice 不修改原數組,只會返回一個淺復制了原數組中的元素的一個新數組。

  • 如果該元素是個對象引用 (不是實際的對象),slice 會拷貝這個對象引用到新的數組里。兩個對象引用都引用了同一個對象。如果被引用的對象發生改變,則新的和原來的數組中的這個元素也會發生改變。

  • 對於字符串、數字及布爾值來說(不是 StringNumber 或者 Boolean 對象),slice 會拷貝這些值到新的數組里。在別的數組里修改這些字符串或數字或是布爾值,將不會影響另一個數組。

如果向兩個數組任一中添加了新元素,則另一個不會受到影響。

以上大致是MDN上面對slice的專業解釋

slice 這個方法在不接受任何參數的時候會返回 this 本身

arguments 是屬於函數內部的變量,其值是函數參數列表,一個類數組對象,是具有長度屬性的,卻並不是數組,不具備slice()這個方法,那就意味着 arguments.slice() 行不通

這里可以改變this的call出現了,假如我用call將arguments把this給slice會發生什么?

slice會得到具有長度屬性的對象,就實現了對象轉數組的

function list() {
  return Array.prototype.slice.call(arguments);
}
console.log(list(1, 2, 3));

一定有人會問,為什么將arguments的call給slice就可以變成數組?內部到底發生了什么

我們可以實現一個自己的slice(),就明白了

Myslice()

Array.prototype.Myslice = function (begin,end){

  var start = begin || 0;   //判斷begin時候存在 不存在給0 這里判斷可以加強
  var len = this;    //獲取this.length  這里得到了call進來的對象
  
  start = (start >= 0) ? start : Math.max(0, len + start); //判斷參數是不是是不是大於1,負數情況下的begin取值
  end = (typeof end == 'number') ? Math.min(end, len) : len;  //判斷end是不是大於this.length的長度
  if(end<0){
    end = end + len  //判斷負值的情況
  }
  var result = new Array();
  
  for (let i = 0; i < end.length; i++) {
    result.push(this[i])
  }
  return result;
}
function list() {
  return Array.prototype.Myslice.call(arguments);
}
console.log(list(1, 2, 3));

相信看到這里就明白為什么Array.prototype.slice.call 是如何將對象變成數組的~~~

最后貼上JavaScript sclie的源碼

Array.prototype.slice = function(begin, end) {
  end = typeof end !== 'undefined' ? end : this.length

  if (Object.prototype.toString.call(this) === '[object Array]') {
    return _slice.call(this, begin, end)
  }

  var i,
    cloned = [],
    size,
    len = this.length

  var start = begin || 0
  start = start >= 0 ? start : Math.max(0, len + start)

  var upTo = typeof end == 'number' ? Math.min(end, len) : len
  if (end < 0) {
    upTo = len + end
  }

  size = upTo - start

  if (size > 0) {
    cloned = new Array(size)
    if (this.charAt) {
      for (i = 0; i < size; i++) {
        cloned[i] = this.charAt(start + i)
      }
    } else {
      for (i = 0; i < size; i++) {
        cloned[i] = this[start + i]
      }
    }
  }

  return cloned
}

function list() {
  return Array.prototype.slice.call(arguments)
}
console.log(list(1, 2, 3))

文章為個人總結,若有錯誤,請指出


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM