x
в вашем примере доступен только для кода в startup.js
. Это не доступно нигде. Это не глобальный (который, я думаю, вы уже знаете), это глобальный модуль внутри startup.js
модуля.
Чтобы сделать его доступным для кода Controller
, обычно нужно передать его Controller
в качестве аргумента:
var controller = new Controller(props, x);
// ------------------------------------^
Это не передает переменную, но она передает текущее значение переменной на момент выполнения этой строки кода.
Если вы хотите передать Controller
что-то, что будет видеть текущее значение x
, даже если вы измените его, вы поместите x
в объект как свойство и передадите ссылку на объект на Controller
вместо:
var stuff = {x: 10};
// ...
var controller = new Controller(props, stuff);
Controller
запомнит ссылку на объект, а затем найдет x
этого объекта:
class Controller {
constructor(props, stuff) {
this.stuff = stuff; // <====
}
createEntry(entry, callback) {
console.log(stuff.x);
// ---------^^^^^^
return callback(entry);
}
}
module.exports = Controller;
В качестве альтернативы, в зависимости от того, что такое x
(параметр конфигурации для всей системы?): Вы можете поместить x
и другие связанные с ним вещи в их собственный модуль (скажем, stuff.js
):
module.exports = {x: 10};
... и иметь controller.js
и все остальное, что нужно для загрузки модуля:
var stuff = require("./stuff");
// ...
class Controller {
constructor(props) {
}
createEntry(entry, callback) {
console.log(stuff.x);
// ---------^^^^^^
return callback(entry);
}
}
Я думаю, что вышеизложенное отвечает на вопросы № 2 и № 3, но:
1. Как работает область видимости под капотом?
Scoping - это лексическая (текстовая) концепция, которая определяет, какие идентификаторы, et. al., доступны для кода. Области действия работают как вложенные блоки: каждая область имеет доступ ко всему в своей содержащей области. Так, например:
var x;
// Code here has access to `x`
function outer() {
var y;
// Code here has access to `x` and `y`
function inner() {
var z;
// Code here has access to `x`, `y`, and `z`
}
inner();
}
outer();
Вы можете подумать: «Эй, подожди, но что, если ты позвонишь outer
дважды? Тогда есть два y
с!» И вы абсолютно правы, есть! А также два inner
с. Каждый inner
имеет доступ к одному и тому же x
, но у каждого есть разные y
: y
, созданный для вызова outer
, который создал inner
.
Вот как замыкания работают. Подробнее:
Re this.x
: Вы упомянули использование this
для доступа к x
(например, this.x
). Этот механизм (this.x
) ищет свойство объекта . Напротив, ваша x
переменная не является свойством, это переменная. Объекты JavaScript и область видимости не имеют ничего общего друг с другом. Хотя мы часто концептуализируем область видимости как использование скрытых объектов за кулисами (спецификация, безусловно, делает это), эти объекты являются чисто концептуальными и не доступны в коде (за одним исключением: глобальный объект, который дублируется как реальный объект и контейнер для глобальных переменных, объявленных с var
и глобальных объявленных функций [но не для переменных, объявленных с let
или const
, или классов, определенных с class
]).