Изменение поведения JavaScript с помощью оператора, чтобы предотвратить изменение глобального объекта в присваивании - PullRequest
2 голосов
/ 20 февраля 2011

Оператор with в JavaScript сначала проверяет, существует ли запрошенное свойство объекта, а затем решает, следует ли ему устанавливать свойство данного объекта или свойство глобального объекта.

Пример:

var x = {a:5};

with(x){
    a = 6; //x.a is now 6
    b = 7; //window.b is now 7, x.b still does not exist
}

Я хочу изменить поведение with, чтобы при проверке наличия свойства объекта, с которым я работаю, оно всегда обрабатывалось так, как если бы оно существовало, предотвращая случайное назначение в блоке изменение глобального объекта.

Может ли это быть достигнуто путем перегрузки функции, которая проверяет, существует ли свойство объекта или нет? Например что-то вроде этого:

Object.prototype.__hasOwnProperty__ = function(p){
    return true;
}

var x = {a:5};

with(x){
    a = 6; //x.a is now 6
    b = 7; //x.b should now be 7
}

Мой код работает на node.js & V8, поэтому не имеет значения, работают ли решения только с этим.

Надеюсь, у кого-то есть идея, как я это понимаю.

Спасибо за вашу помощь!

Ответы [ 4 ]

3 голосов
/ 20 февраля 2011

Вы пытаетесь фундаментально изменить работу оператора with в JavaScript.Это невозможно, поскольку вы не можете гарантировать, что интерпретатор использует hasOwnProperty (или любую другую конструкцию, к которой у вас есть доступ) для проверки наличия свойства объекта, с которым вы работаете.1004 * Вы присоединяетесь к хорошей традиции желать, чтобы with работал по-другому, но это не так.Он работает так, как работает, и его лучше избегать.

2 голосов
/ 20 февраля 2011

Две вещи:

  1. Не изменяйте Object.prototype. Это считается плохой практикой и повсеместно приведет к неожиданному результату, плюс другие платформы JS даже не будут работать, если он был изменен.

  2. Пожалуйста, не используйте with. Он устарел из javascript, потому что не может быть определено, как он должен лучше всего функционировать, когда существует локальная переменная с тем же именем, что и у свойства.

Если вам нужно перебрать свойства объекта, просто сделайте это:

for (var i in myObject) {
    if (myObject.hasOwnProperty(i)) {
        // processing logic here
    }
}

Вы упомянули код, который поможет вам переопределить эту настройку логики. https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects содержит информацию об использовании defineSetter для переопределения части настройки, но это настоятельно рекомендуется, даже если это невозможно из JavaScript 1.8.1 и после. Я бы порекомендовал другой подход.

0 голосов
/ 20 февраля 2011

Я нашел способ полностью изолировать скрипт.Это не хороший код, но он работает.

X = 5;
function ExecuteIsolated(code){
    var vars = [];
    (function(){
        for(var v in window){
            vars.push(v);                   
        }           
        eval("var "+vars.join(",")+";");

        //Totally isolated code here:           
        eval(code);     
        //End of totally isolated code
    })();
    var i = 0;
    for(var v in window){
        if(vars[i++] != v){
            delete window[v];
            i--;
        }
    }
}       
ExecuteIsolated("X = 8");
console.log(X);

Может быть, это полезно для кого-то еще;)

0 голосов
/ 20 февраля 2011

Чтобы сохранить переменные вне глобальной области видимости, вы можете использовать анонимную функцию;Так как JavaScript имеет функциональную область видимости, все переменные, определенные в функции, являются локальными в области видимости.Это требует, чтобы вы объявляли переменные должным образом, но я бы настоятельно рекомендовал это при любых обстоятельствах.

(function () {
    var a = 1;
    alert("a is... " + a);
    // do more stuff here
}());
alert(typeof a); // should be undefined

Пример: http://jsfiddle.net/AWDzV/

Это не относится конкретно к вашим with заявление, но это, вероятно, лучший способ выполнить то, что вы ищете.Затем все, что вам нужно сделать, чтобы эмулировать поведение оператора with, - это использовать переменную:

(function () {
    var a = 1,
        some_very_long_object_name = {a: 1, b: 2, c: 3},
        obj = some_very_long_object_name;
    obj.a = 2;
    obj.b = 3;
    obj.c = 4;
}());
alert(typeof a); // should be undefined

Не лучший код в мире, но он демонстрирует, что использование короткого имени переменнойзаменить длинное имя объекта работает отлично.В общем, я считаю, что это, вероятно, лучшее решение.

Конечно, любая переменная, которая не была должным образом объявлена, будет "просачиваться" в глобальную область видимости:

(function () {
    a = 1; // notice the lack of "var" keyword
}());
alert(a); // should be 1

Пример: http://jsfiddle.net/AWDzV/1/

Но вы можете использовать JSLint , чтобы помочь отследить эту конкретную ошибку.Выполнение этого кода выше приводит к следующему сообщению об ошибке:

Ошибка: подразумеваемая глобальная: 2,4, предупреждение 4

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...