В SO действительно много вопросов, которые кажутся похожими на это, но на самом деле каждый из этих вопросов касается немного разных вещей. И также я знаю, что вещи, которые я описываю, являются хакерским и нерекомендованным способом, но в моем случае это действительно необходимо (размер кода ДЕЙСТВИТЕЛЬНО важен для меня, каждые пять байтов имеют значение):
У меня есть объект, который динамически заполняется некоторыми переменными (я подготавливаю его для внутреннего использования, но он заполняется переменными, определенными пользователем):
var scope = { 'a': 0, 'b': 12, 'c': 64 };
И у меня есть пользовательская анонимная функция, которой нужен прямой доступ к этой области, без использования this
(я бы действительно предпочел) , и она определена , а не в мой var
-обзор :
function anonymousFunc() { // user don't knows any names of arguments
console.log(a, b, c); // I expect '0, 12, 64'
}
На самом деле, scope
это даже не объект, а сложный массив, в котором хранятся уровни контекстов, так что, по правде говоря, на самом деле это выглядит примерно так: [ { 'a': 0 }, { 'b': 12, 'c': 64 } ]
, а затем я выбираю уровень для конкретного функция для доступа. И, чтобы быть еще более правдивым, у меня есть несколько подобных объектов, которые можно смешать в область действия функции.
Таким образом, лучший другой способ сделать без взлома (eval
или with
) (путь ООП), я вижу, это заставить пользователя вести себя так:
(function() {
function prepareAndCall(f) {
c = this.ctx[level];
l = currentLabels();
m = makeChunk();
f();
}
var c, l, m;
// it is injected from user code
function anonymousFunc() {
console.log(c.a, c.b, l.g, m.pos);
}
prepareAndCall(anonymousFunc);
})();
Но я хочу, чтобы пользователь не думал о том, где ему нужно взять эти переменные. Я могу смешать их в одном объекте, но в моем случае это тоже не очень удобно: большинство этих переменных определяются самим пользователем во внешнем месте, поэтому он ожидает, что они будут находиться непосредственно в его области видимости, и я ' Мне нравится, если он ничего не знает о тех c
- m
- l
переменных, даже если это просто c
. Я хочу подражать тому, что у него есть эти переменные на руках. И он знает, что может случайно переопределить их.
Итак, я нашел несколько методов:
One С eval, и требует строкового источника функции
( Upd. , я удалил предыдущий плохой пример после @ Gijs комментировал и обновил его новым )
А второй загрязняет глобальный контекст ( при jsfiddle )
(function(global_ctx) {
// here is the user context, variables
// defined here are accessible to user
var __g = global_ctx;
__g.__test_var = 5;
if (__test_var !== 5) alert('__g is not global context');
var __f = (function() {
// here is the inner context, variables
// defined here are not accessible to user
var scope = [
{ a: 16 },
{ oo: 12 },
{ b: 17, c: 20 }
];
function callUserFunc(f) {
//console.log('call user func');
loadVars(__g, 2);
f();
}
// __g.__f = callUserFunc;
function loadVars(g, level) {
for (name in scope[level]) {
g[name] = scope[level][name];
}
}
return callUserFunc;
})();
if (typeof scope !== 'undefined') alert('scope is visible, error');
if (typeof loadVars !== 'undefined') alert('loadVars is visible, error');
__f(function() { // user function will be inserted here
if (typeof oo !== 'undefined') alert('user function sees what it must not see');
alert(b + ', ' + c);
});
})(this);
В результате, я думаю, что это, вероятно, не вопрос, а скорее предмет для обсуждения: действительно ли это плохой способ использования with
или eval
в данном случае ? Потому что я не знаю другого способа сделать это так.
Связанная литература: