Я читаю серию книг «Вы не знаете JS» и попытался запустить фрагмент:
function foo() {
console.info( this.a );
}
function doFoo(fn) {
// `fn` is just another reference to `foo`
fn(); // <-- call-site!
}
var obj = {
a: 2,
foo: foo
};
var a = "oops, global"; // `a` also property on global object
doFoo( obj.foo ); // "oops, global"
(Вы можете найти его во 2-й главе 3-й книги: 'это' Теперь все имеет смысл)
Если я сохраню это в 'foo.js' и запустил с узел foo.js (v 8.11.1), я получу undefined. Если я запускаю узел REPL и набираю тот же код, то получаю:
> function foo() { console.info(this.a); }
undefined
> function doFoo(fn) { fn(); }
undefined
> var obj = { a:2, foo:foo };
undefined
> var a = "oops, global";
undefined
> doFoo(obj.foo);
oops, global
undefined
Как и ожидалось из книги. Тот же результат на консоли разработчика Firefox.
Если я удалю объявление и оставлю только назначение a = "oops, global", оно будет работать должным образом как на REPL, так и на Node.js. Для меня это имеет больше смысла, потому что таким образом я устанавливаю свойство для глобального объекта, в то время как «исходным» способом я просто объявляю переменную.
Может ли кто-нибудь объяснить мне такое поведение? Спасибо вам всем.
Обновлено: Я думаю, что близок к решению, я заметил, что если я сделаю сценарий foo.js, который содержит только:
var x = 42;
console.info(this);
У меня {}, значит, x не привязан к глобальному объекту. Если я запускаю REPL на Node.js и набираю тот же код, я получаю большой объект с прикрепленным к нему x:
{
...
x: 42
}
Так что я думаю, что разница зависит от того, «кто является глобальным объектом?» в REPL и в Node.js.



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Когда вы запускаете файл в Node.js, ваш var a на самом деле находится не в глобальной области, а в области функции - области функции модуля (подробнее об этом здесь). По сути, все содержимое файла запускается как внутри функции. Итак, var a фактически находится в этой области действия.
Тогда как в REPL это действительно глобально.
Извините, если я настаиваю, но я бы попытался хорошо понять: это та же самая причина, по которой при загрузке Node.js REPL с помощью Object.prototype; и Array.prototype он отвечает с помощью { } и [ ], в то время как с тем же вводом движок браузера (например, Chrome v8) отвечает с {constructor: ƒ, __defineGetter__: ƒ, __defineSetter__: ƒ, hasOwnProperty: ƒ, __lookupGetter__: ƒ, …} и [constructor: ƒ, concat: ƒ, find: ƒ, findIndex: ƒ, pop: ƒ, …]? Спасибо за ваше время.
Совсем не та же причина (т.е. сфера действия). Это больше связано с тем, как движок решает их показать. .prototype - интересный объект, о котором стоит прочитать отдельно. Но в основном он имеет некоторые общие свойства, такие как constructor, hasOwnProperty и т. д. Chrome, показывающий {constructor ...} для Object.prototype, и [constructor ...] для Array.prototype, - лишь его стилистический выбор. Firefox отображает это иначе. Node вообще не отображает эти внутренние свойства, но вы все равно сможете получить к ним доступ, если укажете их по имени, то есть Object.prototype.constructor.
Я пришел к такому же выводу, что и ваше изменение, вы можете опубликовать его как ответ на свой вопрос.