Тема о многих аспектах определения значения this — традиционных функциях и функциях-конструкторах, а также наследовании.
Пример 1
function foo() { this.total = 0; setTimeout(function baz() { this.total++; console.log(`in the scope of baz, ${this.total} is NaN.`); }); setTimeout(() => console.log(`foo total remains ${this.total}`)); this.total.subtotal = 0; } let instance = new foo();
this.total равен NaN
при вызове в рамках функции baz(). this.total увеличивается внутри функции setTimeout, а this получается из глобального объекта окна.
setTimeout(function, milliseconds) { fn() // this is window.fn(), implicitly }
Традиционные функции заботятся о том, где они вызываются, как видно при добавлении к функции-конструктору путем объявления методов-прототипов даже за пределами ее области действия.
foo.prototype.increment = function () { this.total.subtotal++; } foo.prototype.increment = () => { this.total.subtotal++; }
Контекстно-зависимая стрелочная функция получает и вызывает неопределенное свойство .total элемента this из глобальной области, в которой оно объявлено. Как мы знаем, атрибут [object Window] this.total не определен! Вы получаете TypeError: Cannot read properties of undefined (чтение «value»).
Пример 2
function foo(){ this.total = 0; setTimeout(() => { this.total++; console.log(`in the scope of foo, this.total is ${this.total}`); }); } new foo();
При ссылке на this традиционные функции заботятся о том, где они вызываются, тогда как стрелочные функции заботятся о том, где они объявлены.¹ Вот почему мы используем обработчики событий в виде стрелочных функций; нет необходимости в этой привязке. Для традиционных функций, которые можно использовать в качестве функций-конструкторов, мы можем использовать оператор new. Это скрытое свойство [[Construct]], которое связывает традиционные функции с оператором new². Важно отличать =› от конструкторов.
const foo = () => {}; console.log(`foo prototype is ${foo.prototype}`); new foo();
TypeError: foo is not a constructor
.
Если вам интересно, как получить такое причудливое форматирование в Visual Studio Code, Shift + ⌥ + F автоматически форматирует.
Дополнительную информацию по этой теме см. в разделе freeCodeCamp, когда и почему следует использовать стрелочные функции ES6!³
[1]: Мой друг Джастин Кристенсен говорит, что мы должны использовать стрелочные функции, которые ведут себя так, как ожидается.
[2]: Джон Ау-Юнг. Лучшее из современного JavaScript — стрелочные функции и новые возможности ООП
https://javascript.plainenglish.io/best-of-modern-javascript-arrow-functions-and-new-oop -особенности-6ce77ce9db8e
[3]: freeCodeCamp. Когда (и почему) следует использовать стрелочные функции ES6, а когда не следует
https://www.freecodecamp.org/news/when-and-why-you- следует-использовать-es6-функции-стрелок-и-когда-не следует-3d851d7f0b26/