簡體   English   中英

`Array.prototype.slice.call` 是如何工作的?

[英]How does `Array.prototype.slice.call` work?

我知道它用於使arguments成為真正的Array ,但我不明白使用Array.prototype.slice.call(arguments);時會發生什么 .

幕后發生的事情是,當.slice()被正常調用時, this是一個數組,然后它只是迭代該數組,並完成它的工作。

this是如何在.slice() function 一個數組中的? 因為當你這樣做時:

object.method();

... objectmethod()中自動成為this的值。 所以:

[1,2,3].slice()

... [1,2,3]數組在.slice()中設置為this的值。


但是如果你可以用別的東西代替this值呢? 只要您替換的任何內容都具有數字.length屬性,以及一堆數字索引的屬性,它就應該可以工作。 這種類型的 object 通常稱為類數組 object

.call( .call().apply()方法允許您在 function 中手動設置this的值。 因此,如果我們在.slice() this值設置為類似數組的 object.slice()假設它正在使用數組,並且會做它的事情。

以這個普通的 object 為例。

var my_object = {
    '0': 'zero',
    '1': 'one',
    '2': 'two',
    '3': 'three',
    '4': 'four',
    length: 5
};

這顯然不是一個數組,但如果你可以將它設置為.slice()this值,那么它就可以工作,因為它看起來很像一個數組,可以讓.slice()正常工作。

var sliced = Array.prototype.slice.call( my_object, 3 );

示例: http://jsfiddle.net/wSvkv/

正如您在控制台中看到的,結果是我們所期望的:

['three','four'];

因此,當您將arguments object 設置為.slice()this值時,就會發生這種情況。 因為arguments有一個.length屬性和一堆數字索引, .slice()就像在處理一個真正的數組一樣工作。

arguments object 實際上不是 Array 的實例,並且沒有任何 Array 方法。 因此, arguments.slice(...)將不起作用,因為 arguments object 沒有切片方法。

Arrays確實有這個方法,而且因為arguments object很像一個數組,所以兩者是兼容的。 這意味着我們可以在 arguments object 中使用數組方法。 而且由於數組方法是在考慮 arrays 的情況下構建的,因此它們將返回 arrays 而不是其他參數對象。

那么為什么要使用Array.prototype呢? Array是 object,我們從( new Array() )創建新的 arrays ,這些新的 arrays 是傳遞的方法和屬性,如 slice。 這些方法存儲在[Class].prototype object 中。 因此,為了提高效率,我們直接從原型中獲取,而不是通過(new Array()).slice.call()[].slice.call()訪問 slice 方法。 這樣我們就不必初始化一個新數組。

但是為什么我們必須首先這樣做呢? 好吧,正如您所說,它將 arguments object 轉換為 Array 實例。 然而,我們使用 slice 的原因更多的是“hack”。 slice 方法將獲取一個數組的切片,並將該切片作為新數組返回。 Passing no arguments to it (besides the arguments object as its context) causes the slice method to take a complete chunk of the passed "array" (in this case, the arguments object) and return it as a new array.

通常,調用

var b = a.slice();

將數組a復制到b中。 然而,我們做不到

var a = arguments.slice();

因為arguments沒有slice作為方法(它不是真正的數組)。

Array.prototype.slice是 arrays 的slice function。 .call運行此slice function, this值設置為arguments

首先,您應該閱讀function 調用如何在 JavaScript 中工作 我懷疑僅此一項就足以回答您的問題。 但這里是正在發生的事情的摘要:

Array.prototype.sliceArray原型中提取slice方法 但是直接調用它是行不通的, 因為它是一個方法(不是一個函數) ,因此需要一個上下文(一個調用 object, this ),否則它會拋出Uncaught TypeError: Array.prototype.slice called on null or undefined

call()方法允許您指定方法的上下文,基本上使這兩個調用等效:

someObject.slice(1, 2);
slice.call(someObject, 1, 2);

除了前者要求slice方法存在於someObject的原型鏈中(就像Array一樣),而后者允許將上下文( someObject )手動傳遞給該方法。

此外,后者是以下簡稱:

var slice = Array.prototype.slice;
slice.call(someObject, 1, 2);

這與以下內容相同:

Array.prototype.slice.call(someObject, 1, 2);
// We can apply `slice` from  `Array.prototype`:
Array.prototype.slice.call([]); //-> []

// Since `slice` is available on an array's prototype chain,
'slice' in []; //-> true
[].slice === Array.prototype.slice; //-> true

// … we can just invoke it directly:
[].slice(); //-> []

// `arguments` has no `slice` method
'slice' in arguments; //-> false

// … but we can apply it the same way:
Array.prototype.slice.call(arguments); //-> […]

// In fact, though `slice` belongs to `Array.prototype`,
// it can operate on any array-like object:
Array.prototype.slice.call({0: 1, length: 1}); //-> [1]

Array.prototype.slice.call(arguments) 是將 arguments 轉換為數組的老式方法。

在 ECMAScript 2015 中,您可以使用 Array.from 或擴展運算符:

let args = Array.from(arguments);

let args = [...arguments];

這是因為,正如MDN 所指出

arguments object 不是數組。 它類似於數組,但除了長度之外沒有任何數組屬性。 例如,它沒有 pop 方法。 但是它可以轉換為一個真正的數組:

在這里,我們在本機 object Array上調用slice而不是在其實現上,這就是為什么額外的.prototype

var args = Array.prototype.slice.call(arguments);

不要忘記,這種行為的底層基礎是完全集成在 JS 引擎中的類型轉換。

Slice 只需要 object(感謝現有的 arguments.length 屬性)並在對其執行所有操作后返回數組對象。

如果您嘗試使用 INT 值處理字符串方法,則可以測試相同的邏輯:

String.prototype.bold.call(11);  // returns "<b>11</b>"

這解釋了上面的陳述。

Array.prototype.slice=function(start,end){
    let res=[];
    start=start||0;
    end=end||this.length
    for(let i=start;i<end;i++){
        res.push(this[i])
    }
    return res;
}

當你這樣做時:

Array.prototype.slice.call(arguments) 

arguments變成slicethis的值,然后slice返回一個數組

它使用 arrays 擁有的slice方法,並將this arguments object。 這意味着假設arguments有這樣的方法,它就好像你做了arguments.slice()一樣調用它。

創建沒有任何 arguments 的切片將簡單地獲取所有元素 - 因此它只是將元素從arguments復制到數組。

假設您有: function.apply(thisArg, argArray )

apply 方法調用 function,傳入將綁定到此的 object 和 arguments 的可選數組。

slice() 方法選擇數組的一部分,並返回新數組。

因此,當您調用Array.prototype.slice.apply(arguments, [0])時,會在 arguments 上調用(綁定)數組切片方法。

當.slice() 被正常調用時,這是一個數組,然后它只是迭代該數組,並完成它的工作。

 //ARGUMENTS
function func(){
  console.log(arguments);//[1, 2, 3, 4]

  //var arrArguments = arguments.slice();//Uncaught TypeError: undefined is not a function
  var arrArguments = [].slice.call(arguments);//cp array with explicity THIS  
  arrArguments.push('new');
  console.log(arrArguments)
}
func(1,2,3,4)//[1, 2, 3, 4, "new"]

也許有點晚了,但所有這些混亂的答案是 call() 在 JS 中用於 inheritance。 例如,如果我們將其與 Python 或 PHP 進行比較,則 call 分別用作 super()。 init () 或 parent::_construct()。

這是它的用法示例,它闡明了所有內容:

function Teacher(first, last, age, gender, interests, subject) {
  Person.call(this, first, last, age, gender, interests);

  this.subject = subject;
}

參考: https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Objects/Inheritance

/*
    arguments: get all args data include Length .
    slice : clone Array
    call: Convert Object which include Length to Array
    Array.prototype.slice.call(arguments): 
        1. Convert arguments to Array
        2. Clone Array arguments
*/
//normal
function abc1(a,b,c){
    console.log(a);
} 
//argument
function: function abc2(){
    console.log(Array.prototype.slice.call(arguments,0,1))
}

abc1('a','b','c');
//a
abc2('a','b','c');
//a

我知道它用於使 arguments 成為真正的數組,但我不明白使用Array.prototype.slice.call(arguments)時會發生什么

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM