改变JavaScript的全局对象?

时间:2011-02-19 18:13:12

标签: javascript

有没有办法在JavaScript中更改 root 对象?

例如,在浏览器中, root 对象是“window”。所以

X = 5;
console.log(Y);

与:

相同
window.X = 5;
console.log(window.Y);

我现在要做的是更改此 root 对象,因此当我执行以下操作时:

X = 6;

我需要这个的原因:

Node.js应用程序中,程序的每个部分都可以访问全局对象。这是一个大问题,因为Node.js网络服务器执行的每个脚本都可以向其添加新变量。他们将在那里,直到重新启动网络服务器。我想通过更改全局对象来避免这种情况。

更新

我测试了以下代码,得到了一个非常有趣的结果。 您对以下代码的期望是什么?

var X = {A:"a",B:"b"};

with(X){
    A = 5;
    C = 7;
}
for(a in X){
    console.log(a+" is "+X[a]);
}

/* 
Expected Console Output:
A is 5
B is b
C is 7

Real Console Output:
A is 5;
B is b;

*/

有没有办法像我预期的那样获得输出?

更新

我现在用以下代码测试了模块系统。

//program.js
var t = require("./module.js");
t.Test();

console.log(A);

//module.js
A = 5;
exports.Test = function(){
    console.log("hello world!");
}

输出结果为:

hello world!
5

这告诉我,module.js中定义的变量“A”被添加到program.js的全局对象中。该模块也没有解决我的问题。

3 个答案:

答案 0 :(得分:6)

with语句,但不建议在严格模式下禁止使用。

最好明确地引用保存对象的变量。

回应更新的问题:

with将搜索范围链,直到找到具有匹配属性的对象或获取window。在对象上定义新属性是没有用的。

var X = { A: 5, B: 8, C: 7};
with(X){
    console.log(A, B, C);
}

答案 1 :(得分:5)

如果你在谈论变量,JavasScript有功能范围。

X = 5;  // global variable

console.log( window.X );  // 5

(function() {
   var X = 6;  // declare a local variable by using the "var" keyword

   console.log( X );  // 6
})();

console.log( window.X );  // 5

否则,您可以创建一个Object,并为其添加属性。

X = 5; 

console.log( window.X );  // 5

var obj = {};

obj.X = 6;

console.log( obj.X ); // 6

console.log( window.X );  // 5

编辑:添加可以使用的可能的解决方案。

您可以调用匿名函数,但将函数的上下文设置为X对象。然后,函数中的this将引用X

var X = {};
(function(){
    this.A = 5;
    this.B = 8;
    this.C = 7;
}).call(X);
for(a in X){
    console.log(a+" is "+X[a]);
}

.call()方法(以及.apply()方法)允许您显式设置 thisArg of a calling context. The first argument you pass will be how this`在上下文中定义调用

或者只是将X作为参数传递。

var X = {};
(function(X){
    X.A = 5;
    X.B = 8;
    X.C = 7;
})(X);
for(a in X){
    console.log(a+" is "+X[a]);
}

虽然最简单的是简单地引用它(正如我在上面的回答中所述)。

var X = {};
X.A = 5;
X.B = 8;
X.C = 7;
for(a in X){
    console.log(a+" is "+X[a]);
}

或使用模块模式:

   /****** I'm guessing at the use of "global" here ********/
global.myNamespace = (function(global,undefined) {

    // define the object to be returned
    var X = {};

    //  define private local variables
    var a_local = 'some value';
    var another_local = 'some other value';

    // define private functions
    function myFunc() {
        // do something with local variables
    }

    // give the return object public members
    X.someProperty = 'some value';
    X.anotherProperty = 'another value';
    X.publicFunc = function() {
        //do something with the local variables
        //    or public properties
    };
    X.anotherFunc = function() {
        //do something with the local variables
        //    or public properties
    };
    // return the object
    return X;

})(global);

console.log(myNamespace);

答案 2 :(得分:0)

我在EcmaScript 6中找到了一种调整with(context) { ... }的方法,以便我们分配的所有新变量都将进入context对象,而不是全局/ window对象。

感谢本文Metaprogramming in ES6: Part 3 - Proxies教我有关ES6代理功能的信息。

在代理中:

  • 我们重写has以返回true,因此我们的上下文似乎具有所有属性,并且当我们设置任何变量时,它将进入对象。
  • 我们重写get来从上下文中获取属性,或者如果它不在那里,则从up对象(默认为全局window)中获取属性)。

我知道with不被接受,但是这种技术可以创建可变的可扩展模块,在这里我们可以方便地以foo而不是Module.foo的方式访问成员,我不认为这是不安全或模棱两可的。

function scope(x, up=window) {
    return new Proxy(x, {
        has: (o, k) => true,
        get: (o, k) => k in o ? o[k] : up[k]
    });
}

var Test = {};

with (scope(Test)) {
    x = 1;
    y = 2;
    add_x = function(y) {
        console.log(x + y);
    }
}

Test.add_x(10);

with (scope(Test)) {
    x = 3;
    add_y = function(x) {
        console.log(x + y);
    }
}

Test.add_x(20);

Test.y = 5;

Test.add_y(30);