Можете ли вы динамически добавлять локальные переменные в функцию?
Я использую объекты для namespace моего кода JavaScript. Эти объекты обычно содержат функции, которые называются сопоставлением this
-pointer с самим объектом с помощью apply
. Однако я считаю неудобным использовать this
-pointer каждый раз, когда хочу получить доступ к другим функциям или свойствам объекта, особенно потому, что во многих случаях я использую new
-оператор для использования объектов-функций так, как вы использовать классы. Я бы предпочел написать new Line()
вместо new this.Line()
.
Было бы здорово, если бы вы могли добавить локальные переменные в функцию, как это делает php с extract
(после псевдокода это немного сложнее)
var sample_object = {
"some_function": function() {}
}
test() {
extract(sample_object);
some_function(); // imported from sample_object
}
Возможно ли это?
Ответы
Ответ 1
Я уверен, что eval
- ваш единственный ответ; но вы должны знать, что если какой-либо вход вне вашего контроля, это не безопасно
function dynamicArgs (varName, varValue) {
eval("var " + varName + "=" + JSON.encode(varValue) );
alert(a);
}
dynamicArgs("a", "value");
Вы можете увидеть проблему с этим. Как ваша функция должна вызывать динамическую переменную, если она не знает ее имени? Я жестко привязал его к переменной, поскольку передаю ее при вызове, но это не очень хорошее решение. Единственным решением будет другой eval
. Вы действительно должны думать о том, что вам нужно делать, и полезно ли это. Но это выполнимо.
Здесь он находится в действии: http://jsfiddle.net/mendesjuan/GG3Wu/
function dynamicArgs (varName, varValue) {
eval('var ' + varName + "='" + varValue + "';");
alert(eval(varName));
}
dynamicArgs("f", "Here I am");
Теперь вот пример вроде того, что вы делаете, создавая переменную из this.MyConstructor
http://jsfiddle.net/mendesjuan/AK3WD/
var ns = {
MyConstructor: function(val) {
this.prop = val;
},
runConstructor: function(val) {
var Ctor = "MyConstructor";
eval('var ' + Ctor + ' = this.' + Ctor);
return new MyConstructor(val);
}
}
alert( ns.runConstructor("Hello").prop );
И вот пример, если вы хотите импортировать все значения из объекта в область;
http://jsfiddle.net/mendesjuan/AK3WD/1/
var ns = {
MyConstructor: function(val) {
this.val= val;
},
anotherProperty: 5,
runConstructor: function(val) {
// Bring all the variables from this into this scope
for (var prop in this) {
eval('var ' + prop + ' = this.' + prop);
}
alert('Testing var anotherProperty: ' + anotherProperty);
var obj = new MyConstructor(val);
alert('Created MyConstructor: its prop is ' + obj.val)
}
}
ns.runConstructor("Hello");
Ответ 2
Существует спорный with
, в котором есть отличные приложения, но незначительно медленно и подвержен ошибкам. Он выдает ошибку в строгом режиме (который вы всегда должны выбирать) и будет устаревать.
var sampleObject = {
someFunction: function() {},
b: 10
}
with (sampleObject) {
typeof someFunction // "function"
var a = 42
var b = 20
}
sampleObject.a // undefined
sampleObject.b // 20
Обратите внимание, что новые переменные, определенные в with
-block, не будут добавлены к объекту. Тем не менее, если объект уже имел в нем одноименное свойство, это свойство было бы изменено (спасибо, @Rocket).
Просто для удовольствия, здесь реализация extract
с помощью eval
(что еще хуже, чем with
). Вы можете делать с ним невыразимые вещи, например, если ваш объект имеет такие свойства, как sampleObject['x; while (true) { alert("Hi!") }']
.
Ответ 3
Вот как я это сделал:
function smObject ( object) {
return function () {
function getter(prop) {
return function() {
return this[prop];
}
}
function setter(prop) {
return function(data) {
this[prop]=data;
}
}
for (var o = 0; o < object.length; o++) {
this[object[o]] = {};
this['get' + object[o]] = getter(object[o]);
this['set' + object[o]] = setter(object[o]);
}
}
}
теперь вы можете создать такую функцию:
var fields = ['Name', 'Id', 'Other', '....' ]
var MyFunction = smObject( fields );
var myObject = new MyFunction();
// getter/setters
myObject.setId(5);
myObject.getId(); // will return 5
С уважением,
Emanouil