更改JavaScript with with语句的行为以防止赋值修改全局对象

时间:2011-02-19 21:35:01

标签: javascript while-loop

JavaScript中的with语句首先检查对象的请求属性是否存在,然后才决定是否应该设置给定对象的属性或全局对象的属性。

示例:

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 个答案:

答案 0 :(得分:3)

您正尝试从根本上改变with语句在JavaScript中的工作方式。这是不可能的,因为您无法保证解释器正在使用hasOwnProperty(或您有权访问的任何其他构造)来检查您正在使用的对象上是否存在属性。

你加入了一个很好的传统,希望with的工作方式不同,但事实并非如此。它的工作原理如何,最好避免使用。

答案 1 :(得分:2)

两件事:

  1. 请勿修改Object.prototype。它被认为是不好的做法,并且会在任何地方引起意想不到的结果,而且如果它被修改,其他JS框架甚至都不会运行。

  2. 请不要使用with。它是从javascript中弃用的,因为当存在与属性同名的局部变量时,无法确定它应该如何最佳运行。

  3. 如果需要迭代对象的属性,只需执行以下操作:

    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及更高版本。我会推荐另一种方法。

答案 2 :(得分:0)

要使变量不在全局范围内,可以使用匿名函数;由于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

答案 3 :(得分:0)

我找到了一种完全隔离skript的方法。这不是很好的代码,但它确实有用。

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);

也许它对其他人有用;)