开发者

Changing the behavior of JavaScript's with statement to prevent assignment from modifying the global object

The with statement in JavaScript first checks if the requested property of the object exists before it decides if it should set the property of the given object or the property of the global object.

Example:

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
}

I want to change the behavior of with, so that when it checks for the presence of a property on the object I'm working with it will always treat it as though it exists, preventing assignments within the block from accidentally modifying the global object.

Could this be accomplished by overloading the function that checks whether the property of the object exists or not? For example something like this:

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
}

My code runs on node.js & V8, so it doesn't matter if the solutions only work with this.

Hope someone has an ide how I realize this.

Thanks for开发者_如何学Go your help!


You're trying to fundamentally change how the with statement works in JavaScript. This isn't possible, because you have no guarantee that the interpreter is using hasOwnProperty (or any other construct you have access to) to check for the presence of a property on the object you're working with.

You're joining a nice tradition of wishing that with worked differently, but it doesn't. It works how it does and it's best avoided.


Two things:

  1. Don't modify the Object.prototype. It's considered bad practice and will cause unexpected result everywhere, plus other JS frameworks won't even run if it's been modified.

  2. Please don't use with. It is being deprecated from javascript because it can't be determined how it should best function when there is local variable with the same name as a property.

If you need to iterate over the properties of an object, just do this:

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

You mentioned code that would help you achieve overriding that setting logic. https://developer.mozilla.org/en/JavaScript/Guide/Working_with_Objects has information on using defineSetter to override the setting portion, but it is highly recommended, on not even possible from JavaScript 1.8.1 and after. I would recommend another approach.


To keep variables out of the global scope, you can use an anonymous function; since JavaScript has functional scoping, all variables defined in a function are local in scope. It requires you to declare variables properly, though, but I would highly suggest that under any circumstance.

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

Example: http://jsfiddle.net/AWDzV/

This doesn't specifically deal with your with statement, but it is probably the best way to accomplish what you're looking for. Then, all you have to do to emulate the behavior of the with statement is to use a variable:

(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

Not the best code in the world, but it does demonstrate that using a short variable name to replace a long object name works perfectly. All-in-all, I feel this is probably the best solution.

Of course, any variable not declared properly will "leak" into the global scope:

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

Example: http://jsfiddle.net/AWDzV/1/

But you can use JSLint to help catch that particular error. Running it on the above code yields the following error message:

Error: Implied global: a 2,4, alert 4


I've found a way to totally isolate a skript. It's not good code, but it works.

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

Maybe its useful for someone else ;)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜