es6 学习笔记 参考 阮一峰的ES6教程
let 和 const
es6 中新增了 let 和 const 命令,用来声明变量。let 声明的变量,只在 let 命令所在的代码块内有效。
let 必须先声明,后使用。
ES6 明确规定,如果区块中存在let和const命令,这个区块对这些命令声明的变量,从一开始就形成了封闭作用域。凡是在声明之前就使用这些变量,就会报错。被称作“暂时性死区” (temporal dead zone,简称 TDZ)
const 用来声明一个只读的常量,声明后,常量的值就不能改变。
变量的结构赋值
ES6 允许按照一定模式,从数组和对象中提取值,对变量进行赋值,这被称为解构(Destructuring)。
1 | let [a, b, c] = [1, 2, 3]; |
这种写法也可以称作“模式匹配”,只要等号两边的模式相同,左边的变量就会被赋予对应的值。
如果解析不成功,值为 undefined
1 | let [foo] = []; |
不完全解构,即等号左边的模式,只匹配一部分等号右边的数组,这种情况下依旧可以解构成功。
1 | let [x, y] = [1, 2, 3]; |
如果右边不是数组(或者说不是可遍历的结构),会报错。
… op 为剩余运算符
1 | let [a, ...b] = [1, 2, 3]; |
字符串的拓展
模板字符串
1 | $('#result').append(` |
模板字符串(template string)是增强版的字符串,用反引号(`)标识。它可以当作普通字符串使用,也可以用来定义多行字符串,或者在字符串中嵌入变量。
函数的拓展
可以给函数加默认值
1 | function log(x, y = 'World') { |
参数的默认值可以和结构赋值结合使用。
作用域
一旦设置参数的默认值,函数进行声明结构初始化时,参数会形成一个单独的作用域,等初始化完成后,作用域就会消失。
1 | var x = 1; |
利用参数默认值,可以指定一个参数不得省略,如果省略就抛出一个错误。
1 | function throwIfMissing() { |
rest 参数
es6 中引入了 rest 参数 (形式为 …变量名),类似 java 中的可变参数。用于获取函数多余的参数,这样就不需要使用 arguments 对象了。
rest 参数实际上就是一个数组。
要注意,rest 参数后不能有其他参数,所以 rest 参数必须是最后一个参数。
函数的 length 属性里,不包括 rest 参数。
严格模式
ES2016 做了一点修改,规定只要函数参数使用了默认值、解构赋值、或者扩展运算符,那么函数内部就不能显式设定为严格模式,否则会报错。
name 属性
函数的 name 属性,返回该函数的
ES6 对这个属性的行为做出了一些修改。如果将一个匿名函数赋值给一个变量,ES5 的name属性,会返回空字符串,而 ES6 的name属性会返回实际的函数名。
如果将一个具有名字的函数赋值给一个变量,es5和es6都会返回这个函数原有的名字
1 | const bar = function baz() {}; |
箭头函数
1 | // 语法规则 |
如果箭头函数不需要参数或者需要多个参数,要用一个圆括号代码参数列表。
如果箭头函数代码块多于一条语句,要用 {} 将它们括起来。由于大括号被解释为代码块,所以如果箭头函数直接返回一个对象,必须在对象外面加上括号,否则会报错。
1 | let getTempItem = id => ({ id: id, name: "Temp" }); |
使用箭头函数时,要注意
- 函数体内的 this 对象,就是定义所在的对象,而不是使用所在的对象。
- 不可以当作构造函数,也就是说,不能使用 new 命令。
- 不可以使用arguments对象,该对象在函数体内不存在。如果要用,可以用 rest 参数代替。
- 不可以使用yield命令,因此箭头函数不能用作 Generator 函数。
上面四点中,第一点尤其值得注意。this对象的指向是可变的,但是在箭头函数中,它是固定的。
this指向的固定化,并不是因为箭头函数内部有绑定this的机制,实际原因是箭头函数根本没有自己的this,导致内部的this就是外层代码块的this。正是因为它没有this,所以也就不能用作构造函数。
除了 this, 以下三个变量在箭头函数中也是不存在的,指向外层函数的对应变量:arguments, super, new.target。
箭头函数不适用常见
第一个场合是定义对象的方法,且该方法内部包括 this。
因为对象不构成单独的作用域,所以 this 指向会指向全局,在某些情况下导致错误发生。
第二个场合是需要动态this的时候,也不应使用箭头函数。
对象的拓展
属性简洁写法
ES6 允许直接写入变量和函数,作为对象的属性和方法
1 | function f(x, y) { |
方法简写
1 | const o = { |
注意,简洁写法的属性名总是字符串
1 | const obj = { |
属性名表达式
JavaScript 定义对象的属性,有两种方法。
1 | // 方法一 |
如果使用字面量方式定义对象(直接使用大括号),在ES5中只能使用方法一定义属性。
ES6 中允许在字面量方式定义对象时,采用方法二作为对象的属性名。
但要注意:属性名表达式与简洁表示法,不能同时使用,会报错。
1 | // 报错 |
要注意:如果属性名表达式是一个对象,会自动将对象转换为字符串 “[object Object]”。
1 | const keyA = {a: 1}; |
可枚举性
对象的每一个属性都有一个描述对象 (Descriptor),用来控制该属性的行为。
Object.getOwnPropertyDescriptor方法可以获取该属性的描述对象。
1 | let obj = { foo: 123 }; |
描述对象的 enumerable 属性,称作 “可枚举性”,如果该属性为 false ,就表示某些操作会忽略当前属性。
目前,有四个操作会忽略 enumerable 为 false 的属性。
- for…in循环:只遍历对象自身的和继承的可枚举的属性。
- Object.keys():返回对象自身的所有可枚举的属性的键名。
- JSON.stringify():只串行化对象自身的可枚举的属性。
- Object.assign(): 忽略enumerable为false的属性,只拷贝对象自身的可枚举的属性。
其中第四条为 ES6 中新增的。
引入可枚举性,就是为了在某些操作下,可以规避进行规避,避免所有的内部属性和方法都被遍历。
另外,ES6规定,所有的Class的原型方法都是不可枚举的。
属性的遍历
ES6 中一共有5种方法可以遍历对象的属性。
- for…in
- for…in循环遍历对象自身的和继承的可枚举属性(不含 Symbol 属性)。
- Object.keys(obj)
- Object.keys返回一个数组,包括对象自身的(不含继承的)所有可枚举属性(不含 Symbol 属性)的键名。
- Object.getOwnPropertyNames(obj)
- Object.getOwnPropertyNames返回一个数组,包含对象自身的所有属性(不含 Symbol 属性,但是包括不可枚举属性)的键名。
- Object.getOwnPropertySymbols(obj)
- Object.getOwnPropertySymbols返回一个数组,包含对象自身的所有 Symbol 属性的键名。
- Reflect.ownKeys(obj)
- Reflect.ownKeys返回一个数组,包含对象自身的所有键名,不管键名是 Symbol 或字符串,也不管是否可枚举。
以上5种方法遍历对象的键名,都遵守同样的属性遍历次序规则
- 首先遍历所有数值键,按照数值升序排列。
- 其次遍历所有字符串键,按照加入时间升序排列。
- 最后遍历所有 Symbol 键,按照加入时间升序排列。
1 | Reflect.ownKeys({ [Symbol()]:0, b:0, 10:0, 2:0, a:0 }) |
Symbol
ES6 中引入了新的原始数据类型 Symbol,用来表示一个独一无二的值。
Symbol 值通过函数 Symbol 生成。
Symbol 函数可以接受一个字符串作为参数,用来作为 Symbol 的描述,从而来更好的区分 Symbol 。