javascript中变量的范围是什么?它们的内部是否与函数外部相同?或者甚至重要吗?此外,如果全局定义变量,那么它们存储在哪里?
javascript中变量的范围是什么?它们的内部是否与函数外部相同?或者甚至重要吗?此外,如果全局定义变量,那么它们存储在哪里?
我认为我能做的最好的事情就是给你一些学习的例子。 Javascript程序员实际上根据他们理解范围的程度进行排名。 它有时可能非常违反直觉。
全局范围的变量
// global scope
var a = 1;
function one() {
alert(a); // alerts '1'
}
本地范围
// global scope
var a = 1;
function two(a) {
// local scope
alert(a); // alerts the given argument, not the global value of '1'
}
// local scope again
function three() {
var a = 3;
alert(a); // alerts '3'
}
中间: 没有JavaScript中的块范围 (ES5; ES6介绍 let
)
一个。
var a = 1;
function four() {
if (true) {
var a = 4;
}
alert(a); // alerts '4', not the global value of '1'
}
湾
var a = 1;
function one() {
if (true) {
let a = 4;
}
alert(a); // alerts '1' because the 'let' keyword uses block scoping
}
中间: 对象属性
var a = 1;
function Five() {
this.a = 5;
}
alert(new Five().a); // alerts '5'
高级: 关闭
var a = 1;
var six = (function() {
var a = 6;
return function() {
// JavaScript "closure" means I have access to 'a' in here,
// because it is defined in the function in which I was defined.
alert(a); // alerts '6'
};
})();
高级: 基于原型的范围解析
var a = 1;
function seven() {
this.a = 7;
}
// [object].prototype.property loses to
// [object].property in the lookup chain. For example...
// Won't get reached, because 'a' is set in the constructor above.
seven.prototype.a = -1;
// Will get reached, even though 'b' is NOT set in the constructor.
seven.prototype.b = 8;
alert(new seven().a); // alerts '7'
alert(new seven().b); // alerts '8'
环球+本地: 一个额外复杂的案例
var x = 5;
(function () {
console.log(x);
var x = 10;
console.log(x);
})();
这将打印出来 undefined
和 10
而不是 5
和 10
因为JavaScript总是将变量声明(而不是初始化)移动到作用域的顶部,使代码等效于:
var x = 5;
(function () {
var x;
console.log(x);
x = 10;
console.log(x);
})();
Catch子句范围的变量
var e = 5;
console.log(e);
try {
throw 6;
} catch (e) {
console.log(e);
}
console.log(e);
这将打印出来 5
, 6
, 5
。在catch子句中 e
阴影全局变量和局部变量。但是这个特殊范围仅适用于捕获的变量。如果你写 var f;
在catch子句中,它与在try-catch块之前或之后定义它完全相同。
Javascript使用范围链来为给定函数建立范围。通常有一个全局范围,每个定义的函数都有自己的嵌套范围。在另一个函数中定义的任何函数都有一个链接到外部函数的局部作用域。始终是源中定义范围的位置。
范围链中的元素基本上是一个带有指向其父范围的指针的Map。
解析变量时,javascript从最里面的范围开始并向外搜索。
全球声明的变量具有全局范围。在函数内声明的变量作用于该函数,并且阴影全局变量具有相同名称。
(我确信真正的JavaScript程序员可以在其他答案中指出很多细微之处。特别是我遇到过 这一页 究竟是什么 this
意思是在任何时候。希望 这个更多的介绍性链接 足以让你开始。)
传统上,JavaScript实际上只有两种类型的范围:
我不会详细说明这一点,因为已经有许多其他答案解释了这一点。
该 最新的JavaScript规范 现在还允许第三个范围:
传统上,您可以像这样创建变量:
var myVariable = "Some text";
块范围变量的创建方式如下:
let myVariable = "Some text";
要了解功能范围和块范围之间的区别,请考虑以下代码:
// i IS NOT known here
// j IS NOT known here
// k IS known here, but undefined
// l IS NOT known here
function loop(arr) {
// i IS known here, but undefined
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( var i = 0; i < arr.length; i++ ) {
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
for( let j = 0; j < arr.length; j++ ) {
// i IS known here, and has a value
// j IS known here, and has a value
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
};
// i IS known here, and has a value
// j IS NOT known here
// k IS known here, but has a value only the second time loop is called
// l IS NOT known here
}
loop([1,2,3,4]);
for( var k = 0; k < arr.length; k++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
};
for( let l = 0; l < arr.length; l++ ) {
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS known here, and has a value
};
loop([1,2,3,4]);
// i IS NOT known here
// j IS NOT known here
// k IS known here, and has a value
// l IS NOT known here
在这里,我们可以看到我们的变量 j
只在第一个for循环中知道,但不在之前和之后。然而,我们的变量 i
在整个功能中都是众所周知的。
另外,请考虑块范围变量在声明之前是未知的,因为它们没有被提升。您也不允许在同一个块中重新声明相同的块范围变量。这使得块范围变量比全局或功能范围变量更不容易出错,这些变量被提升并且在多个声明的情况下不会产生任何错误。
今天是否安全使用取决于您的环境:
如果您正在编写服务器端JavaScript代码(Node.js的),你可以安全地使用 let
声明。
如果您正在编写客户端JavaScript代码并使用转换器(如 Traceur),你可以安全地使用 let
声明,但是你的代码在性能方面可能不是最优的。
如果您正在编写客户端JavaScript代码而不使用转换器,则需要考虑浏览器支持。
今天,2016年2月23日,这些是一些不支持的浏览器 let
或只有部分支持:
有关哪些浏览器支持的最新概述 let
在您阅读此答案时的陈述,请参阅 这个 Can I Use
页。
(*)全局和功能范围的变量可以在声明之前初始化和使用,因为JavaScript变量是 悬挂。 这意味着声明始终位于范围的顶部。
(**)未提升块范围变量
这是一个例子:
<script>
var globalVariable = 7; //==window.globalVariable
function aGlobal( param ) { //==window.aGlobal();
//param is only accessible in this function
var scopedToFunction = {
//can't be accessed outside of this function
nested : 3 //accessible by: scopedToFunction.nested
};
anotherGlobal = {
//global because there's no `var`
};
}
</script>
您需要研究闭包,以及如何使用它们 私人会员。
根据我的理解,关键是Javascript具有功能级别范围与更常见的C块范围。
在“Javascript 1.7”(Mozilla对Javascript的扩展)中,还可以使用声明块范围变量 let
声明:
var a = 4;
let (a = 3) {
alert(a); // 3
}
alert(a); // 4