在 JavaScript 中,代码块、函数或模块为变量创建
作用域
。例如
代码块为变量
创建作用域:
在
代码块作用域内可以访问
。但是在作用域之外,该变量不可访问。
好的,这是作用域的简短介绍。如果你想了解更多信息,建议阅读我的文章
用简单的词解释 JavaScript 作用域
。
以下是 5 种有趣的情况,其中 JavaScript 作用域的行为与你预期的不同。你可能会研究这些案例以提高对作用域的了解,或者只是为面试做准备。
1.for循环内的var变量
思考以下代码片段:
当你打印
和
变量时会发生什么?
答案
输出数字
,而
则抛出
。
变量是使用
语句声明的。你可能已经知道,
变量
仅受函数体作用域限制
而并非代码块。
相反,变量
使用
语句声明。因为
变量是块作用域的,所以
仅在
循环作用域内才可访问。
修复
把
声明从
改为
。现在变量
被封装在
循环体内。
2. 代码块中的函数声明
在以下代码段中:
调用
会怎样?
(代码段在 ES2015 环境中执行)
答案
因为代码块为函数声明创建了作用域,所以在 ES2015 环境中调用
会引发
。
有趣的是,在 ES2015 之前的环境中,在执行上述代码段时不会抛出错误。
你知道为什么吗?请在下面的评论中写下你的答案!
3. 你可以在哪里导入模块?
你可以在代码块中导入模块吗?
答案
上面的脚本将触发错误:
。
你只能在模块文件的最顶级作用域(也称为
模块作用域
)中导入模块。
修复
始终从模块作用域导入模块。另外一个好的做法是将
语句放在源文件的开头:
ES2015 的模块系统是静态的。通过分析 JavaScript 源代码而不是执行代码来确定模块的依赖关系。所以在代码块或函数中不能包含
语句,因为它们是在运行时执行的。
使用HTML,CSS,JavaScript开发Android应用程序 英文文字pdf版附源文件
如果你了解HTML,CSS和JavaScript,您已经拥有所需的工具开发Android应用程序。本动手本书展示了如何使用这些开源web标准设计和建造,可适应任何Android设备的应用程序 - 无需使用Java。您将学习如何创建一个在您选择的平台的Android友好的网络应用程序,然后转换与自由PhoneGap框架到一个原生的Android应用程序。了解为什么设备无关的移动应用是未来的潮流,并开始构建应用程序,提供更
下载
4. 函数参数作用域
思考以下函数:
调用
会发生什么?
答案
当调用函数
时,将会引发错误:
。
发生这种情况是因为函数的参数具有自己的作用域(与函数作用域分开)。参数
等效于
。
让我们仔细看看
。
首先,定义变量
。然后 JavaScript 尝试评估默认值表达式
,但此时绑定
已经创建但尚未初始化(不能访问外部作用域的变量
)。因此抛出一个错误,即在初始化之前访问了
。
修复
为了解决这个问题,你可以重命名变量
,也可以重命名功能参数
。
让我们选择重命名函数参数:
函数参数从
重命名为
。当调用
时,未指定参数,因此将参数
初始化为默认值
。为了评估
,访问外部作用域的变量
:
。
5. 函数声明与类声明
以下代码在代码块内定义了一个函数和一个类:
是否可以在块作用域之外访问
和
?
(考虑 ES2015 环境)
答案
和
声明都是块作用域的。所以在代码块作用域外调用函数
和构造函数
就会抛出
。
6. 总结
必须注意
变量,因为它们是函数作用域的,即使是在代码块中定义的。
由于 ES2015 模块系统是静态的,因此你必须在模块作用域内使用
语法(以及
)。
函数参数具有其作用域。设置默认参数值时,请确保默认表达式内的变量已经用值初始化。
在 ES2015 运行时环境中,函数和类声明是块作用域的。但是在 ES2015 之前的环境中,函数声明仅在函数作用域内。
希望这些陷阱能够帮你巩固作用域知识!
英文原文地址:https://dmitripavlutin.com/javascript-scope-gotchas/作者:Dmitri Pavlutin
更多编程相关知识,请访问:
编程入门
!!
ifmessageif (true) {
const message = 'Hello';
console.log(message); // 'Hello'
}
console.log(message); // throws ReferenceErrorifmessageconst colors = ['red', 'blue', 'white'];
for (let i = 0, var l = colors.length; i < l; i++) {
console.log(colors[i]); // 'red', 'blue', 'white'
}
console.log(l); // ???
console.log(i); // ???liconsole.log(l)3console.log(i)ReferenceErrorlvarvariletletiforlvar l = colors.lengthconst l = colors.lengthlfor// ES2015 env
{
function hello() {
return 'Hello!';
}
}
hello(); // ???hello()hello()ReferenceError: hello is not definedif (true) {
import { myFunc } from 'myModule'; // ???
myFunc();
}'import' and 'export' may only appear at the top-levelimportimport { myFunc } from 'myModule';
if (true) {
myFunc();
}importlet p = 1;
function myFunc(p = p + 1) {
return p;
}
myFunc(); // ???myFunc()myFunc()ReferenceError: Cannot access 'p' before initializationp = p + 1let p = p + 1p = p + 1pp + 1plet p = 1plet p = 1p = p + 1let p = 1;
function myFunc(q = p + 1) {
return q;
}
myFunc(); // => 2pqmyFunc()qp + 1p +1pp +1 = 1 + 1 = 2if (true) {
function greet() {
// function body
}
class Greeter {
// class body
}
}
greet(); // ???
new Greeter(); // ???greetGreeterfunctionclassgreet()new Greeter()ReferenceErrorvarimportexport