Большинство ответов здесь дают полезные советы, когда у вас есть одна операция async, но иногда это возникает, когда вам нужно выполнить асинхронную операцию для каждой записи в массиве или другом списке подобная структура. Искушение состоит в том, чтобы сделать это:
// WRONG
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log(results); // E.g., using them, returning them, etc.
Пример:
// WRONG
var theArray = [1, 2, 3];
var results = [];
theArray.forEach(function(entry) {
doSomethingAsync(entry, function(result) {
results.push(result);
});
});
console.log("Results:", results); // E.g., using them, returning them, etc.
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
Причина, 't работа заключается в том, что обратные вызовы из doSomethingAsync
еще не запущены к тому моменту, когда вы пытаетесь использовать результаты.
Итак, если у вас есть массив (или список какого-то типа) и хотите выполнять асинхронные операции для каждой записи, у вас есть два варианта: выполнять операции параллельно (перекрывающиеся) или последовательно (последовательно последовательно).
Вы могут запускать все из них и отслеживать количество обратных вызовов, которые вы ожидаете, а затем использовать результаты, когда вы получили много обратных вызовов:
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", results); // E.g., using the results
}
});
});
Пример:
var theArray = [1, 2, 3];
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
console.log("Results:", results); // E.g., using the results
}
});
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Мы могли бы покончить с expecting
и просто использовать results.length === theArray.length
, но это оставляет нам открытым возможность того, что theArray
изменяется, пока вызовы выдающиеся ...)
Обратите внимание, как мы используем index
из forEach
, чтобы сохранить результат в results
в том же положении, что и запись это относится, даже если результаты a (поскольку асинхронные вызовы не обязательно завершаются в том порядке, в котором они были запущены).
Но что, если вам нужно вернуть те результаты от функции? Как указывали другие ответы, вы не можете; вы должны принять вашу функцию и вызвать обратный вызов (или вернуть Promise ). Вот вариант обратного вызова:
function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray, callback) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
callback(results);
}
});
});
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
Или вот версия, возвращающая Promise
вместо:
function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Конечно, если doSomethingAsync
передал нам ошибки, мы использовали бы reject
, чтобы отклонить обещание, когда мы получили сообщение об ошибке.)
Пример:
function doSomethingWith(theArray) {
return new Promise(function(resolve) {
var results = [];
var expecting = theArray.length;
theArray.forEach(function(entry, index) {
doSomethingAsync(entry, function(result) {
results[index] = result;
if (--expecting === 0) {
// Done!
resolve(results);
}
});
});
});
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Или, альтернативно, вы можете сделать обертку для doSomethingAsync
, который возвращает обещание, а затем сделайте следующее ...)
Если doSomethingAsync
дает вам Promise , вы можете использовать Promise.all
:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry, function(result) {
results.push(result);
});
}));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return Promise.all(theArray.map(function(entry) {
return doSomethingAsync(entry, function(result) {
results.push(result);
});
}));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
Обратите внимание, что Promise.all
решает свое обещание с помощью массива результатов всех обещаний, которые вы даете ему, когда все они разрешены, или отвергает его обещание, когда первый обещаний, которые вы ему даете, отклоняет.
Предположим, вы не хотите, чтобы операции были параллельны? Если вы хотите запускать их один за другим, вам нужно дождаться завершения каждой операции до начала следующего. Вот пример функции, которая делает это, и вызывает обратный вызов с результатом:
function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith(theArray, function(results) {
console.log("Results:", results);
});
(Поскольку мы выполняем работу последовательно, мы можем просто использовать results.push(result)
, так как мы знаю, что мы не получим результаты не в порядке. В приведенном выше примере мы могли бы использовать results[index] = result;
, но в некоторых из следующих примеров у нас нет индекса для использования.)
Пример:
function doSomethingWith(theArray, callback) {
var results = [];
doOne(0);
function doOne(index) {
if (index < theArray.length) {
doSomethingAsync(theArray[index], function(result) {
results.push(result);
doOne(index + 1);
});
} else {
// Done!
callback(results);
}
}
}
doSomethingWith([1, 2, 3], function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value, callback) {
console.log("Starting async operation for " + value);
setTimeout(function() {
console.log("Completing async operation for " + value);
callback(value * 2);
}, Math.floor(Math.random() * 200));
}
.as-console-wrapper {
max-height: 100% !important;
}
(Или снова создайте обертку для doSomethingAsync
, которая дает вам обещание и выполните ниже ...)
Если doSomethingAsync
дает вам обещание, если вы можете использовать синтаксис ES2017 + (возможно, с транспилером, например Babel ), вы можете использовать функцию async
с помощью for-of
и await
:
async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});
Пример:
async function doSomethingWith(theArray) {
const results = [];
for (const entry of theArray) {
results.push(await doSomethingAsync(entry));
}
return results;
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
Если вы не можете использовать синтаксис ES2017 + (пока), вы можете использовать вариацию на Обещают уменьшить шаблон (это сложнее, чем обычное сокращение Promise, потому что мы не передаем результат от одного к другому, а вместо gat
function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith(theArray).then(function(results) {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return theArray.reduce(function(p, entry) {
return p.then(function(results) {
return doSomethingAsync(entry).then(function(result) {
results.push(result);
return results;
});
});
}, Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
.. , который менее громоздк с функциями стрелок ES2015 + :
function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith(theArray).then(results => {
console.log("Results:", results);
});
Пример:
function doSomethingWith(theArray) {
return theArray.reduce((p, entry) => p.then(results => doSomethingAsync(entry).then(result => {
results.push(result);
return results;
})), Promise.resolve([]));
}
doSomethingWith([1, 2, 3]).then(function(results) {
console.log("Results:", results);
});
function doSomethingAsync(value) {
console.log("Starting async operation for " + value);
return new Promise(function(resolve) {
setTimeout(function() {
console.log("Completing async operation for " + value);
resolve(value * 2);
}, Math.floor(Math.random() * 200));
});
}
.as-console-wrapper {
max-height: 100% !important;
}
В дополнение к большим ответам до сих пор я хотел бы представить совершенно другую причину, по которой функции стрелок в определенном смысле существенно лучше, чем «обычные» функции JavaScript. Для обсуждения, давайте временно предположим, что мы используем проверку типа TypeScript или «Flow» Facebook. Рассмотрим следующий игрушечный модуль, который является действительным кодом ECMAScript 6 плюс плюс аннотации типа потока: (я буду включать нетипный код, который в конечном итоге будет получен из Babel в конце этого ответа, поэтому он может быть запущен.)
export class C {
n : number;
f1: number => number;
f2: number => number;
constructor(){
this.n = 42;
this.f1 = (x:number) => x + this.n;
this.f2 = function (x:number) { return x + this.n;};
}
}
Теперь посмотрим, что произойдет, когда мы используем класс C из другого модуля, например:
let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1: number = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2: number = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!
Как вы можете видеть, ошибка проверки типа здесь: f2 должен был возвратить число, но он вернул строку!
Хуже того, кажется, что нет мыслимой проверки типа может обрабатывать обычные (не стрелочные) функции JavaScript, потому что «это» из f2 не встречается в списке аргументов f2, поэтому требуется type для «this» не может быть добавлен как аннотация к f2.
Эта проблема также затрагивает людей, которые не используют контролеры типов? Я так думаю, потому что даже когда у нас нет статических типов, мы думаем, что они там. («Первые параметры должны быть числом, второе - строкой» и т. Д.). Скрытое «это» действие, которое может или не может быть использовано в теле функции, делает нашу умственную бухгалтерию более сложной.
Вот текущая нетипизированная версия, которая будет вызываться Babel:
class C {
constructor() {
this.n = 42;
this.f1 = x => x + this.n;
this.f2 = function (x) { return x + this.n; };
}
}
let o = { f1: new C().f1, f2: new C().f2, n: "foo" };
let n1 = o.f1(1); // n1 = 43
console.log(n1 === 43); // true
let n2 = o.f2(1); // n2 = "1foo"
console.log(n2 === "1foo"); // true, not a string!
Функции стрелок - наиболее широко используемая функция ES6 до сих пор ...
blockquote>Использование: все функции ES5 должны быть заменены функциями стрелок ES6, за исключением следующих сценариев:
Функции стрелок НЕ должны использоваться:
- Когда мы хотим, чтобы функция hoisting как функции стрелок была анонимной.
- Когда мы хотим использовать
this
/arguments
в функции, поскольку функции стрелки не имеютthis
/arguments
, они зависят от их внешнего контекста.- Когда мы хотим использовать именованную функцию, поскольку функции стрелок анонимны.
- Когда мы хотим использовать функцию как
constructor
, поскольку функции стрелки не имеют своихthis
.- Когда мы хотим добавить функцию как свойство в объектный литерал и использовать в ней объект, поскольку мы не можем получить доступ к
this
(который должен быть самим объектом).Давайте рассмотрим некоторые из вариантов функций стрелок, которые лучше понять:
Вариант 1: Когда мы хотим передать более одного аргумента функции и вернуть некоторые
Версия ES5 :
var multiply = function (a,b) { return a*b; }; console.log(multiply(5,6)); //30
Версия ES6 :
var multiplyArrow = (a,b) => a*b; console.log(multiplyArrow(5,6)); //30
Примечание: ключевое слово
function
НЕ требуется.=>
требуется.{}
являются необязательными, когда мы не предоставляем{}
return
неявно добавляется JavaScript, и когда мы предоставляем{}
, нам нужно добавитьreturn
, если нам это нужно.Вариант 2: Если мы хотим передать ТОЛЬКО один аргумент функции и вернуть некоторое значение из него.
Версия ES5 :
var double = function(a) { return a*2; }; console.log(double(2)); //4
Версия ES6 :
var doubleArrow = a => a*2; console.log(doubleArrow(2)); //4
Примечание: при передаче только одного аргумента мы можем опустить скобки
()
.Вариант 3: когда мы НЕ хотим передавать какие-либо аргумент функции и НЕ хотите возвращать какое-либо значение.
Версия ES5 :
var sayHello = function() { console.log("Hello"); }; sayHello(); //Hello
Версия ES6 :
var sayHelloArrow = () => {console.log("sayHelloArrow");} sayHelloArrow(); //sayHelloArrow
Вариант 4: Если мы хотим явно вернуться из функций стрелок.
Версия ES6 :
var increment = x => { return x + 1; }; console.log(increment(1)); //2
Вариант 5: Когда мы хотим вернуть объект из функций стрелок.
Версия ES6 :
var returnObject = () => ({a:5}); console.log(returnObject());
Примечание: нам нужно обернуть объект в скобки
()
, в противном случае JavaScript не может различать блок и объект.Вариант 6: Arro w не имеют
arguments
(массив, такой как объект), они зависят от внешнего контекста дляarguments
.Версия ES6 :
function foo() { var abc = i => arguments[0]; console.log(abc(1)); }; foo(2); // 2
Примечание:
foo
- это функция ES5 с массивомarguments
, подобным объекту, и переданный ему аргумент2
, поэтому дляfoo
дляarguments[0]
установлено значениеarguments[0]
.
abc
- это функция стрелок ES6, так как у нее нет ееarguments
, поэтому она выводитarguments[0]
вfoo
, это внешний контекст.Вариант 7: Функции стрелки НЕ имеют
this
, они зависят от внешнего контекста дляthis
Версия ES5 :
var obj5 = { greet: "Hi, Welcome ", greetUser : function(user) { setTimeout(function(){ console.log(this.greet + ": " + user); // "this" here is undefined. }); } }; obj5.greetUser("Katty"); //undefined: Katty
Примечание. Обратный вызов, переданный setTimeout, является ES5 и имеет свой собственный
this
, который не определен в средеuse-strict
, поэтому мы получаем выход:undefined: Katty
Версия ES6 :
var obj6 = { greet: "Hi, Welcome ", greetUser : function(user) { setTimeout(() => console.log(this.greet + ": " + user)); // this here refers to outer context } }; obj6.greetUser("Katty"); //Hi, Welcome: Katty
Примечание. Обратный вызов, переданный в
setTimeout
, является функцией стрелок ES6, и у него нет своегоthis
, поэтому он берет его из внешнего контекста, который являетсяgreetUser
, который имеетthis
, который являетсяobj6
, следовательно мы получаем выход:Hi, Welcome: Katty
Разное: мы не можем использовать функцию
new
со стрелками. Функции стрелки не имеют свойстваprototype
. У нас нет привязкиthis
, когда функция стрелки вызывается черезapply
илиcall
.
Функции стрелок были созданы для упрощения функции scope
и решения ключевого слова this
, упростив ее. Они используют синтаксис =>
, который выглядит как стрелка.
Примечание: он не заменяет существующие функции. Если вы замените каждый синтаксис функций на функции со стрелками, он не будет работать во всех случаях.
Давайте посмотрим на существующий синтаксис ES5. Если ключевое слово this
находилось внутри метода объекта (функция который принадлежит объекту), к чему это относится?
var Actor = {
name: 'RajiniKanth',
getName: function() {
console.log(this.name);
}
};
Actor.getName();
Вышеприведенный фрагмент ссылается на object
и печатает имя "RajiniKanth"
. Давайте рассмотрим нижеприведенный фрагмент и посмотрим, что здесь будет здесь.
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
. А теперь, если ключевое слово this
находилось внутри method’s function
?
Здесь это будет означать window object
, чем inner function
, как его выпавшее из scope
. Поскольку this
всегда ссылается на владельца функции, в которой он находится, для этого случая - поскольку он теперь выходит из области видимости - объект window / global.
Когда он находится внутри object
's метод - владелец function
является объектом. Таким образом, это ключевое слово привязано к объекту. Однако, когда он находится внутри функции, как автономной, так и внутри другого метода, она всегда будет ссылаться на объект window/global
.
var fn = function(){
alert(this);
}
fn(); // [object Window]
Есть способы решить эту проблему в нашем ES5
сам, рассмотрим, что перед тем, как погрузиться в функции ES6 arrow, как решить проблему.
Как правило, вы должны создать переменную вне внутренней функции метода. Теперь метод ‘forEach’
получает доступ к this
и, следовательно, к свойствам object’s
и их значениям.
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
var _this = this;
this.movies.forEach(function(movie) {
alert(_this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
, используя bind
, чтобы прикрепить ключевое слово this
, которое ссылается на метод method’s inner function
.
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach(function(movie) {
alert(_this.name + " has acted in " + movie);
}).bind(this);
}
};
Actor.showMovies();
Теперь с помощью функции стрелки ES6
мы можем более эффективно решить проблему lexical scoping
.
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
showMovies: function() {
this.movies.forEach((movie) => {
alert(this.name + " has acted in " + movie);
});
}
};
Actor.showMovies();
Arrow functions
больше похожи на операторы функций, за исключением того, что они bind
это parent scope
. Если аргумент arrow function is in top scope
, this
будет ссылаться на window/global scope
, тогда как функция стрелки внутри регулярной функции будет иметь свой этот аргумент так же, как и внешнюю функцию.
С функциями arrow
this
привязан к закрытию scope
во время создания и не может быть изменен. Новый оператор, bind, call и apply не влияют на это.
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
// With a traditional function if we don't control
// the context then can we lose control of `this`.
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`
asyncFunction(o, function (param) {
// We made a mistake of thinking `this` is
// the instance of `o`.
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? false
В приведенном выше примере мы потеряли контроль над этим. Мы можем решить приведенный выше пример, используя переменную ссылку this
или используя bind
. С ES6 становится легче управлять this
в качестве привязки к lexical scoping
.
var asyncFunction = (param, callback) => {
window.setTimeout(() => {
callback(param);
}, 1);
};
var o = {
doSomething: function () {
// Here we pass `o` into the async function,
// expecting it back as `param`.
//
// Because this arrow function is created within
// the scope of `doSomething` it is bound to this
// lexical scope.
asyncFunction(o, (param) => {
console.log('param === this?', param === this);
});
}
};
o.doSomething(); // param === this? true
Внутри литерала объекта.
var Actor = {
name: 'RajiniKanth',
movies: ['Kabali', 'Sivaji', 'Baba'],
getName: () => {
alert(this.name);
}
};
Actor.getName();
Actor.getName
определяется функцией стрелки, но при вызове он оповещает о неопределенности, поскольку this.name
является undefined
, поскольку контекст остается в window
.
Это происходит потому, что функция стрелки связывает контекст лексически с внешним окружением window object
... i.e. Выполнение this.name
эквивалентно window.name
, которое не определено.
Прототип объекта
Это же правило применяется при определении методов на prototype object
. Вместо использования функции-стрелки для определения метода sayCatName, который приводит к некорректному context window
:
function Actor(name) {
this.name = name;
}
Actor.prototype.getName = () => {
console.log(this === window); // => true
return this.name;
};
var act = new Actor('RajiniKanth');
act.getName(); // => undefined
Конструкторы Invoke
this
в вызове построения - это вновь созданный объект , При выполнении нового Fn () контекст constructor Fn
является новым объектом: this instanceof Fn === true
.
this
настроен из охватывающего контекста, то есть внешней области, которая делает ее не назначенной вновь созданному объекту.
var Message = (text) => {
this.text = text;
};
// Throws "TypeError: Message is not a constructor"
var helloMessage = new Message('Hello World!');
Обратный вызов с динамическим контекстом
Функция Arrow связывает декларацию context
статически и не может сделать ее динамической. Присоединение прослушивателей событий к элементам DOM является общей задачей при программировании на стороне клиента. Событие запускает функцию обработчика с этим в качестве целевого элемента.
var button = document.getElementById('myButton');
button.addEventListener('click', () => {
console.log(this === window); // => true
this.innerHTML = 'Clicked button';
});
this
- это окно в функции стрелки, которая определена в глобальном контексте. Когда происходит событие клика, браузер пытается вызвать функцию обработчика с контекстом кнопки, но функция стрелки не изменяет свой предварительно определенный контекст. this.innerHTML
эквивалентен window.innerHTML
и не имеет смысла.
Вы должны применить выражение функции, которое позволяет изменить это в зависимости от целевого элемента:
var button = document.getElementById('myButton');
button.addEventListener('click', function() {
console.log(this === button); // => true
this.innerHTML = 'Clicked button';
});
Когда пользователь нажимает кнопку, это в функции обработчика является кнопкой. Таким образом, this.innerHTML = 'Clicked button'
корректно изменяет текст кнопки, чтобы отразить статус щелчка.
Ссылки: https://rainsoft.io/when-not-to-use-arrow-functions-in-javascript/
Простым способом,
var a =20; function a(){this.a=10; console.log(a);}
//20, since the context here is window.
Другой экземпляр:
var a = 20;
function ex(){
this.a = 10;
function inner(){
console.log(this.a); //can you guess the output of this line.
}
inner();
}
var test = new ex();
Ans: Консоль будет печатать 20.
Причина, функция выполняет свой собственный стек, в этом примере функция ex
выполняется с оператором new
, поэтому будет создан контекст, и когда inner
будет выполнен, JS создаст новый стек и выполнит inner
, но существует локальный контекст.
Итак, если мы хотим, чтобы функция inner
имела локальный контекст, который является ex
, нам нужно привязать контекст к внутренней функции .
Стрелки решают эту проблему, вместо того, чтобы принимать Global context
, они берут local context
, если они существуют. В given example,
он примет значение new ex()
как this
.
Итак, во всех случаях, когда привязка является явной, Arrows решает проблему по умолчанию.
Я предпочитаю использовать функции стрелок во все времена, когда не требуется доступ к локальному this
, потому что функция стрелки не связывает свои собственные, аргументы, супер или new.target .