tnblog
首页
视频
资源
登录

es6块级作用域

3931人阅读 2022/1/23 21:58 总访问:295344 评论:0 收藏:0 手机
分类: 前端

为什么需要块级作用域?

ES5 只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。


第一种场景,内层变量可能会覆盖外层变量。

  1. var tmp = new Date();
  2. function f({
  3.   console.log(tmp);
  4.   if (false) {
  5.     var tmp = 'hello world';
  6.   }
  7. }
  8. f(); // undefined

上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。


第二种场景,用来计数的循环变量泄露为全局变量。

  1. var s = 'hello';
  2. for (var i = 0; i < s.length; i++) {
  3.   console.log(s[i]);
  4. }
  5. console.log(i); // 5

上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。


ES6 的块级作用域

let实际上为 JavaScript 新增了块级作用域。

  1. function f1({
  2.   let n = 5;
  3.   if (true) {
  4.     let n = 10;
  5.   }
  6.   console.log(n); // 5
  7. }

上面的函数有两个代码块,都声明了变量n,运行后输出 5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是 10。


ES6 允许块级作用域的任意嵌套。

  1. {{{{
  2.   {let insane = 'Hello World'}
  3.   console.log(insane); // 报错
  4. }}}};

上面代码使用了一个五层的块级作用域,每一层都是一个单独的作用域。第四层作用域无法读取第五层作用域的内部变量。


内层作用域可以定义外层作用域的同名变量。

  1. {{{{
  2.   let insane = 'Hello World';
  3.   {let insane = 'Hello World'}
  4. }}}};

块级作用域的出现,实际上使得获得广泛应用的匿名立即执行函数表达式(匿名 IIFE)不再必要了。

  1. // IIFE 写法
  2. (function ({
  3.   var tmp = ...;
  4.   ...
  5. }());
  6. // 块级作用域写法
  7. {
  8.   let tmp = ...;
  9.   ...
  10. }

块级作用域与函数声明

函数能不能在块级作用域之中声明?这是一个相当令人混淆的问题。


ES5 规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。

  1. // 情况一
  2. if (true) {
  3.   function f({}
  4. }
  5. // 情况二
  6. try {
  7.   function f({}
  8. catch(e) {
  9.   // ...
  10. }

上面两种函数声明,根据 ES5 的规定都是非法的。


但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。


ES6 引入了块级作用域,明确允许在块级作用域之中声明函数。ES6 规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。

  1. function f(console.log('I am outside!'); }
  2. (function ({
  3.   if (false) {
  4.     // 重复声明一次函数f
  5.     function f(console.log('I am inside!'); }
  6.   }
  7.   f();
  8. }());

上面代码在 ES5 中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。

  1. // ES5 环境
  2. function f(console.log('I am outside!'); }
  3. (function ({
  4.   function f(console.log('I am inside!'); }
  5.   if (false) {
  6.   }
  7.   f();
  8. }());

ES6 就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于

  1. let
,对作用域之外没有影响。但是,如果你真的在 ES6 浏览器中运行一下上面的代码,是会报错的,这是为什么呢?

  1. // 浏览器的 ES6 环境
  2. function f(console.log('I am outside!'); }
  3. (function ({
  4.   if (false) {
  5.     // 重复声明一次函数f
  6.     function f(console.log('I am inside!'); }
  7.   }
  8.   f();
  9. }());
  10. // Uncaught TypeError: f is not a function


转载:https://www.bookstack.cn/read/es6-3rd/spilt.2.docs-let.md

评价

es6 新增特性 解构赋值

ES6 中数据解构赋值在 ES6 中通过使用解构赋值代码可以方便时使我们快速的上手代码的实现方式 · 数组的解构:有一下的代...

es6 数组的新增方法

数组的扩展 类数组 / 伪数组Array.from()Array.of()copyWithin()fill()includes() 类数组 / 伪数组: 什么是类数组或...

js与es6中基本语法异同比较

前端刷副本日记chapter1!!js中和ES6中声明变量的区别://js中value在声明之前可以使用value=&quot;黄大仙&quot;;varvalue...

es6中一些常用基本函数的使用

前端刷副本日记chapter2!!ES6中一些常用基本函数的使用//按条件筛选数组中指定的值//varresult=[];//varsports=[&quot;篮...

es6新增的字符串方法

String.fromCodePoint()String.raw()实例方法:codePointAt()实例方法:normalize()实例方法:includes(), startsWith(), e...

es6 Reflect

概述Reflect对象与Proxy对象一样,也是 ES6 为了操作对象而提供的新 API。Reflect对象的设计目的有这样几个。(1) 将Objec...

es6 Module 的语法介绍

历史上,JavaScript 一直没有模块(module)体系,无法将一个大程序拆分成互相依赖的小文件,再用简单的方法拼装起来。其他...

js,es6在集合中排除某些数据。js判断集合中是否存在某个值

js判断集合中是否存在某个值利用indexOf就可以了,在集合中可以使用indexOf找某个值,如果找不到就返回-1 const noDataLes...
旧年素颜,君记否
排名
15
文章
52
粉丝
1
评论
2
ICP备案 :渝ICP备18016597号-1
网站信息:2018-2025TNBLOG.NET
技术交流:群号656732739
联系我们:contact@tnblog.net
公网安备:50010702506256
欢迎加群交流技术