Подтвердить что ты не робот

Почему `obj.foo = function() {};` не присваивает функции `foo` функции?

Как и в ES2015 (ES6), функции имеют собственные имена (включая официальное свойство name), а имена назначаются, когда функция создается разными способами в дополнение к очевидному объявлению функции и названному выражению функции, такие как присвоение переменных (имя функции задано как имя переменной), назначение свойств объекта (имя функции задано как имя свойства), даже значения по умолчанию для параметров функции (имя функции задано на имя параметра). Но присваивание свойства существующему объекту (например, не в инициализаторе объекта) не присваивает этому имени свойства функции. Почему нет? Разумеется, должна быть определенная причина, в которой это нежелательно/возможно. Что это было?

Чтобы быть ясным: я не спрашиваю, как обойти это. Я спрашиваю, что мешает этому, казалось бы, очевидному случаю, обрабатываться, когда так много других (включая значения параметров по умолчанию!). Должна быть веская причина.

Пожалуйста, не спекулируйте или не теоретизируйте. У TC39 была причина не включать его. Меня интересует, что это за причина. Я прошел через заметки совещания TC39, но еще не нашел его. Самое близкое, что я нашел до сих пор, - это Аллен Вирфс-Брок отвечая на вопрос Берги, чтобы сказать, что не было никакого консенсуса в отношении того, чтобы сделать это для этой формы из-за "различных возражений", но к сожалению, он не сказал, каковы эти возражения.

Подробнее:

Все следующие присваивают функции foo функции в совместимом браузере:

// Requires a compliant browser

// Assigning to a variable or constant...
// ...whether in the initializer...
{
    let foo = function() { };
    console.log("1:", foo.name); // "foo"
}
{
    const foo = function() { };
    console.log("2:", foo.name); // "foo"
}
// ...or later...
{
    let foo;
    foo = function() { };
    console.log("3:", foo.name); // "foo"
}
// As an initializer for an object property
{
    const obj = {
        foo: function() { }
    };
    console.log("4:", obj.foo.name); // "foo"
}
// Or as a method
{
    const obj = {
        foo() { }
    };
    console.log("5:", obj.foo.name); // "foo"
}
// Even if it a computed property name
{
    let name = "f";
    const obj = {
        [name + "o" + "o"]() { }
    };
    console.log("6:", obj.foo.name); // "foo"
}
// As a default value for a parameter
(function(foo = function() { }) {
    console.log("7:", foo.name); // "foo"
})();
// ...and a bunch of others
4b9b3361

Ответ 1

Allen Wirfs-Brock ответил в списке обсуждений с возражениями, которые помешали консенсусу TC39 в форме obj.foo = function() { }:

... для

cache[getUserSecret(user)] = function() {};

это приведет к утечке секретной информации пользователя как значения имени

и для

obj[someSymbol] = function() {}

это приведет к утечке значения Symbol в качестве значения имени

и для

 table[n]=function() {}

name скорее всего будет числовой строкой

Есть счетчики этих возражений (особенно последний, который крайне слаб, есть много других способов, которым функция автоматически назначает числовое имя строки), но это не точка; Дело в том, что это были возражения.

Он также добавил, что операция IsPropertyReference, которая потребуется (где в настоящее время только IsIdentifierRef)...

... является операцией во время выполнения, а для новой семантики требуется определение времени выполнения. Это все лишняя работа во время работы, которая может замедлить создание закрытий функций, которые появляются внутри циклов.

Итак, в целом, по-видимому, в то время, когда было принято решение, эти возражения переносились на этот день (и, вполне возможно, сейчас тоже), поэтому эта форма автоматически не называет функции, тогда как многие другие делают.

Ответ 2

Я прочитал ответы Аллена Вирфса-Брока, и он прямо говорит о возможных проблемах безопасности. Я лично с ним согласен.

Также могут быть проблемы с безопасностью. Свойство name потенциально течет через объект функции имя переменной, которой она первоначально назначена. Но мало что может сделать с именем локальной переменной, за пределами исходной функции. Но пропущенное имя свойства потенциально обладает большей способностью.

Похоже, возражения, о которых он говорит, имеют к этому какое-то отношение. Если TC39 больше не объясняет это решение, трудно понять, почему они оставили это так:).

Я сожалею, что больше не могу помочь тебе.

Ответ 3

Идея функции с именем немного страннее. Если вы рассматриваете функцию как еще один вид переменной, тогда ее присвоение не должно изменять внутреннее состояние назначенных переменных. Это похоже на волшебство. Это становится более запутанным, если функции передаются (хотя он может быть разрешен путем назначения имен при создании какой-либо функции, а не при ее передаче).

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

Я лично согласен с группой, которая думает, что имена функций странные, но я также думаю, что как только вы это делаете, вы должны пройти весь путь. Но люди такие глупые. Компромиссы не всегда имеют наибольший смысл.

Ответ 4

Я не уверен, что есть определенная причина.

obj.foo = function (){};

сначала создает ссылку для выражения функции в obj, затем привязывает foo к этой ссылке, которая уже имеет (только для чтения) имя.

Итак:

obj.fooC = (new Function ());
console.log(obj.fooC.name);//'anonymous'

obj.fooFE = function (){};
console.log(obj.fooFE.name);//''

obj.fooNFE = function a_name (){};
console.log(obj.fooNFE.name);//'a_name'

- нормальное поведение.

Есть ли ограничение на запись:

obj.foo = (function foo(){});