javascript中变量的范围是什么?它们在函数内部的作用域与在函数外部的作用域相同吗?或者这有关系吗?此外,如果变量是全局定义的,那么变量存储在哪里?
当前回答
在JavaScript中,有两种类型的作用域:
本地范围全局范围
Below函数有一个局部范围变量carName。这个变量不能从函数外部访问。
function myFunction() {
var carName = "Volvo";
alert(carName);
// code here can use carName
}
Below Class有一个全局范围变量carName。这个变量可以从类中的任何地方访问。
class {
var carName = " Volvo";
// code here can use carName
function myFunction() {
alert(carName);
// code here can use carName
}
}
其他回答
我很喜欢接受的答案,但我想补充一点:
作用域收集并维护所有声明的标识符(变量)的查找列表,并对当前执行的代码如何访问这些标识符实施一组严格的规则。
作用域是一组按标识符名称查找变量的规则。
如果在直接作用域中找不到变量,引擎将继续查询下一个外部包含作用域,直到找到或到达最外部(即全局)作用域。是一组规则,用于确定在何处以及如何查找变量(标识符)。该查找可能用于分配变量,该变量是LHS(左侧)参考,也可能用于检索其值,该值是RHS(右侧)参考。LHS引用源于赋值操作。与作用域相关的赋值可以使用=运算符进行,也可以通过将参数传递给(赋值给)函数参数进行。JavaScript引擎在执行代码之前首先编译代码,在这样做的过程中,它会拆分像vara=2这样的语句;分为两个单独的步骤:第一步。首先,var a在该范围中声明它。这是在代码执行之前开始执行的。第二。稍后,a=2查找变量(LHS引用),如果找到,则将其赋值。LHS和RHS引用查找都从当前执行的作用域开始,如果需要的话(也就是说,它们找不到它们在那里寻找的对象),它们会在嵌套作用域中一次一个作用域(层)查找标识符,直到它们到达全局(顶层)并停止,然后要么找到,要么不找到。未完成的RHS引用导致引发ReferenceError。未完成的LHS引用将导致该名称的自动隐式创建的全局(如果不在严格模式下),或ReferenceError(如果在严格模式中)。作用域由一系列“气泡”组成,每个气泡充当容器或桶,其中声明了标识符(变量、函数)。这些气泡整齐地嵌套在彼此内部,这种嵌套是在作者时定义的。
几乎只有两种类型的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);
这似乎与直觉相悖,但从命令式语言设计者的角度来看,这是有道理的。
我发现许多新接触JavaScript的人很难理解继承在默认情况下在语言中是可用的,而函数作用域是迄今为止唯一的作用域。我为去年年底我写的一个名为JSprety的美化者提供了一个扩展。功能为代码中的函数范围着色,并始终将颜色与该范围中声明的所有变量相关联。当在不同的范围中使用来自一个范围的颜色的变量时,可以直观地演示闭包。
尝试以下功能:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope
观看演示:
http://prettydiff.com/jspretty.xhtml?c=white&jsscope&s=http://prettydiff.com/lib/markup_beauty.js
在以下位置查看代码:
http://prettydiff.com/lib/jspretty.jshttps://github.com/austincheney/Pretty-Diff/blob/master/lib/jspretty.js
目前,该功能支持深度为16个嵌套函数,但目前不为全局变量着色。
我的理解是有三个范围:全球范围,全球可用;局部范围,无论块如何,整个功能都可用;和块范围,仅对使用它的块、语句或表达式可用。全局和局部作用域用关键字“var”表示,无论是在函数内还是在函数外,块作用域都用关键字“let”表示。
对于那些认为只有全局和局部范围的人,请解释为什么Mozilla会有一个完整的页面来描述JS中块范围的细微差别。
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let
试试这个奇怪的例子。在下面的示例中,如果a是一个初始化为0的数字,您将看到0,然后是1。除了a是一个对象,javascript将向f1传递a的指针,而不是它的副本。结果是两次都得到相同的警报。
var a = new Date();
function f1(b)
{
b.setDate(b.getDate()+1);
alert(b.getDate());
}
f1(a);
alert(a.getDate());
推荐文章
- Babel 6改变了它导出默认值的方式
- 如何配置历史记录?
- ES6模板文字可以在运行时被替换(或重用)吗?
- [Vue警告]:找不到元素
- 可以在setInterval()内部调用clearInterval()吗?
- AngularJS控制器的生命周期是什么?
- 无法读取未定义的属性“msie”- jQuery工具
- 我的蛋蛋怎么不见了?
- JavaScript中的排列?
- JavaScript中有睡眠/暂停/等待功能吗?
- 如何禁用文本选择使用jQuery?
- 如何停止事件冒泡复选框点击
- 如何在PHP中截断字符串最接近于一定数量的字符?
- 向对象数组添加属性
- 如何在Redux应用程序中动态加载代码分割的减速器?