簡體   English   中英

更改JavaScript的with語句的行為,以防止分配修改全局對象

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

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上運行,因此,解決方案是否僅與此兼容。

希望有人對我如何實現這一想法有所了解。

謝謝你的幫助!

您正在嘗試從根本上改變with語句在JavaScript中的工作方式。 這是不可能的,因為您無法保證解釋器正在使用hasOwnProperty (或您有權訪問的任何其他構造)來檢查正在使用的對象上是否存在屬性。

您正在加入一個很好的傳統,希望它能with不同的方式工作,但事實並非如此。 它可以正常工作,最好避免。

兩件事情:

  1. 不要修改Object.prototype 這被認為是不好的做法,並且會在任何地方導致意外的結果,而且如果對其進行修改,其他JS框架甚至都無法運行。

  2. 請不要with使用。 它已從javascript中棄用,因為當存在與屬性同名的局部變量時,無法確定如何最好地發揮作用。

如果您需要遍歷對象的屬性,請執行以下操作:

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

您提到的代碼將幫助您實現覆蓋該設置邏輯。 https://developer.mozilla.org/zh-CN/JavaScript/Guide/Working_with_Objects提供了有關使用defineSetter覆蓋設置部分的信息,但強烈建議這樣做,即使在JavaScript 1.8.1及更高版本中也是如此。 我建議另一種方法。

為了使變量不在全局范圍之內,可以使用匿名函數。 由於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

我找到了一種完全隔離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);

也許對其他人有用;)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM