Можете ли вы динамически добавлять локальные переменные в функцию?

Я использую объекты для 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