正在读阮一峰的《ECMAScript 6 入门》,本系列博客都是读书笔记。
ES6 PlayGround
在介绍具体的内容之前,想给大家介绍一个好玩的playgroud,尤其合适边看书,边敲代码的同学们。Traceur%3B%0A%7D%0A%0Aconsole.log(b)%3B%0A%0A)
这个工具会在你敲完每行代码之后帮你执行检查是否有错误,然后翻译成es5并执行,然后再配合JS控制台,就是很棒的playground了。
使用:
- 打开网页
- command + option + J打开javascript控制台
- 在最左边的框里面输入代码,
效果如下:
左边:写代码的地方 中间:翻译之后的js代码,右边:控制台
let命令
作用域和var不同
ES6中建议全部使用let来生命变量,let和var的作用用法类似,但是let声明的变量,作用域是在其所在的代码块。
|
|
看起来很简单吧,那我们来看下道题目吧
|
|
和
|
|
答案是:
a(7)() : 10
b(7)() : 7
你猜对了吗?0_0
我第一次看其实是答错了的,然后我把a[7] 和 b[7]打印了出来
|
|
我理解是因为let和var的缘故,所以a[7]里面的i实际是就是一个static的变量,在i++之后变成了10,而b[7]里面的i就是7
变量提升
let 不会出现变量提升的现象。
首先,我们把let抛一边,看下什么是变量提升。先看个代码,猜猜它的结果:
|
|
它的输出结果是多少?
答案: 5,很简单吧,好,我们再看一个相似的函数:
|
|
结果是多少呢?
答案是:100
为什么会这样呢?
作用域
作为一个一直在使用OC的程序员,想要弄懂JS的作用域,开始会很别扭,因为两者的作用域是基于不同的标准或者模式。在介绍之前,我们先看下两个C和JS的小例子:
C:
|
|
JS:
|
|
结果不一样了,为什么呢? 刚才提到C和Js的作用域的模式不一样,C是基于块级的作用域(block-level scope),每个大括号括起来的都可以理解为一个小的作用域,如果变量在小的作用域里声明,那么在小的作用域中是会忽略外部同名的变量。
而在JS中,则是基于函数的作用域,即每个函数都有自己的作用域(function-level scope),所以上述的列子最后的结果就不一致了,在JS的列子中,a的值其实被覆盖。
C,C++,Java都是块级作用域,那么JS中,如何实现类似的效果呢?答案是使用闭包
|
|
在f()这个函数中,会再次定义一个只能在f()中起作用的a,从而实现了类似块级作用域的效果。
变量提升
讲完了作用域,我们来看下什么是变量提升,还是先来个列子:
|
|
这三行代码在解释器中会变成:
|
|
所有var声明的变量的声明语句,都会被解释器给放到变量所在作用域的顶部。注意,只是把生命语句放到最上面,但是不会把赋值等位置提升,这就是所谓的变量提升。
函数也会有变量提升的现象,但是会根据声明方式的不同,有着不同的结果。创建函数的方法有两个: function f(){} 和 var f = function(){},他们会有什么不同呢? 我们看下列子:
|
|
这段代码在解释器中:
|
|
函数的变量提升,如果是fucntion f()
的形式,怎会整个函数都提升到顶部,如果是var f() = function(){}
的形式,则只会提升var f()
到顶部。
如此,本节开头的两个例子就不难理解了。
|
|
在解释器中是:
|
|
|
|
在解释器中是:
|
|
而let 关键字是不具备变量提升的,所以它声明的变量,其实就是块级作用域。
最后一个例子:
|
|
而在ES5中不会报错的先使用再声明的模式,在ES6中用let的话,就会报错了。比如:
|
|
所以建议如下:
- ES6中永远使用let
- 所有变量的声明,都写在函数的顶部
这是我在看变量提升的时候,找到一篇质量很棒的blog,本篇的结构和内容也参考了很多Javascript作用域和变量提升
const
const的用法和let基本一致,不可重复定义,不会变量提升,作用域是块作用域。
要注意的是,const修饰一个对象的话,只会限定这个对象的地址不变,不会限定它的值不变,如:
|
|
想要值不变的话,可以使用Object.freeze()
方法:
|
|
如果想将对象全部冻结,要将里面的每个value都冻结:
|
|