javascript中变量的范围是什么?它们在函数内部的作用域与在函数外部的作用域相同吗?或者这有关系吗?此外,如果变量是全局定义的,那么变量存储在哪里?


当前回答

全局声明的变量具有全局范围。在函数中声明的变量的作用域是该函数,并隐藏同名的全局变量。

(我相信真正的JavaScript程序员可以在其他答案中指出许多微妙之处。特别是我在这个页面上看到了这到底意味着什么。不过,希望这个更为介绍性的链接足以让你开始。)

其他回答

运行代码。希望这能提供一个关于范围界定的想法

Name = 'global data';
document.Name = 'current document data';
(function(window,document){
var Name = 'local data';
var myObj = {
    Name: 'object data',
    f: function(){
        alert(this.Name);
    }
};

myObj.newFun = function(){
    alert(this.Name);
}

function testFun(){
    alert("Window Scope : " + window.Name + 
          "\nLocal Scope : " + Name + 
          "\nObject Scope : " + this.Name + 
          "\nCurrent document Scope : " + document.Name
         );
}


testFun.call(myObj);
})(window,document);

(函数foo(){console.log(foo)})();console.log(foo类型);//未定义,因为“foo”的作用域是它自己的表达式//但是,像这样(函数foo(){console.log('1:',foo)//函数foofoo=100console.log('2:',foo)//函数foo,不是100,为什么?})()

为了补充其他答案,范围是所有声明的标识符(变量)的查找列表,并强制执行一组严格的规则,以确定当前执行的代码如何访问这些标识符。该查找可能用于分配变量,该变量是LHS(左侧)引用,也可能用于检索其值,该值是RHS(右侧)引用。这些查找是JavaScript引擎在编译和执行代码时在内部执行的操作。

因此,从这个角度来看,我认为我在凯尔·辛普森(Kyle Simpson)的《范围与关闭》(Scopes and Closures)电子书中找到的一张图片会有所帮助:

引用他的电子书:

该构建表示程序的嵌套范围规则集。第一个建筑物的楼层代表您当前执行的范围,无论你在哪里。建筑的顶层是全球范围。通过查看当前楼层来解析LHS和RHS参考,如果你找不到,就乘电梯到下一层,看那里,然后看下一个,以此类推。一旦你到达顶层(全球范围),你要么找到你想要的,要么不要。但你必须停止不管。

值得一提的是,“范围查找一旦找到第一个匹配项就停止”。

“作用域级别”的概念解释了如果在嵌套函数中查找“This”,为什么可以使用新创建的作用域来更改“This”。这里有一个链接,介绍了所有这些细节,您想了解的关于javascript范围的一切

JavaScript中有两种类型的作用域。

全局范围:在全局范围中宣布的变量可以在程序中的任何地方非常流畅地使用。例如:var carName=“BMW”;//这里的代码可以使用carName函数myFunction(){//这里的代码可以使用carName}函数作用域或局部作用域:在此作用域中声明的变量只能在其自身的函数中使用。例如://这里的代码不能使用carName函数myFunction(){var carName=“BMW”;//这里的代码可以使用carName}

几乎只有两种类型的JavaScript作用域:

每个var声明的范围都与最直接的封闭函数相关联如果var声明没有封闭函数,则为全局范围

因此,除函数之外的任何块都不会创建新的作用域。这解释了for循环覆盖外部范围变量的原因:

var i = 10, v = 10;
for (var i = 0; i < 5; i++) { var v = 5; }
console.log(i, v);
// output 5 5

改用函数:

var i = 10, v = 10;
$.each([0, 1, 2, 3, 4], function(i) { var v = 5; });
console.log(i,v);
// output 10 10

在第一个示例中,没有块范围,因此最初声明的变量被覆盖。在第二个示例中,由于函数的原因,出现了一个新的作用域,因此最初声明的变量是SHADOWED,而不是重写。

就JavaScript范围而言,这几乎是您需要了解的全部内容,除了:

try/catch仅为异常变量本身引入新范围,其他变量没有新范围with子句显然是另一个例外,但不鼓励使用with子句(https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/with)

因此,您可以看到JavaScript作用域实际上非常简单,尽管并不总是直观的。需要注意的几点:

var声明被提到了范围的顶端。这意味着无论var声明发生在哪里,对于编译器来说,就像var本身发生在顶部一样同一范围内的多个var声明组合在一起

因此,此代码:

var i = 1;
function abc() {
  i = 2;
  var i = 3;
}
console.log(i);     // outputs 1

相当于:

var i = 1;
function abc() {
  var i;     // var declaration moved to the top of the scope
  i = 2;
  i = 3;     // the assignment stays where it is
}
console.log(i);

这似乎与直觉相悖,但从命令式语言设计者的角度来看,这是有道理的。