《ECMAScript 6入门》笔记2
来源:互联网 发布:北航研究生院软件学院 编辑:程序博客网 时间:2024/06/01 10:31
块级作用域
ES5只有全局作用域和函数作用域,没有块级作用域,这带来很多不合理的场景。
第一种场景,内层变量可能会覆盖外层变量。
var tmp = new Date();function f() { console.log(tmp); if (false) { var tmp = 'hello world'; }}f(); // undefined
上面代码的原意是,if代码块的外部使用外层的tmp变量,内部使用内层的tmp变量。但是,函数f执行后,输出结果为undefined,原因在于变量提升,导致内层的tmp变量覆盖了外层的tmp变量。
第二种场景,用来计数的循环变量泄露为全局变量。
var s = 'hello';for (var i = 0; i < s.length; i++) { console.log(s[i]);}console.log(i); // 5
上面代码中,变量i只用来控制循环,但是循环结束后,它并没有消失,泄露成了全局变量。
ES6的块级作用域
let实际上为JavaScript新增了块级作用域。
function f1() { let n = 5; if (true) { let n = 10; } console.log(n); // 5}
上面的函数有两个代码块,都声明了变量n,运行后输出5。这表示外层代码块不受内层代码块的影响。如果两次都使用var定义变量n,最后输出的值才是10。
ES6允许块级作用域的任意嵌套。
{{{{{let insane = 'Hello World'}}}}};
上面代码使用了一个五层的块级作用域。外层作用域无法读取内层作用域的变量。
{{{{ {let insane = 'Hello World'} console.log(insane); // 报错}}}};
内层作用域可以定义外层作用域的同名变量。
{{{{ let insane = 'Hello World'; {let insane = 'Hello World'}}}}};
块级作用域的出现,实际上使得获得广泛应用的立即执行函数表达式(IIFE)不再必要了。
// IIFE 写法(function () { var tmp = ...; ...}());// 块级作用域写法{ let tmp = ...; ...}
块级作用域与函数声明
ES5规定,函数只能在顶层作用域和函数作用域之中声明,不能在块级作用域声明。
// 情况一if (true) { function f() {}}// 情况二try { function f() {}} catch(e) { // ...}
上面两种函数声明,根据ES5的规定都是非法的。
但是,浏览器没有遵守这个规定,为了兼容以前的旧代码,还是支持在块级作用域之中声明函数,因此上面两种情况实际都能运行,不会报错。
ES6引入了块级作用域,明确允许在块级作用域中声明函数。ES6规定,块级作用域之中,函数声明语句的行为类似于let,在块级作用域之外不可引用。
function f() { console.log('I am outside!'); }(function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f();}());
上面代码在ES5中运行,会得到“I am inside!”,因为在if内声明的函数f会被提升到函数头部,实际运行的代码如下。
// ES5 环境function f() { console.log('I am outside!'); }(function () { function f() { console.log('I am inside!'); } if (false) { } f();}());
ES6就完全不一样了,理论上会得到“I am outside!”。因为块级作用域内声明的函数类似于let,对作用域之外没有影响。但是,如果你真的在ES6浏览器中运行一下上面的代码,是会报错的,这是为什么呢?
原来,如果改变了块级作用域内声明的函数的处理规则,显然会对老代码产生很大的影响。为了减轻因此产生的不兼容问题,ES6在附录B里面规定,浏览器的实现可以不遵守上面的规定,有自己的行为方式。
-允许在块级作用域内声明函数。
-函数声明类似于var,即会提升到全局作用域或函数作用域的头部。
-同时,函数声明还会提升到所在的块级作用域的头部。
注意,上面三条规则只对ES6的浏览器实现有效,其他环境的实现不用遵守,还是将块级作用域的函数声明当作let处理。
根据这三条规则,在浏览器的ES6环境中,块级作用域内声明的函数,行为类似于var声明的变量。
// 浏览器的 ES6 环境function f() { console.log('I am outside!'); }(function () { if (false) { // 重复声明一次函数f function f() { console.log('I am inside!'); } } f();}());// Uncaught TypeError: f is not a function
上面的代码在符合ES6的浏览器中,都会报错,因为实际运行的是下面的代码。
// 浏览器的 ES6 环境function f() { console.log('I am outside!'); }(function () { var f = undefined; if (false) { function f() { console.log('I am inside!'); } } f();}());// Uncaught TypeError: f is not a function
考虑到环境导致的行为差异太大,应该避免在块级作用域内声明函数。如果确实需要,也应该写成函数表达式,而不是函数声明语句。
// 函数声明语句{ let a = 'secret'; function f() { return a; }}// 函数表达式{ let a = 'secret'; let f = function () { return a; };}
ES6的块级作用域允许声明函数的规则,只在使用大括号的情况下成立,如果没有使用大括号,就会报错。
// 不报错'use strict';if (true) { function f() {}}// 报错'use strict';if (true) function f() {}
do表达式
本质上,块级作用域是一个语句,将多个操作封装在一起,没有返回值。
{ let t = f(); t = t * t + 1;}
上面代码中,块级作用域将两个语句封装在一起。但是,在块级作用域以外,没有办法得到t的值,因为块级作用域不返回值,除非t是全局变量。
现在有一个提案,使得块级作用域可以变为表达式,也就是说可以返回值,办法就是在块级作用域之前加上do,使它变为do表达式。
let x = do { let t = f(); t * t + 1;};
上面代码中,变量x会得到整个块级作用域的返回值。
阅读全文
0 0
- 《ECMAScript 6入门》笔记2
- 《ECMAScript 6入门》笔记6
- ECMAScript 6 入门学习笔记
- ECMAScript 6入门 学习笔记
- 《ECMAScript 6入门》笔记1
- 《ECMAScript 6入门》笔记3
- 《ECMAScript 6入门》笔记4
- 《ECMAScript 6入门》笔记5
- ECMAScript 6 入门 个人笔记(一)
- ECMAScript 6 入门 个人笔记(二)
- ECMAScript 6 入门笔记(六)Class
- ES6-Symbol(ECMAScript 6 入门笔记)
- ECMAScript 6入门
- ECMAScript 6 入门
- ECMAScript 6入门
- ECMAScript 6入门
- ECMAScript 6 入门简介
- ECMAScript 6 入门
- 输入:包含条形码图形和条形码文本的图片 输出:条形码的文本
- cmake编译ITK报错:The C compiler is not able to compile a simple test program
- linux中/etc/init.d的作用
- POJ
- (3)HttpServletRequest
- 《ECMAScript 6入门》笔记2
- JAVABean与xml互转
- 算法学习笔记--5.merge sort & divide-and-conquer
- nohup和&的区别
- 13个人围成一圈,从第一个人开始顺序报号1、2、3,凡是报到3的人退出圈子。最后留的人是几号?
- poj2455 二分最大流裸题
- js把数组拼接字符串
- LeetCode 263. Ugly Number
- 注解(Annotation)自定义注解入门