ECMAScript 6是JavaScript语言的下一代标准,2015年发布,目标是让JS可用来编写复杂大型应用程序,成为企业级开发语言
ECMAScript和JavaScript的关系是,前者是后者的规范,后者是前者的一种实现
ES6是个泛指,含义是5.1版本后的JS下一代标准,涵盖了ES2015、ES2016、ESES2017等,而ES2015等是该年份发布的正式版本
let
ES5只有全局作用域和函数作用域,没有块级作用域
ES6有块级作用域的概念,花括号 { } 内的区域为块级作用域,如if语句、for循环等,使用let后就需要考虑块级作用域的存在,声明的变量只在其中有效
var a = []
for (var i = 0; i < 10; i++) {
a[i] = function () {
console.log(i)
}
}
a[6]() //10
i是使用var声明的,是全局变量,i只有一个,循环结束i就变成10,所以无论是哪个函数调用i,得到的都是10
如果使用let来声名i,则当前的i只在本轮循环有效,也就是每次循环都是一个新的i
JS引擎会记住上一轮循环i的值,初始化本轮i时,就在上一轮循环的基础上进行计算
所以 a6 输出的结果是6,因为十个函数有十个i与之对应,而不是共用一个i
for循环设置循环变量的部分是父级作用域,其循环体是子级作用域
let不存在变量提升
console.log(x) //Uncaught ReferenceError: x is not defined
let x = 1
如果x由var声名,那么在预解析的时候声明会提升到当前作用域的顶部,但赋值不会被提升,所以输出结果是undefined,但用let声明的变量不会被提升,还没存在x就使用,所以报错
暂时性死区(temporal dead zone,TDZ)
使用let声明的变量,在本作用域内只有在声明后才能使用,否则报错
var x = 0
if(true){
x = 1
let x = 6 //Uncaught ReferenceError: x is not defined
}
即便x已被初始化,但在if作用域中,let x之前的都是变量x的"死区",只有在声明语句之后才能使用x
let x = x 亦会报错,因为这条声明语句没结束就去取x的值
不允许重复声明
let不允许在相同作用域重复声明同一变量
使用var声明同一变量,后者会覆盖前者,但不用let声明已声明的变量
var x = 1
let x = 2 //Uncaught SyntaxError: Identifier 'x' has already been declared
let x = 1
let x = 2 //Uncaught SyntaxError: Identifier 'x' has already been declared
#const const用于声明常量,一旦声明,常量的值就不能改变,即不能再赋值 正因为值不能改变所以一旦声明就必须初始化(赋值),否则报错 const和let一样其声明只在所在**块级作用域**内有效,声明的变量也不会提升,也存在暂时性死区,也不可重复声明 const实际不是保证变量的值不能改动,而是变量的**指向**不可变 内存(内存储器)是如何存储数据的?默默翻开曾经的《汇编语言》 > 存储器被划分成若干个存储单元,每个存储单元从0开始顺序编号。 电子计算机最小信息单位是bit,也就是一个二进制位,8位组成一个字节(Byte),而一个存储器有128个存储单元,每个存储单元可存128个字节。 微机存储器的容量以字节为最小单位。 存储单元的编号可看作存储单元在存储器中的**地址**,CPU要从内存中读数据,先要指定存储单元的地址,也就是要确定要读取哪个存储单元中的数据。
变量名是数据内存地址的别名,仅是为了给人看
这个别名代表某块内存,或者说指向某块内存,使用const后,这个指向不可变,对于简单数据类型(数字、字符串、布尔值),值就保存在变量指向的那个内存地址
但对于对象,变量保存的只是对象实例的一个引用
const arr = []
arr.push('Hello')
arr = ['Hi'] //将arr指向另一个数组对象,会报错
const声明的对象,只能保证变量永远指向这个对象实例,但实例的属性和方法是可变的
变量声明
ES5只有两种声明变量的方法,var和function
ES6在此基础上还添加了let、const、import和class
顶层对象属性
在浏览器中顶层对象是window,在Node中顶层对象是global对象
ES5中,全局变量其实就是顶层对象的属性
在ES6中,var和funcion声明的全局变量依旧是window的属性,但let、const、class声明的全局变量则不再是window的属性
var a = 1
// 如果在 Node 的 REPL 环境,可以写成 global.a
// 或者采用通用方法,写成 this.a
window.a // 1
let b = 1
window.b //undefined
#函数参数 ES为函数参数指定默认值,只能使用此方式 ``` function log(x,y){ y = y || 'Hi' } ``` ES6可在参数列表中为参数设置默认值 ``` functino log(x,y='Hi'){
}
<br>
##length属性
设置了参数默认值后,函数的length属性,返回的是没有指定默认值的参数个数,因为length属性原本含义就是函数要接收的参数个数,设置默认值实际上就不需要为此参数传值
<br>
##rest参数
rest参数用于获取函数的多余参数,这样就不需要使用arguments对象,并且rest是个真数组,可以调用数组的方法
用法:**...参数名**
function show(...values) {
for (let i = 0; i < values.length; i++) {
console.log(values[i])
}
}
show(1,2,3)
**rest参数不会被length属性记录**
(function(a) {}).length //1
(function(...a) {}).length //0
(function(a, ...b) {}).length //1
<br>
##作用域
一旦参数设置了默认值,**初始化时**参数列表会变成一个单独作用域
let x = 1
function f(y = x) {
let x = 2
console.log(y)
}
f() // 1
函数f调用时,参数y = x形成一个单独的作用域。这个作用域里面,变量x本身没有定义,所以会向上层作用域寻找x。函数调用时,函数体内部的局部变量x影响不到默认值变量x。
<br>
#箭头函数
ES6允许使用"箭头=>"定义函数
var f = v => v //第一个v为函数参数,第二个v为函数返回值
// 等同于
var f = function (v) {
return v
}
如果箭头函数不需要参数或需要多个参数,就使用一个圆括号代表参数部分
var f = () => 5
// 等同于
var f = function () { return 5 }
var sum = (n1, n2) => n1 + n2
// 等同于
var sum = function(n1, n2) {
return n1 + n2
}
如果函数体只有一条语句且没有返回值,右边直接写此语句
let f = () => console.log('Hi')
如果函数体多于一条语句就要使用大括号{}包裹起来说明这是函数体
let f = (x,y) => {
let sum = x + y
console.log(sum)
}
如果要返回一个对象,则需要使用括号包裹起来,如果不用括号包裹,引擎会认为这是函数体,但函数体里使用逗号冒号会报错
let f = (id,name) => {id:id,name:name} //Uncaught SyntaxError: Unexpected token :
let f = (id,name) => ({ id: id, name:name }) //不报错
<br>
##注意事项
1. 函数体内的this对象,是函数定义时所在的对象(切指向不可变),而不是使用时所在对象
2. 箭头函数不能使用new
3. arguments对象在箭头函数中不存在,可用rest参数代替
#参考资料
阮一峰老师的[《ES6标准入门》](http://es6.ruanyifeng.com/)