Каква е целта на извикването на Array.prototype.slice срещу NodeList?

Търсих как да повторя NodeLists и попаднах на следния код.

var nodesArray = Array.prototype.slice.call(nodeList);
nodesArray.forEach(function(node) { 
    //...
})

Каква е целта на извикването на Array.prototype.slice срещу NodeList?


person Renaud is Not Bill Gates    schedule 20.02.2014    source източник
comment
Имам чувството, че понякога решението на споровете относно дублирането е MOAR dup-closing. Хората, които намират този въпрос, ще искат да знаят две неща: 1) каква е работата с този странен прототип..call() модел? (класическа странност на DOM API) и 2) защо трябва да го използвам с NodeList (вие не го правите). И двата въпроса са задавани и отговаряни преди (много) - така че нека просто да се свържем с тях, а?   -  person Shog9    schedule 23.07.2019
comment
@shog9, така че с други думи първоначалният ми глас за измама беше напълно добър?   -  person Jonas Wilms    schedule 28.07.2019
comment
@JonasWilms да, знам, изпратихме го тук :) Радвам се, че е подредено. Моля, не се колебайте да поставите персонализиран флаг на публикации, когато имате притеснения.   -  person    schedule 28.07.2019


Отговори (4)


Каква е целта на извикването на Array.prototype.slice срещу NodeList?

Методът Array#slice "връща плитък копиране на част от масив в нов обект на масив".

Методът Function#call "извиква функция с дадена тази стойност и аргументи, предоставени индивидуално".

Тъй като масивите са обекти, всички имена на свойства на обекти се съхраняват като низове и всички списъци с възли съхраняват своите елементи с последователно номерирани имена на свойства (отново съхранени като низове), списъците с възли могат да се използват като this стойност за методите на масива.

Създаването на плитко копие на NodeList като масив ви позволява да използвате други методи за масив в новосъздадения масив, без да използвате Function#call.

Много съвременни браузъри са внедрили NodeList#forEach, въпреки че методът е все още е препоръка за кандидат и не е включен в спецификацията на този етап. Препоръчвам да използвате този метод внимателно, а не в отворената мрежа, докато не достигне по-стабилно състояние.


Ето някои други примери за Array методи, които се извикват с NodeList като цел:

// Convert to an array, then iterate
const nodeArray = Array.prototype.slice.call(nodeList)
nodeArray.forEach(doSomething);
// Iterate NodeList directly without conversion
Array.prototype.forEach.call(nodeList, doSomething);
// Perform operation on each element in NodeList, output results to a new Array
Array.prototype.map.call(nodeList, function(item) { 
    return item; 
}).forEach(doSomething);
// Filter NodeList, output result to a new Array
Array.prototype.filter.call(nodeList, function(item) { 
    return /* condition */; 
}).forEach(doSomething);

Има много други начини, по които можете да итерирате NodeList, които не изискват използването на Array методи, ето още няколко примера:

Можете да използвате добър старомоден for цикъл, да започнете от нула и да циклите, докато стигнем до края на масива. Този метод съществува от векове и се използва редовно и днес. Този метод е донякъде по-малко четлив от другите методи, споменати тук, но всичко се свежда до това какво е по-лесно за вас да пишете.

for(let i = 0; i < nodeList.length; ++i)  doSomething(nodeList[i]);

Използването на обратен цикъл (където е възможно) може да спести намаляване на времето за изпълнение поради липса на условна оценка. Всъщност някои IDE ще преобразуват предишния цикъл в следната структура по подразбиране.

for(let i = nodeList.length; i--;)  doSomething(nodeList[i]);

Можете да използвате цикъл while, който очаква условен оператор като свой параметър. Ако NodeList.item(n) е извън границите на NodeList, той ще върне null, което ще прекрати цикъла.

let i = 0, node;
while((node = nodeList.item(i++))) doSomething(node);

Можете да направите същото с for цикъл в условното:

let node;
for(let i = 0; (node = nodeList.item(i)); i++) doSomething(node);

Можете да използвате for...in цикъл с Object.keys(). Обърнете внимание, че трябва да използвате Object.keys, когато използвате for...in цикъл, защото в противен случай той ще повтори неизброимите свойства, както и изброимите.

Методът Object.keys() връща масив от собствените изброими свойства на даден обект в същия ред като този, предоставен от for...in цикъл (разликата е, че for-in цикълът изброява свойствата във веригата на прототипа като добре).
От: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys

for(var i in Object.keys(nodeList))  doSomething(nodeList[i]);

Можете да използвате for...of цикъл (ECMAScript 2015+), като извлечете функцията Iterator от Array() и я приложите към NodeList. Това ще работи и за повечето други употреби на обект, стига свойствата да са изброими.

nodeList[Symbol.iterator] = [][Symbol.iterator];
for(node of nodeList) doSomething(node);

Ако приложите Array Iterator към прототипа на класа NodeList, когато се създаде нов екземпляр на NodeList, той винаги ще може да се повтаря. Въпреки това, не е препоръчително да се разширяват естествени прототипи.

NodeList.prototype[Symbol.iterator] = [][Symbol.iterator];
for(node of nodeList) doSomething(node);
person Community    schedule 21.05.2015

Можете да създадете XML или JSON структура с помощта на PHP и да извикате услугата от flash/flex приложение. Тук можете да намерите кода за генериране на XML: cristalab.com/tutoriales/
person Xotic750    schedule 20.02.2014

Всички тези отговори са остарели. Всъщност можете да използвате forEach в NodeList в съвременните браузъри!

Така че просто използвайте forEach!

person rugk    schedule 09.04.2018

Тъй като slice връща копие на всеки подобен на масив аргумент като нов обект на масив, което е точно това, от което се нуждаем. Можем също толкова лесно да използваме concat.

person Wayne    schedule 20.02.2014
comment
Сигурни ли сте, че concat ще работи, бих си помислил, че това е един метод на масив, който вероятно ще се провали в тази ситуация? Бих искал да видя как да. jsfiddle.net/Xotic750/k552C - person Xotic750; 21.02.2014
comment
Не можете да използвате concat само по себе си, ще трябва да първо да разделите масива, което ще ви даде същият ефект като самото използване на slice. - person ; 08.09.2015