面试中关于 JavaScript 作用域的 5 个陷阱

栏目: IT技术 · 发布时间: 5年前

内容简介:作者:Dmitri Pavlutin

每日前端夜话 第324篇

翻译: 疯狂的技术宅

作者:Dmitri Pavlutin

来源:dmitripavlutin

正文共:1829  字

预计阅读时间:10 分钟

面试中关于 JavaScript 作用域的 5 个陷阱

在 JavaScript 中,代码块、函数或模块为变量创建作用域。例如 if 代码块为变量 message 创建作用域:

1if (true) {
2  const message = 'Hello';
3  console.log(message); // 'Hello'
4}
5console.log(message); // throws ReferenceError

if 代码块作用域内可以访问 message 。但是在作用域之外,该变量不可访问。以上是作用域的简短介绍。

以下是 5 种有趣的情况,其中 JavaScript 作用域的行为与你预期的不同。你可能会研究这些案例以提高对作用域的了解,或者只是为面试做准备。

1. for 循环内的 var 变量

思考以下代码片段:

1const colors = ['red', 'blue', 'white'];
2
3for (let i = 0, var l = colors.length; i < l; i++) {
4  console.log(colors[i]); // 'red', 'blue', 'white'
5}
6console.log(l); // ???
7console.log(i); // ???

当你打印 li 变量时会发生什么?

答案

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. 代码块中的函数声明

在以下代码段中:

1// ES2015 env
2{
3  function hello() {
4    return 'Hello!';
5  }
6}
7
8hello(); // ???

调用 hello() 会怎样? (代码段在 ES2015 环境中执行)

答案

因为代码块为函数声明创建了作用域,所以在 ES2015 环境中调用 hello() 会引发   ReferenceError: hello is not defined

有趣的是,在 ES2015 之前的环境中,在执行上述代码段时不会抛出错误。 你知道为什么吗?请在下面的评论中写下你的答案!

3. 你可以在哪里导入模块?

你可以在代码块中导入模块吗?

1if (true) {
2  import { myFunc } from 'myModule'; // ???
3  myFunc();
4}

答案

上面的脚本将触发错误: 'import' and 'export' may only appear at the top-level

你只能在模块文件的最顶级作用域(也称为模块作用域)中导入模块。

修复

始终从模块作用域导入模块。另外一个好的做法是将 import 语句放在源文件的开头:

1import { myFunc } from 'myModule';
2
3if (true) {
4  myFunc();
5}

ES2015 的模块系统是静态的。通过分析 JavaScript 源代码而不是执行代码来确定模块的依赖关系。所以在代码块或函数中不能包含 import 语句,因为它们是在运行时执行的。

4. 函数参数作用域

思考以下函数:

1let p = 1;
2
3function myFunc(p = p + 1) {
4  return p;
5}
6
7myFunc(); // ???

调用 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

让我们选择重命名函数参数:

1let p = 1;
2
3function myFunc(q = p + 1) {
4  return q;
5}
6
7myFunc(); // => 2

函数参数从 p 重命名为 q 。当调用 myFunc() 时,未指定参数,因此将参数 q 初始化为默认值 p + 1 。为了评估 p +1 ,访问外部作用域的变量 pp +1 = 1 + 1 = 2

5. 函数声明与类声明

以下代码在代码块内定义了一个函数和一个类:

 1if (true) {
 2  function greet() {
 3    // function body
 4  }
 5
 6  class Greeter {
 7    // class body
 8  }
 9}
10
11greet();       // ???
12new Greeter(); // ???

是否可以在块作用域之外访问 greetGreeter(考虑 ES2015 环境)

答案

functionclass 声明都是块作用域的。所以在代码块作用域外调用函数 greet() 和构造函数 new Greeter() 就会抛出 ReferenceError

6. 总结

必须注意 var 变量,因为它们是函数作用域的,即使是在代码块中定义的。

由于 ES2015 模块系统是静态的,因此你必须在模块作用域内使用 import 语法(以及 export )。

函数参数具有其作用域。设置默认参数值时,请确保默认表达式内的变量已经用值初始化。

在 ES2015 运行时环境中,函数和类声明是块作用域的。但是在 ES2015 之前的环境中,函数声明仅在函数作用域内。

希望这些陷阱能够帮你巩固作用域知识!

原文链接

https://dmitripavlutin.com/javascript-scope-gotchas/

2020年

京程一灯课程体系上新,这是我们第一次将全部课程列表对外开放。

愿你有个好前程,愿你月薪30K。我们是认真的 ! 面试中关于 JavaScript 作用域的 5 个陷阱

点击文末  阅读全文   查看细节。

面试中关于 JavaScript 作用域的 5 个陷阱

长按二维码,加大鹏老师微信好友

拉你加入前端技术交流群

唠一唠怎样才能拿高薪

面试中关于 JavaScript 作用域的 5 个陷阱

往期精彩回顾

面向开发人员的十大 NodeJS 框架

JavaScript 类完整指南

讲给前端的正则表达式

WebAssembly 正式成为 Web 的第四种语言

2020 年 Node.js 将会有哪些新功能

2020 年 Web 开发展望

从 JavaScript、ES6、ES7 到 ES10,你学到哪儿了?

15个 Vue.js 高级面试题

面试中关于 JavaScript 作用域的 5 个陷阱


以上所述就是小编给大家介绍的《面试中关于 JavaScript 作用域的 5 个陷阱》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First HTML and CSS

Head First HTML and CSS

Elisabeth Robson、Eric Freeman / O'Reilly Media / 2012-9-8 / USD 39.99

Tired of reading HTML books that only make sense after you're an expert? Then it's about time you picked up Head First HTML and really learned HTML. You want to learn HTML so you can finally create th......一起来看看 《Head First HTML and CSS》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

MD5 加密
MD5 加密

MD5 加密工具

html转js在线工具
html转js在线工具

html转js在线工具