Поскольку вы заявляете, что хотите, чтобы поведение было похоже на window/global
, я предположил, что вы хотите это в данном контексте, отличном от window/global
. Самый простой способ сделать это - использовать оператор with
в сочетании с объектом local
и функцией define
, которые реализуют Object.defineProperty
с local
в качестве цели. Вы просто помещаете свой собственный код в блок with
.
ВАЖНО: with
перегружает собственные локальные переменные (var, let, const
). Из-за этого очень важно сохранять четкий код и предотвращать дублирование имен в контексте и родительском / дочернем контекстах.
Позволяет начать с контекста, в данном случае я использую замыкание, но это также может быть функция, конструктор или любой другой контекст.
// This closure represents any function, class or other scoped block.
(function (){
}());
Затем мы добавляем контейнер для хранения и функцию define
. Это в основном то, с чего вам всегда следует начинать, если вы хотите получить доступ к локальным свойствам из любого места вашего кода (в этой области).
// This is where we store the local property. (except: var, let, const)
const local = {};
// The define function is used to declare and define the local properties.
function define(name, descriptor){ Object.defineProperty(local, name, descriptor); }
Теперь вы можете поместить любой код перед оператором with
, но для этого примера мы добавим только код, для которого требуется local
, так что следующим шагом будет создание оператора with
.
// This with statement extends the current scope with local.
with(local){
// This is where your code goes.
}
Теперь внешняя структура оператора with
готова, и мы можем начать добавлять код внутри оператора with.
Весь код, помещенный в блок оператора with
, имеет доступ к свойствам local
, как если бы они были определены, например, с помощью var
, включая свойства, определенные в операторе with
.
Существует несколько способов работы со свойствами local
. Самый простой способ определить свойство - установить его непосредственно в 'local'. Это нужно сделать только один раз, после чего свойство доступно только по его имени.
local.setDirectly = "directly set value";
console.log(setDirectly); // logs "directly set value"
Другим способом определения свойства, кроме поддержки get/setters
, а также опций перечисления и доступа для записи, является использование функции define
. Ожидайте того же поведения, что и от Object.defineProperty
.
Например, вы можете добавить свойство time
, которое возвращает текущее время.
define("time", {
get: function(){
var date = new Date();
return date.getHours() + ":" + ("0" + date.getMinutes()).substr(-2);
}
})
console.log(time);
Или вы можете создать свойство счетчика, которое увеличивается при каждом обращении к нему, помещая его во вложенное замыкание, чтобы защитить собственную переменную счетчика от нежелательных изменений.
(function (){
var counterValue = 0;
define("count", {get: function(){ return counterValue++ }});
}());
console.log(count); // logs 0
console.log(count); // logs 1
Когда вы объедините все это, вы получите нечто похожее на следующий код
// This closure represeents any function, class or other scoped block.
(function(){
// This is where we store the local property. (except: var, let, const)
const local = {};
// The define function is used to declare and define the local properties.
function define(name, descriptor){ Object.defineProperty(local, name, descriptor); }
// This with statement extends the current scope with local.
with(local){
// This is where your code goes.
// Defining a variable directly into local.
local.setDirectly = "directly set value";
console.log(setDirectly); // logs "directly set value"
// Defining local properties with the define function
// For instance a time variable that return the current time (Hours:Minutes)
define("time", {
get: function(){
var date = new Date();
return date.getHours() + ":" + ("0" + date.getMinutes()).substr(-2);
}
})
console.log(time); // logs HH:MM
// Or a counter property that increments each time it's been accessed.
(function (){
var counterValue = 0;
define("count", {get: function(){ return counterValue++ }});
}());
console.log(count); // logs 0
console.log(count); // logs 1
console.log(count); // logs 2
console.log(count); // logs 3
}
}());
Как я уже упоминал ранее, важно понимать последствия использования оператора with
. Более подробную информацию о with
можно найти на MDN - с . Как говорится в вопросе, это поиск того, как вы могли бы, а не как вы должны. Используйте информацию на MDN, чтобы увидеть, соответствует ли она вашей ситуации.