我在函数中有一个本地表变量,并且一个子函数应该具有一个具有相同名称的变量,同时仍然能够访问父变量。这应该是显而易见的,但不幸的是,如果我在任何地方定义一个具有相同名称的局部变量,JavaScript不允许我访问父变量:
var p = {alpha : 'beta'};
console.debug (p);
// [08:16:21.896] ({alpha:"beta"})
// Okay.
(function() {
console.debug (p);
// [08:16:21.896] ({alpha:"beta"})
// Right! JavaScript, you're so awesome!
})();
// One moment though, I think I still need the parent's table...
(function() {
var p = { 'p': p };
console.debug (p);
// [08:16:21.896] ({p:(void 0)})
// Wait, what?
})();
// Okay, maybe giving it the same name in the same statement confuses you?
(function() {
var parent_p = p;
var p = {};
console.debug (parent_p);
// [08:16:21.897] undefined
})();
// Give me back my variable! http://v.gd/jsWhyDoYouDoThis
那里发生了什么?有什么方法可以解决这个问题吗?
答案 0 :(得分:5)
尽管JavaScript看起来像C,Java等,但它们具有块级范围。 JavaScript具有功能级范围。
因此在JavaScript中,if
语句不会创建新块。只有功能。最重要的是,var
iable和function
声明被“提升”(无形地移动)到块的顶部。这就是你问题的原因。
定义变量时:
function foo() {
bar();
var x = 1;
}
实际上被解释为:
function foo() {
var x;
bar();
x = 1;
}
因此,如果您在x
中阅读了变量bar()
,即使它在更高的范围内定义(foo()
之外),也会显示foo()
的{{1}} x
1}},执行undefined
时为bar()
。
仔细研究一下你的代码,试着去理解实践中发生的事情:
var p = {alpha : 'beta'};
...
(function() {
// var p = { 'p': p }; actually is:
var p;
p = { 'p': p }; // thus p inside is `undefined`
console.debug (p);
})();
(function() {
// var parent_p = p; var p = {}; actually is:
var parent_p, p;
parent_p = p; // that's why parent_p becomes undefined here
p = {};
console.debug (parent_p);
})();
答案 1 :(得分:2)
不,在标准的ECMAScript中无法做到这一点。
块内任何地方的var
声明都是JS解析器的指令,该块中所有使用命名变量的指针都指向局部变量。在JS中,为此目的的块是周围的函数,或者如果不在函数定义(*)中则是全局的。
因此,在上一个示例中,您要为parent_p
分配局部变量p
的值,因为您尚未为其分配任何内容undefined
。
如果绝对必须重用变量名称,则必须使用中间范围来保存引用:
(function() {
var parent_p = p;
(function() {
var p = {};
console.debug (parent_p);
})();
})();
ECMAScript的未来版本可能会采用Mozilla JS扩展let
,它为定义引入了比函数更小的块。这可以让你更简单地拼写:
(function() {
var parent_p = p;
let (p = {}) {
console.debug (parent_p);
}
})();
另一种常见方法是将变量作为参数传递:
(function(parent_p) {
var p = {};
console.debug (parent_p);
})(p);
(*:您可以使用全局对象从全局范围读取变量 - 即window.p
- 但您无法通过封闭非全局范围来获取局部变量。)
答案 2 :(得分:1)
作为acdcjunior正确答案的另一种观点:
由于功能范围(无块范围)和提升,这个:
(function() {
var parent_p = p;
var p = {};
console.debug (parent_p);
// [08:16:21.897] undefined
})();
变为:
(function() {
var parent_p, p; //both undefined
parent_p = p; //undefined
p = {};
console.debug (parent_p);
// [08:16:21.897] undefined
})();
所以要解决这个问题,你要将变量作为包含它的对象的属性来访问;在这种情况下,window
是'host'/'root'对象,它将p
作为其中一个直接属性。
(function() {
var parent_p = window.p,
p = {};
console.debug (parent_p);
// [08:16:21.897] ({alpha:"beta"})
})();