контекст, щоб використовувати виклик і застосовувати в Javascript?


74

Хлопці, чи може хтось пояснити контекст використання callта applyметоди в Javascript?

Навіщо використовувати callі applyзамість того , щоб викликати функцію безпосередньо?


3
Це прочитане допомогло мені зрозуміти сенс під thisArgчас дзвінка, apply()і call()це, здається, є суттю вашого запитання. Вам потрібно зрозуміти примітив виклику функції в Javascript
Saba Ahang

Відповіді:


80

Ви використовуєте callабо applyколи ви хочете передати інше thisзначення функції. По суті, це означає, що ви хочете виконати функцію так, ніби це метод певного об'єкта. Єдина різниця між ними полягає в тому, що callочікуються параметри, розділені комами, тоді як applyочікуються параметри в масиві.

Приклад зі сторінки Mozillaapply , де конструктори прив’язані ланцюгами:

function Product(name, price) {
    this.name = name;
    this.price = price;

    if (price < 0)
        throw RangeError('Cannot create product "' + name + '" with a negative price');
    return this;
}

function Food(name, price) {
    Product.apply(this, arguments);
    this.category = 'food';
}
Food.prototype = new Product();

function Toy(name, price) {
    Product.apply(this, arguments);
    this.category = 'toy';
}
Toy.prototype = new Product();

var cheese = new Food('feta', 5);
var fun = new Toy('robot', 40);

Що Product.apply(this, arguments)робить наступне: ProductКонструктор застосовуються в якості опції в кожному з Foodі Toyконструкторів, і кожен з цих примірників об'єктів в даний час передаються в якості this. Таким чином, кожен з Foodі Toyзараз має this.nameі this.categoryвластивості.


6
просто питання про наданий фрагмент коду, чому прототип Toy's та Food замінюється об’єктом Product?
Девідс

Коментуючи лише для того, щоб зіткнутися із запитанням @davids: навіщо нам це робити Toy.prototype = new Product();? Я перевірив це, і видалення цих рядків, здається, не впливає на кінцевий результат.
adrianp

6
@davids & @adrianp: Це потрібно, щоб зробити їжу та іграшки успадкованими від Product. Подивіться на цей приклад: jsfiddle.net/Shawn/xNEYЯкщо я вилучив, Toy.prototype = new Product();але залишив Food.prototype = new Product();, то тепер їжа успадковує продукт, а Іграшка ні. Я також додав метод до прототипу Продукту і зателефонував йому з Food and Toy, щоб зробити відсутність успадкування більш очевидним (просто відкрийте консоль і запустіть код, Food може викликати метод, успадкований від Product, але Toy не може і видає помилку) .
Шон

Як би використовувався прототип при використанні з об’єктними літералами?
user244394

Я думаю, я просто не розумію мети робити це замість того, що здається набагато простішим, наприклад, такого .

22

Тільки якщо ви використовуєте callабо applyможете змінити thisконтекст усередині функції.

На відміну від інших мов - у JavaScript thisне посилається на поточний об'єкт, а на контекст виконання, і його може встановити абонент.

Якщо ви викликаєте функцію за допомогою newключового слова this, правильно буде посилатися на новий об'єкт (усередині функції конструктора).

Але у всіх інших випадках - thisбуде посилатися на глобальний об'єкт, якщо не встановлено явно через виклик


Це може посилатися на виклик obj, якщо використовується obj.whatever();синтаксис.
Абхішек Соні

Вираз "Але у всіх інших випадках - це буде стосуватися глобального об'єкта, якщо не встановлено явно через виклик", слід виправити таким чином: "Але у всіх інших випадках, якщо не встановлено явно через виклик, це буде стосуватися глобального об'єкта при Ecmascript 3 або Ecmascript 5 (або пізнішої версії) у несуворому режимі. Однак у Ecmascript 5 (або пізнішої версії) у суворому режимі це завжди не визначено, якщо це явно не встановлено, і JS Engine видасть виняток, коли ви отримаєте доступ до цього. " Посилання: stackoverflow.com/questions/9822561/…
Алан CS

10

Ви використовуєте, .call()коли хочете, щоб функція виконувалася з іншим thisзначенням. Він встановлює thisзначення, як вказано, встановлює аргументи, як вказано, а потім викликає функцію. Різниця між .call()функцією та просто її виконанням полягає у значенні thisпокажчика під час виконання функції. Коли ви виконуєте функцію нормально, javascript вирішує, яким thisбуде вказівник (зазвичай глобальний контекст, windowякщо функція не викликається як метод на об'єкті). Коли ви використовуєте .call(), ви точно вказуєте, на що ви хочете thisбути встановлені.

Ви використовуєте, .apply()коли аргументи, які ви хочете передати функції, знаходяться в масиві. .apply()також може призвести до виконання функції із певним thisзначенням. .apply()найчастіше використовується, коли у вас невизначена кількість аргументів, які надходять з іншого джерела. Часто використовується, щоб передавати аргументи з одного виклику функції іншому, використовуючи спеціальну локальну змінну, argumentsяка містить масив аргументів, переданих поточній функції.

Я вважаю корисними сторінки посилань на MDN для .call () та .apply () .


Дякую, ти дуже добре це пояснюєш. Нарешті зрозумійте використання першого аргументу.
Переповнення питання

4

Якщо у вас є досвід роботи з jQuery, ви будете знати, що більшість функцій використовують thisоб'єкт. Наприклад, collection.each(function() { ... }); усередині цієї функції, "this"посилається на об'єкт ітератора. Це одне з можливих застосувань.

Я особисто використовував .apply()для реалізації черги запитів - я штовхаю масив аргументів у чергу, і коли настає час її виконання, я беру елемент і передаю його як аргументи для функції обробника, використовуючи .apply(), таким чином, роблячи тоді очищувач коду, якщо потрібно передавати масив аргументів як перший аргумент. Це ще один приклад.

Загалом, просто майте на увазі, що такі способи виклику функції існують, і одного дня ви можете знайти їх зручними для реалізації вашої програми.


1

Якщо у вас є досвід роботи, Object Oriented Programmingтоді виклик та застосування матиме сенс, якщо ви порівняєте це з успадкуванням та перевизначите властивості або метод / функції батьківського класу з дочірнього класу. Що схоже на виклик у javascript наступним чином:

function foo () {
  this.helloworld = "hello from foo"
}
foo.prototype.print = function () {
  console.log(this.helloworld)
}

foo.prototype.main = function () {
  this.print()
}


function bar() {
  this.helloworld = 'hello from bar'
}
// declaring print function to override the previous print
bar.prototype.print = function () {
  console.log(this.helloworld)
}

var iamfoo = new foo()

iamfoo.main() // prints: hello from foo

iamfoo.main.call(new bar()) // override print and prints: hello from bar

0

Я не можу згадати жодної нормальної ситуації, коли встановлення thisArg на щось інше є метою використання apply.

Метою apply є передача масиву значень функції, яка бажає ці значення як аргументи.

Це було замінено оператором розповсюдження у звичайному повсякденному використанні.

напр

// Finding the largest number in an array
`Math.max.apply(null, arr)` becomes `Math.max(...arr)`

// Inserting the values of one array at the start of another
Array.prototype.unshift.apply(arr1, arr2); 
// which becomes 
arr1 = [...arr2, ...arr1]
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.