Когда ES6 теперь широко поддерживается, лучший ответ на этот вопрос изменился. ES6 предоставляет ключевые слова let
и const
для этого точного обстоятельства. Вместо того, чтобы возиться с закрытием, мы можем просто использовать let
для установки переменной области цикла таким образом:
var funcs = [];
for (let i = 0; i < 3; i++) {
funcs[i] = function() {
console.log("My value: " + i);
};
}
val
затем укажет на объект, специфичный для этого конкретного поворота цикл, и вернет правильное значение без дополнительной записи закрытия. Это явно значительно упрощает эту проблему.
const
аналогично let
с дополнительным ограничением на то, что имя переменной не может отскочить к новой ссылке после первоначального присваивания.
Поддержка браузера теперь предназначена для тех, кто ориентирован на последние версии браузеров. const
/ let
в настоящее время поддерживается в последних версиях Firefox, Safari, Edge и Chrome. Он также поддерживается в узле, и вы можете использовать его в любом месте, используя инструменты построения, такие как Babel. Вы можете увидеть рабочий пример здесь: http://jsfiddle.net/ben336/rbU4t/2/
Документы здесь:
Остерегайтесь, однако, что поддержка IE9-IE11 и Edge до Edge 14 let
, но получим неверное (они не создают новый i
каждый раз, поэтому все вышеперечисленные функции будут записывать 3, как если бы мы использовали var
). Edge 14, наконец, получает это право.
Я думаю, что это также может иметь какое-то отношение к неожиданному поведению, которое может возникнуть из-за неявного предоставления лексического имени тому, что вы можете ожидать анонимной функцией.
Скажем, например, кто-то понял функцию стрелки:
(x) => x+2;
Чтобы иметь регулярную функцию, эквивалентную:
function(x) {
return x+2;
}
Было бы довольно легко ожидать этот код:
let foo = (x) => x+2;
Чтобы быть эквивалентом:
let foo = function(x) {
return x+2;
}
Если функция остается анонимной и неспособна ссылаться на себя, чтобы делать такие вещи, как рекурсия.
Итак, если тогда, в нашем блаженном невежестве, у нас было что-то вроде этого:
let foo = (x) => (x<2) ? foo(2) : "foo(1)? I should be a reference error";
console.log(foo(1));
Он успешно выполнялся, потому что эта функция явно не была анонимной:
let foo = function foo(x) {
return (x<2) ? foo(2) : "foo(1)? I should be a reference error";
}
Это может потенциально усугубиться тем фактом, что в других ситуациях, когда Babel неявно добавляет имя анонимным функциям (что, на мой взгляд, фактически является побочным эффектом поддержки имен неявных функций, в первую очередь, хотя Я мог ошибаться в этом), они правильно обрабатывают любые случаи краев и бросают опорные ошибки там, где вы ожидаете.
Например:
let foo = {
bar: function() {}
}
// Will surprisingly transpile to..
var foo = {
bar: function bar() {}
};
// But doing something like:
var foo = {
bar: function(x) {
return (x<2) ? bar(2) : 'Whats happening!?';
}
}
console.log(foo.bar(1));
// Will correctly cause a ReferenceError: bar is not defined
Вы можете проверить «скомпилированный просмотр» на этом быстром DEMO , чтобы увидеть, как Babel фактически транслирует, чтобы поддерживать поведение анонимной функции.
Короче говоря, быть явным с тем, что вы делаете, - это, как правило, хорошая идея, потому что вы точно знаете, чего ожидать от вашего кода. Отказ от использования неявных имен функций, скорее всего, является стилистическим выбором в поддержку этого, а также остается кратким и простым.
И, вероятно, подъем. Но эй, веселая прогулка.
Не забудьте назвать выражение - анонимные функции могут затруднить поиск проблема в стеке вызовов ошибки ( Обсуждение )
blockquote>Исходный ответ ниже
MDN имеет хорошее отклонение от того, как function name inference работает, включая два предупреждения:
Замечания
Существует нестандартное поведение вывода
<function>.name
в следующих двух сценариях:
- при использовании интерпретаторов сценариев
Интерпретатор сценария установит свойство имени функции только в том случае, если функция не имеет собственного свойства с именем name. ..
blockquote>
- при использовании js tooling
Будьте осторожны при использовании преобразований Function.name и исходного кода, таких как выполняемые с помощью компрессоров (minifiers) JavaScript или обфускаторов
....
В несжатом версия запускается в правдивую ветвь, а logs «foo» - это экземпляр «Foo», тогда как в сжатой версии он ведет себя по-разному и переходит в else-ветку. Поэтому, если вы полагаетесь на Function.name, как в приведенном выше примере, убедитесь, что ваш конвейер сборки не меняет имена функций или не предполагает, что функция имеет определенное имя.
blockquote>Что такое выражение имени функции?
Свойство
blockquote>name
возвращает имя функции или (до реализации ES6) пустую строку для анонимных функцийfunction doSomething() {} console.log(doSomething.name); // logs "doSomething"
Функции, созданные с помощью синтаксиса new Function (...) или просто Function (...), имеют свойство name для пустой строки. В следующих примерах создаются анонимные функции, поэтому имя возвращает пустую строку
blockquote>var f = function() {}; var object = { someMethod: function() {} }; console.log(f.name == ''); // true console.log(object.someMethod.name == ''); // also true
Браузеры, которые реализуют функции ES6, могут вывести имя анонимной функции из ее синтаксической позиции . Например:
var f = function() {}; console.log(f.name); // "f"
Мнение
Лично я предпочитаю (стрелка) функции, назначенные переменной по трем основным причинам:
Во-первых, я не ever используют
function.name
Во-вторых, смешение лексической области именных функций с назначением немного ослабляет:
// This... function Blah() { //... } Blah.propTypes = { thing: PropTypes.string } // ...is the same as... Blah.propTypes = { thing: PropTypes.string } function Blah() { //... } // ALTERNATIVELY, here lexical-order is enforced const Blah = () => { //... } Blah.propTypes = { thing: PropTypes.string }
И, в-третьих, все вещи, Я предпочитаю функции стрелок:
- сообщают читателю, что нет
this
, noarguments
и т. д.- выглядит лучше (imho)
- (в прошлый раз я смотрел, функции стрелок были немного быстрее)
EDIT: моментальные снимки памяти
Я слушал Podcast и гость рассказал о ситуации, когда ему приходилось иметь дело с ограничениями использования функций стрелок с профилированием памяти, я раньше был в в той же самой ситуации.
В настоящее время снимки памяти не будет включать имя переменной - так что вы можете найти преобразование функций стрелок в именованные функции только для подключения профилировщика памяти , Мой опыт был довольно прост, и я до сих пор доволен функциями стрелок.
Плюс я использовал только снимки памяти один раз, поэтому я чувствую себя комфортно, когда по-умолчанию чувствую «инструмент» для (субъективной) ясности.
Это связано с тем, что:
const Listing = ({ hello }) => (
<div>{hello}</div>
);
имеет выведенное имя листинга, хотя похоже, что вы его именовали, вы на самом деле не:
// we know the first three ways already...
let func1 = function () {};
console.log(func1.name); // func1
const func2 = function () {};
console.log(func2.name); // func2
var func3 = function () {};
console.log(func3.name); // func3
что об этом?
const bar = function baz() {
console.log(bar.name); // baz
console.log(baz.name); // baz
};
function qux() {
console.log(qux.name); // qux
}