有没有办法在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
的全局对象中。该模块也没有解决我的问题。
答案 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);