Изменить переменную область действия в Javascript
Меня не интересует вызов или применяется для изменения ссылки this
. Только для моих собственных интересов я играю с идеей для другого, требует техники для javascript, которая сделала бы для некоторых более чистых определений, и цель заключалась в том, чтобы не передавать массивы или дублировать имена ссылочных модулей для моих определений.
У меня есть примерное решение (просто доказательство концепции), использующее toString и eval для функции, но мне интересно, есть ли более безопасный или более эффективный способ сделать это.
// Sample module libraries (would probably be in their own files)
someModules = {
testModule: {test: function(){console.log("test from someModule")}},
anotherModule: { doStuff: function(){console.log("Doin stuffs!");}}
};
sampleRequire = function() {
// Load the modules
for (var i=arguments.length-2; i>=0; --i){
// Create a local variable reference to the module
eval ('var '+arguments[i]+' = someModules.'+arguments[i].toString());
}
// Redefine the programmer function so that it has my local vars in its scope
eval("var fn = "+arguments[arguments.length-1]);
return fn;
}
// Main code...
sampleRequire( 'testModule', 'anotherModule',
function(){
testModule.test();
anotherModule.doStuff();
}
)();
Edit:
Pointy сделал отличную оценку, что это полностью разрушит масштаб основной функции, что часто бывает неприемлемым. В идеале я хотел бы видеть, что переменные модуля добавляются в область функций, не сбивая другие переменные с областью (за исключением имен модулей - программист должен знать, что нельзя использовать одно и то же имя для двух вещей). Я уверен, что это, вероятно, невозможно, но я все равно буду любить некоторые идеи.
Другая цель - сделать это гибко, не добавляя аргументы на модуль к основной функции. В противном случае мы вернемся к квадрату с стилями CommonJS (которые я не пытаюсь сражаться, просто интересуюсь областью!).
Ответы
Ответ 1
Я склонен говорить, что "вы делаете это неправильно". Использование необъявленных переменных никогда не является хорошей идеей, даже если вы можете.
Вот еще один хак, который записывает модули в глобальный объект. Однако это может иметь побочные эффекты для методов, вызванных основной функцией.
sampleRequire = function() {
var cache = {};
var moduleNames = [].slice.call(arguments);
var fn = moduleNames.pop();
return function () {
var result, name, i;
// export modules to global object
for (i = 0; i < moduleNames.length; i++) {
name = moduleNames[i];
cache[name] = window[name]; // remember old values
window[name] = someModules[name];
}
result = fn.apply(null, arguments);
// restore original global stuff
for (i = 0; i < moduleNames.length; i++) {
name = moduleNames[i];
window[name] = cache[name];
}
return result;
};
}
Я также пробовал какую-то магию с ключевым словом with
, которое в основном было сделано именно для того, что вы хотите. Однако, похоже, что в этом случае он не работает без eval
.
Ответ 2
Я не могу думать о другом способе делать то, что тебе нужно. Я также подозреваю, что это может быть одним из немногих вариантов использования eval
, который не является злом. Но имейте в виду, что модули могут полагаться на свои области, и это может сломать их.
Ответ 3
Как насчет чего-то типа:
someModules = {
testModule: {test: function(){console.log("test from someModule")}},
anotherModule: { doStuff: function(){console.log("Doin stuffs!");}}
};
function requireModules() {
var all = [];
for (var i = 0, l = arguments.length; i<l; i++) {
all.push(someModules[i]);
}
return all;
}
(function(testModule,anotherModule){
testModule.test();
anotherModule.doStuff();
}).apply(null,requireModules('testModule','anotherModule'));