Я знаю, що він використовується для перетворення аргументів у реальний масив, але я не розумію, що відбувається під час використання Array.prototype.slice.call(arguments)
Я знаю, що він використовується для перетворення аргументів у реальний масив, але я не розумію, що відбувається під час використання Array.prototype.slice.call(arguments)
Відповіді:
Те, що відбувається під кришкою, - це те, що, коли .slice()
викликається нормально, this
це масив, і він просто перебирає цей масив і виконує свою роботу.
Як this
у .slice()
функції є масив? Тому що коли ви робите:
object.method();
... object
автоматично стає значенням this
в method()
. Так і з:
[1,2,3].slice()
... [1,2,3]
Масив встановлюється як значення this
в .slice()
.
Але що робити, якщо ви могли замінити щось іншим як this
цінність? Поки все, що ви замінюєте, має числову .length
властивість і купу властивостей, що є числовими індексами, воно повинно працювати. Цей тип об'єктів часто називають об'єктом, схожим на масив .
Методи .call()
та .apply()
методи дозволяють вам вручну встановити значення this
функції. Отже, якщо ми встановимо значення this
в об’єкт , схожий.slice()
на масив , .slice()
просто припустимо, що він працює з масивом, і зробить свою справу.
Візьмемо цей приклад простого предмета.
var my_object = {
'0': 'zero',
'1': 'one',
'2': 'two',
'3': 'three',
'4': 'four',
length: 5
};
Це, очевидно, не масив, але якщо ви можете встановити його як this
значення .slice()
, тоді він буде просто працювати, тому що він виглядає досить як масив, .slice()
щоб правильно працювати.
var sliced = Array.prototype.slice.call( my_object, 3 );
Приклад: http://jsfiddle.net/wSvkv/
Як ви бачите на консолі, результат ми очікуємо:
['three','four'];
Отже, це відбувається, коли ви встановлюєте arguments
об'єкт як this
значення .slice()
. Оскільки arguments
має .length
властивість і купу числових індексів, .slice()
просто йде про свою роботу так, ніби працює над реальним масивом.
Array.prototype.slice
опис методу.
for-in
твердження, яке не гарантує замовлення. Використовуваний алгоритм .slice()
визначає числовий порядок, починаючи з 0
кінця (не включаючи) .length
даного об'єкта (або масиву чи будь-якого іншого). Таким чином, замовлення гарантується послідовним у всіх реалізаціях.
var obj = {2:"two", 0:"zero", 1: "one"}
. Якщо ми використовуємо for-in
для перерахунку об'єкта, немає гарантії порядку. Але якщо ми використовуємо for
, ми можемо вручну стежити за дотриманням порядку: for (var i = 0; i < 3; i++) { console.log(obj[i]); }
. Тепер ми знаємо, що властивості об’єкта будуть досягнуті у порядку зростання, який ми визначили нашим for
циклом. Ось що і .slice()
робить. Байдуже, чи є у нього фактичний масив. Він просто починається з 0
та отримує доступ до властивостей у висхідному циклі.
arguments
Об'єкт не є на самому ділі екземпляр масиву, і не має якогось - або з методів масиву. Отже, arguments.slice(...)
не буде працювати, оскільки в об'єкта аргументів немає методу зрізу.
arguments
Цей масив має такий метод, і оскільки об’єкт дуже схожий на масив, вони сумісні. Це означає, що ми можемо використовувати методи масиву з об’єктом аргументів. А оскільки методи масиву були побудовані з урахуванням масивів, вони повертатимуть масиви, а не інші об’єкти аргументів.
То навіщо використовувати Array.prototype
? Це Array
об'єкт, з якого ми створюємо нові масиви з ( new Array()
), і ці нові масиви передаються методами та властивостями, як фрагмент. Ці методи зберігаються в [Class].prototype
об’єкті. Так, заради ефективності, замість того , щоб отримати доступ до методу зрізу шляхом (new Array()).slice.call()
або [].slice.call()
ми просто отримати його прямо від прототипу. Це так, що нам не доведеться ініціалізувати новий масив.
Але чому ми маємо це робити в першу чергу? Ну, як ви сказали, він перетворює об’єкт аргументів в екземпляр Array. Однак причина, по якій ми використовуємо фрагмент, є скоріше "злом", ніж будь-що. Метод зрізу візьме a, ви здогадалися, фрагмент масиву і поверне цей фрагмент як новий масив. Не передаючи йому жодних аргументів (окрім об'єкта аргументів як його контексту), змушує метод зрізу взяти повний фрагмент пройденого "масиву" (у цьому випадку об'єкта аргументів) і повернути його як новий масив.
Зазвичай дзвонять
var b = a.slice();
скопіює масив a
у b
. Однак зробити це ми не можемо
var a = arguments.slice();
тому що arguments
це не справжній масив і не використовується slice
як метод. Array.prototype.slice
є slice
функцією для масивів і call
виконує функцію, this
встановлену на arguments
.
prototype
? це не slice
рідний Array
метод?
Array
це конструкторська функція, і відповідний "клас" є Array.prototype
. Ви також можете використовувати[].slice
slice
- метод кожного Array
примірника, але не Array
конструкторська функція. Ви використовуєте prototype
для доступу до методів теоретичних примірників конструктора.
Спочатку слід прочитати, як функція виклику функціонує в JavaScript . Я підозрюю, що одного лише достатньо, щоб відповісти на ваше запитання. Але ось короткий виклад того, що відбувається:
Array.prototype.slice
витягує метод з російського прототипу . Але зателефонувати безпосередньо не вийде, оскільки це метод (а не функція), і тому потрібен контекст (викликуючий об'єкт, ), інакше він кинеться .slice
Array
this
Uncaught TypeError: Array.prototype.slice called on null or undefined
call()
Метод дозволяє визначити контекст методу, в основному робить ці два виклики еквівалентні:
someObject.slice(1, 2);
slice.call(someObject, 1, 2);
За винятком того, що перший вимагає, щоб slice
метод існував у someObject
ланцюзі прототипів 's (як це відбувається 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 (аргументи) - це старомодний спосіб перетворення аргументів у масив.
У ECMAScript 2015 ви можете використовувати Array.from або оператор розповсюдження:
let args = Array.from(arguments);
let args = [...arguments];
Це тому, що, як зазначає MDN
Об'єкт аргументів не є масивом. Він схожий на масив, але не має властивостей масиву, крім довжини. Наприклад, у нього немає методу pop. Однак він може бути перетворений в реальний масив:
Тут ми закликаємося slice
до рідного об’єкта, Array
а не до його реалізації та ось чому зайвого.prototype
var args = Array.prototype.slice.call(arguments);
Не забувайте, що основи такої поведінки низького рівня - це типовий кастинг, який повністю інтегрований у JS-двигун.
Фрагмент просто приймає об'єкт (завдяки наявній властивості argument.length) і повертає масив-об’єкт, який передавався, виконуючи всі операції з цього.
Ті ж логіки, які ви можете перевірити, якщо ви спробуєте обробити метод String із значенням INT:
String.prototype.bold.call(11); // returns "<b>11</b>"
І це пояснює твердження вище.
Він використовує slice
метод масиви мають і викликає його з його this
бути arguments
об'єктом. Це означає, що він називає це так, як ніби ви arguments.slice()
припускалиarguments
що у вас такий метод.
Створення фрагмента без будь-яких аргументів просто займе всі елементи - тому воно просто копіює елементи з arguments
масиву.
Припустимо, у вас є: function.apply(thisArg, argArray )
Метод застосування викликає функцію, передаючи об'єкт, який буде прив'язаний до цього, і необов'язковий масив аргументів.
Метод slice () вибирає частину масиву і повертає новий масив.
Тому при виклику Array.prototype.slice.apply(arguments, [0])
методу фрагмента масиву викликається (прив'язується) до аргументів.
Можливо, трохи пізно, але відповідь на весь цей безлад полягає в тому, що call () використовується в JS для успадкування. Якщо порівняти це з Python або PHP, наприклад, дзвінок використовується відповідно як super (). у цьому () або батько :: _ 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
коли .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"]
Я просто пишу це, щоб нагадати про себе ...
Array.prototype.slice.call(arguments);
== Array.prototype.slice(arguments[1], arguments[2], arguments[3], ...)
== [ arguments[1], arguments[2], arguments[3], ... ]
Або просто скористайтеся цією зручною функцією $ A, щоб перетворити більшість речей на масив.
function hasArrayNature(a) {
return !!a && (typeof a == "object" || typeof a == "function") && "length" in a && !("setInterval" in a) && (Object.prototype.toString.call(a) === "[object Array]" || "callee" in a || "item" in a);
}
function $A(b) {
if (!hasArrayNature(b)) return [ b ];
if (b.item) {
var a = b.length, c = new Array(a);
while (a--) c[a] = b[a];
return c;
}
return Array.prototype.slice.call(b);
}
Приклад використання ...
function test() {
$A( arguments ).forEach( function(arg) {
console.log("Argument: " + arg);
});
}