JS作用域的陷阱有哪些-创新互联
这篇文章给大家分享的是有关JS作用域的陷阱有哪些的内容。小编觉得挺实用的,因此分享给大家做个参考,一起跟随小编过来看看吧。
让客户满意是我们工作的目标,不断超越客户的期望值来自于我们对这个行业的热爱。我们立志把好的技术通过有效、简单的方式提供给客户,将通过不懈努力成为客户在信息化领域值得信任、有价值的长期合作伙伴,公司提供的服务项目有:主机域名、虚拟空间、营销软件、网站建设、东海网站维护、网站推广。在 JavaScript 中,代码块、函数或模块为变量创建作用域。例如if
代码块为变量message
创建作用域:
if (true) { const message = 'Hello'; console.log(message); // 'Hello' } console.log(message); // throws ReferenceError
在if
代码块作用域内可以访问message
。但是在作用域之外,该变量不可访问。
好的,这是作用域的简短介绍。如果你想了解更多信息,建议阅读我的文章用简单的词解释 JavaScript 作用域。
以下是 5 种有趣的情况,其中 JavaScript 作用域的行为与你预期的不同。你可能会研究这些案例以提高对作用域的了解,或者只是为面试做准备。
1.for 循环内的var 变量
思考以下代码片段:
const 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); // ???
当你打印l
和i
变量时会发生什么?
答案
console.log(l)
输出数字3
,而console.log(i)
则抛出ReferenceError
。
l
变量是使用var
语句声明的。你可能已经知道,var
变量仅受函数体作用域限制而并非代码块。
相反,变量i
使用let
语句声明。因为let
变量是块作用域的,所以i
仅在for
循环作用域内才可访问。
修复
把l
声明从var l = colors.length
改为const l = colors.length
。现在变量l
被封装在for
循环体内。
2. 代码块中的函数声明
在以下代码段中:
// ES2015 env { function hello() { return 'Hello!'; } } hello(); // ???
调用hello()
会怎样?(代码段在 ES2015 环境中执行)
答案
因为代码块为函数声明创建了作用域,所以在 ES2015 环境中调用hello()
会引发 ReferenceError: hello is not defined
。
有趣的是,在 ES2015 之前的环境中,在执行上述代码段时不会抛出错误。你知道为什么吗?请在下面的评论中写下你的答案!
3. 你可以在哪里导入模块?
你可以在代码块中导入模块吗?
if (true) { import { myFunc } from 'myModule'; // ??? myFunc(); }
答案
上面的脚本将触发错误:'import' and 'export' may only appear at the top-level
。
你只能在模块文件的最顶级作用域(也称为模块作用域)中导入模块。
修复
始终从模块作用域导入模块。另外一个好的做法是将import
语句放在源文件的开头:
import { myFunc } from 'myModule'; if (true) { myFunc(); }
ES2015 的模块系统是静态的。通过分析 JavaScript 源代码而不是执行代码来确定模块的依赖关系。所以在代码块或函数中不能包含import
语句,因为它们是在运行时执行的。
4. 函数参数作用域
思考以下函数:
let p = 1; function myFunc(p = p + 1) { return p; } myFunc(); // ???
调用myFunc()
会发生什么?
答案
当调用函数myFunc()
时,将会引发错误:ReferenceError: Cannot access 'p' before initialization
。
发生这种情况是因为函数的参数具有自己的作用域(与函数作用域分开)。参数p = p + 1
等效于let p = p + 1
。
让我们仔细看看p = p + 1
。
首先,定义变量p
。然后 JavaScript 尝试评估默认值表达式p + 1
,但此时绑定 p
已经创建但尚未初始化(不能访问外部作用域的变量 let p = 1
)。因此抛出一个错误,即在初始化之前访问了p
。
修复
为了解决这个问题,你可以重命名变量let p = 1
,也可以重命名功能参数p = p + 1
。
让我们选择重命名函数参数:
let p = 1; function myFunc(q = p + 1) { return q; } myFunc(); // => 2
函数参数从p
重命名为q
。当调用myFunc()
时,未指定参数,因此将参数q
初始化为默认值p + 1
。为了评估p +1
,访问外部作用域的变量p
:p +1 = 1 + 1 = 2
。
5. 函数声明与类声明
以下代码在代码块内定义了一个函数和一个类:
if (true) { function greet() { // function body } class Greeter { // class body } } greet(); // ??? new Greeter(); // ???
是否可以在块作用域之外访问greet
和Greeter
?(考虑 ES2015 环境)
答案
function
和class
声明都是块作用域的。所以在代码块作用域外调用函数greet()
和构造函数new Greeter()
就会抛出ReferenceError
。
6. 总结
必须注意var
变量,因为它们是函数作用域的,即使是在代码块中定义的。
由于 ES2015 模块系统是静态的,因此你必须在模块作用域内使用import
语法(以及export
)。
函数参数具有其作用域。设置默认参数值时,请确保默认表达式内的变量已经用值初始化。
在 ES2015 运行时环境中,函数和类声明是块作用域的。但是在 ES2015 之前的环境中,函数声明仅在函数作用域内。
感谢各位的阅读!关于“JS作用域的陷阱有哪些”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,让大家可以学到更多知识,如果觉得文章不错,可以把它分享出去让更多的人看到吧!
分享标题:JS作用域的陷阱有哪些-创新互联
当前路径:http://myzitong.com/article/ddiees.html