ES6-2015
1. let and const
let
变量必须先声明后使用(没有变量提升或者没有与预解析)let
不允许重复声明let
有块级作用域,var
没有(var
有全局作用域和函数作用域)const
声明的变量不允许修改,但是如果是对象的话,对象的属性是可以修改的
2. Template Literals
模板字符串: 用反引号包裹, 可以换行, 可以嵌套变量, 可以嵌套表达式
;`In JavaScript '\n' is a line-feed.`
变量
let name = 'Bob',
time = 'today'
console(`Hello ${name}, how are you ${time}?`)
// Hello Bob, how are you today?
3. Destructuring
数组解构, 对象解构, 字符串解构, 函数参数解构, 默认值, 解构赋值, 剩余方式运算解构
数组解构
let [a, b, c] = [1, 2, 3]
- 忽略解构
let [, , a] = [1, 2, 3]
console.log(a) // 3
- 部分解构
let [a] = [1, 2, 3]
console.log(a) // 1
- 嵌套解构
let [a, [b, c]] = [1, [2, 3]]
console.log(a, b, c) // 1 2 3
剩余方式运算解构
let [a, ...b] = [1, 2, 3] console.log(a, b) // 1 [2, 3]
对象解构
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }
字符串解构
const [a, b, c, d, e] = 'hello'
函数参数解构
function add([x, y]) { return x + y } add([1, 2]) // 3
默认值
let [foo = true] = [] foo // true
解构赋值
let x {x} = {x: 1} x // 1
4. Default Parameters
默认参数: 用于函数的参数, 如果没有传递参数, 则使用默认参数
function log(x, y = 'World') { console.log(x, y) } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello
5. Rest and Spread
剩余参数: 用于函数的参数, 用于获取函数的多余参数, 用于数组的解构赋值
function add(...values) { let sum = 0 for (var val of values) { sum += val } return sum } add(2, 5, 3) // 10
6. Arrow Functions
箭头函数: 用于函数的简写, 用于数组的遍历
var f = (v) => v // 等同于 var f = function (v) { return v }
7. Enhanced Object Literals
增强对象字面量: 用于对象的简写, 用于对象的属性名的简写
function getPoint() { var x = 1 var y = 10 return { x: x, y: y } } // 等同于 function getPoint() { var x = 1 var y = 10 return { x, y } }
简洁表示法
var foo = 'bar' var baz = { foo } baz // {foo: 'bar'}
8. Classes (类)
类的声明
class Point { constructor(x, y) { this.x = x this.y = y } toString() { return '(' + this.x + ', ' + this.y + ')' } } var point = new Point(2, 3) point.toString() // (2, 3)
类的继承
class ColorPoint extends Point { constructor(x, y, color) { super(x, y) // 调用父类的constructor(x, y) this.color = color } toString() { return this.color + ' ' + super.toString() // 调用父类的toString() } }
类的静态方法
class Foo { static classMethod() { return 'hello' } } Foo.classMethod() // 'hello'
类的静态属性
class Foo {} Foo.prop = 1 Foo.prop // 1
类的实例属性
class MyClass { myProp = 42 constructor() { console.log(this.myProp) // 42 } }
类的私有方法
class Widget { // 公有方法 foo(baz) { this._bar(baz) } // 私有方法 _bar(baz) { return (this.snaf = baz) } }
私有属性
class Point { #x constructor(x = 0) { #x = +x } get x() { return #x } set x(value) { #x = +value } }
私有属性和私有方法
class Widget { #fooValue = 42 getFoo() { return this.#fooValue } #barValue = 84 getBar() { return this.#barValue } }
9. Modules (模块)
模块的导入
import { firstName, lastName, year } from './profile'
模块的导出
export var firstName = 'Michael' export var lastName = 'Jackson' export var year = 1958
模块的默认导出
export default function () { console.log('foo') }
模块的默认导入
import customName from './export-default' customName() // 'foo'
模块的整体导入
import * as circle from './circle' console.log('圆周率:' + circle.pi) console.log('计算面积:' + circle.area(4))
模块的继承
// profile.js export var firstName = 'Michael' export var lastName = 'Jackson' export var year = 1958 // main.js import * as profile from './profile' import { lastName as surname } from './profile' function setName(element) { element.textContent = profile.firstName + ' ' + surname }
import * as object
将所有输出接口,放在一个对象上面
10. Promises (异步
Promises: 用于异步编程的解决方案, 用于解决回调地狱的问题.
Promise 的基本用法
const promise = new Promise(function (resolve, reject) { // ... some code if (/* 异步操作成功 */){ resolve(value) } else { reject(error) } })
Promise 的实例方法
promise.then( function (value) { // success }, function (error) { // failure } ) promise.catch(function (error) { // failure }) promise.finally(function () { // ... })
Promise api 的静态方法
Promise.all([p1, p2, p3]).then(function (results) { console.log(results) }) Promise.race([p1, p2, p3]).then(function (result) { console.log(result) })
11. Generators
Generators: 生成器函数, 可以返回多次的函数, 用于解决异步编程的问题.
Generator 函数的语法
function* helloWorldGenerator() { yield 'hello' yield 'world' return 'ending' } var hw = helloWorldGenerator() hw.next() // { value: 'hello', done: false } hw.next() // { value: 'world', done: false } hw.next() // { value: 'ending', done: true } hw.next() // { value: undefined, done: true }
12. Map/Set/WeakMap/WeakSet
Map : 类似于对象,也是键值对的集合,但是“键”的范围不限于字符串,各种类型的值(包括对象)都可以当作键
const m = new Map() const o = { p: 'Hello World' } console.log(m.set(o, 'content')) // Map(1) { { p: 'Hello World' } => 'content' } m.set(o, 'content') m.get(o) // "content" m.has(o) // true m.delete(o) // true m.has(o) // false
Set : 类似于数组,但是成员的值都是唯一的,没有重复的值
const s = new Set()[(2, 3, 5, 4, 5, 2, 2)].forEach((x) => s.add(x)) console.log(s) // Set(4) { 2, 3, 5, 4 } console.log(s.has(2)) // true s.delete(2) // true for (let i of s) { console.log(i) } // 3 5 4
WeakMap : 只接受对象作为键名(null 除外),不接受其他类型的值作为键名
const wm = new WeakMap()
const element = document.getElementById('example')
wm.add(element, 'some information')
wm.get(element) // "some information"
wm.has(element) // true
wm.delete(element) // true
- WeakSet
const ws = new WeakSet()
const element = document.getElementById('example')
ws.add(element)
ws.has(element) // true
ws.delete(element) // true
ws.has(element) // false
13. Proxies (代理)
ES6 原生提供的一种拦截 JavaScript 操作的能力
Proxy 的基本用法
// 用于拦截目标对象的属性访问,可以识别出读取操作(get)、设置操作(set)、 var proxy = new Proxy(target, handler) var proxy = new Proxy( {}, { get: function (target, property) { return 35 }, } ) var obj = new Proxy( {}, { get: function (target, propKey, receiver) { console.log(`getting ${propKey}!`) return Reflect.get(target, propKey, receiver) }, set: function (target, propKey, value, receiver) { console.log(`setting ${propKey}!`) return Reflect.set(target, propKey, value, receiver) }, } ) obj.count = 1 // setting count! ++obj.count // getting count! // setting count! // 2
14. Symbols (符号)
Symbol: ES6 引入了一种新的原始数据类型 Symbol,表示独一无二的值
Symbol 的基本用法
let s = Symbol() typeof s // "symbol" let s1 = Symbol('foo') let s2 = Symbol('bar') s1 // Symbol(foo) s2 // Symbol(bar) s1.toString() // "Symbol(foo)" s2.toString() // "Symbol(bar)" let s1 = Symbol() let s2 = Symbol() s1 === s2 // false
Iterator 和 for...of 循环
Iterator 的基本用法 :
Iterator 的作用有三个:一是为各种数据结构,提供一个统一的、简便的访问接口;二是使得数据结构的成员能够按某种次序排列;三是 ES6 创造了一种新的遍历命令 for...of 循环,Iterator 接口主要供 for...of 消费
let arr = ['hello', 'world'] let map = arr[Symbol.iterator]() map.next() // { value: "hello", done: false } map.next() // { value: "world", done: false } map.next() // { value: undefined, done: true }
for...of 循环
// for...of循环可以自动遍历 Generator 函数时生成的Iterator对象,且此时不再需要调用next方法。 let arr = ['hello', 'world'] for (let v of arr) { console.log(v) // hello world }
16 String 的扩展
字符的 Unicode 表示法
'\u0061' // "a" '\uD842\uDFB7' // "𠮷" '\u20BB7' // " 7" '\u{20BB7}' // "𠮷"
字符的遍历器接口
for (let codePoint of 'foo') { console.log(codePoint) // "f" "o" "o" }
at()
'abc'.charAt(0) // "a" '𠮷'.charAt(0) // "\uD842" '𠮷'.at(0) // "𠮷"
normalize()
'\u01D1'.normalize() === '\u004F\u030C'.normalize() // true
includes(), startsWith(), endsWith()
'abc'.includes('b') // true 'abc'.startsWith('a') // true 'abc'.endsWith('c') // true
repeat()
'x'.repeat(3) // "xxx" 'hello'.repeat(2) // "hellohello" 'na'.repeat(0) // ""
padStart(), padEnd()
'x'.padStart(5, 'ab') // "ababx" 'x'.padEnd(4, 'ab') // "xaba"
17. 正则的扩展
RegExp 构造函数
var regex = new RegExp('xyz', 'i') var regex = new RegExp(/xyz/i) var regex = new RegExp(/xyz/gi, 'i')
字符串的正则方法
'x'.match(/x/) // ["x"] 'x'.match(/y/) // null 'x'.replace('x', 'y') // "y" 'x'.search(/x/) // 0 'x'.search(/y/) // -1 'x'.split('x') // [""] 'x'.split('y') // ["x"]
u 修饰符
/^\uD83D/u.test('\uD83D\uDC2A') // false /^\uD83D/.test('\uD83D\uDC2A') // true
y 修饰符
var s = 'aaa_aa_a' var r1 = /a+/g var r2 = /a+/y r1.exec(s) // ["aaa"] r2.exec(s) // ["aaa"] r1.exec(s) // ["aa"] r2.exec(s) // null
sticky 属性
var r = /hello\d/y r.sticky // true
flags 属性
;/abc/gi.flags // 'gi'
s 修饰符:dotAll 模式
;/foo.bar/.test('foo\nbar') / // false foo.bar / s.test('foo\nbar') // true
18. 数值的扩展
Number.isFinite(), Number.isNaN()
Number.isFinite(15) // true Number.isFinite(0.8) // true Number.isFinite(NaN) // false Number.isFinite(Infinity) // false Number.isFinite(-Infinity) // false Number.isFinite('foo') // false Number.isFinite('15') // false Number.isFinite(true) // false Number.isNaN(NaN) // true Number.isNaN(15) // false Number.isNaN('15') // false Number.isNaN(true) // false Number.isNaN(9 / NaN) // true Number.isNaN('true' / 0) // true Number.isNaN('true' / 'true') // true
Number.parseInt(), Number.parseFloat()
Number.parseInt === parseInt // true Number.parseFloat === parseFloat // true
Number.isInteger()
Number.isInteger(25) // true Number.isInteger(25.0) // true Number.isInteger(25.1) // false Number.isInteger('15') // false Number.isInteger(true) // false
Number.EPSILON 属性: JavaScript 能够准确表示的最小精度
Number.EPSILON === Math.pow(2, -52) // true
安全整数和 Number.isSafeInteger()
Number.isSafeInteger('a') // false Number.isSafeInteger(null) // false Number.isSafeInteger(NaN) // false Number.isSafeInteger(Infinity) // false Number.isSafeInteger(-Infinity) // false Number.isSafeInteger(3) // true Number.isSafeInteger(1.2) // false Number.isSafeInteger(9007199254740990) // true Number.isSafeInteger(9007199254740992) // false
Math 对象的扩展
Math.trunc(4.1) // 4 Math.trunc(4.9) // 4 Math.trunc(-4.1) // -4 Math.trunc(-4.9) // -4 Math.sign(-5) // -1 Math.sign(5) // +1 Math.sign(0) // +0 Math.sign(-0) // -0 Math.sign(NaN) // NaN Math.sign('foo') // NaN Math.sign() // NaN Math.cbrt(-1) // -1 Math.cbrt(0) // 0 Math.cbrt(1) // 1 Math.cbrt('8') // 2 Math.cbrt('hello') // NaN Math.cbrt() // NaN Math.clz32(0) // 32 Math.clz32(1) // 31 Math.clz32(1000) // 22 Math.clz32() // 32 Math.imul(2, 4) // 8 Math.imul(-1, 8) // -8 Math.imul(-2, -2) // 4 Math.fround(0) // 0 Math.fround(1) // 1 Math.fround(1.337) // 1.3370000123977661 Math.hypot(3, 4) // 5 Math.hypot(3, 4, 5) // 7.0710678118654755 Math.hypot() // 0 Math.expm1(1) // 1.718281828459045 Math.expm1(0) // 0 Math.log1p(1) // 0.6931471805599453 Math.log1p(0) // 0 Math.log10(2) // 0.3010299956639812 Math.log10(1) // 0 Math.log2(2) // 1 Math.log2(1) // 0 Math.sinh(x) // 返回 x 的双曲正弦(hyperbolic sine) Math.cosh(x) // 返回 x 的双曲余弦(hyperbolic cosine) Math.tanh(x) // 返回 x 的双曲正切(hyperbolic tangent) Math.asinh(x) // 返回 x 的反双曲正弦值 Math.acosh(x) // 返回 x 的反双曲余弦值 Math.atanh(x) // 返回 x 的反双曲正切值
19. 函数的扩展
函数参数的默认值
function log(x, y = 'World') { console.log(x, y) } log('Hello') // Hello World log('Hello', 'China') // Hello China log('Hello', '') // Hello
与解构赋值默认值结合使用
function foo({ x, y = 5 }) { console.log(x, y) }
函数的 length 属性
//(function (a) {}).length // 1 --> //(function (a = 5) {}).length // 0 //(function (a, b, c = 5) {}).length // 2 //(function (...args) {}).length // 0 //(function (a, b, ...args) {}).length // 2
rest 参数
function add(...values) { let sum = 0 for (var val of values) { sum += val } return sum } add(2, 5, 3) // 10
20. 数组扩展
Array.from()
Array.from('hello') // ['h', 'e', 'l', 'l', 'o'] let namesSet = new Set(['a', 'b']) Array.from(namesSet) // ['a', 'b']
Array.of()
Array.of(3, 11, 8) // [3,11,8] Array.of(3) // [3] Array.of(3).length // 1
数组实例的 copyWithin()
;[1, 2, 3, 4, 5].copyWithin(0, 3) // [4, 5, 3, 4, 5]
数组实例的 find() 和 findIndex()
;[1, 4, -5, 10] .find((n) => n < 0) // -5 [(1, 5, 10, 15)].find(function (value, index, arr) { return value > 9 }) // 10
21. 对象的扩展
属性的简洁表示法
let foo = 'bar' let baz = { foo } baz // {foo: "bar"}
属性名表达式
let propKey = 'foo' let obj = { [propKey]: true, ['a' + 'bc']: 123, } obj // {foo: true, abc: 123}
方法的 name 属性 返回函数的函数名
const person = { sayName() { console.log('hello!') }, } person.sayName.name // "sayName"
Object.is() 比较两个值是否严格相等
Object.is('foo', 'foo') // true Object.is({}, {}) // false
Object.assign() 方法用于对象的合并,将源对象(source)的所有可枚举属性,复制到目标对象(target)
Object.assign(target, ...sources) let target = { a: 1 } let source1 = { b: 2 } let source2 = { c: 3 } Object.assign(target, source1, source2) target // {a:1, b:2, c:3}
22. Decorator
装饰器是一个函数,用来修改类的行为
// 类装饰器 @testable class MyTestableClass { // ... } function testable(target) { target.isTestable = true } MyTestableClass.isTestable // true // 方法装饰器 class Person { @readonly name() { return `${this.first} ${this.last}` } } function readonly(target, name, descriptor) { descriptor.writable = false return descriptor } let p = new Person() p.name = function () { return 'hello' } p.name() // TypeError: Cannot assign to read only property 'name' of object '#<Person>' // 属性装饰器 class Person { @nonenumerable get kidCount() { return this.children.length } } function nonenumerable(target, name, descriptor) { descriptor.enumerable = false return descriptor } for (let key in p) { console.log(key) } let p = new Person({ children: ['a', 'b'] }) p.kidCount // 2 // 参数装饰器 class Person { greet(@required name) { return 'Hello ' + name } } function required(target, name, index) { Object.defineProperty(target, name, { get: function () { throw new Error('Missing parameter') }, }) } let p = new Person() p.greet() // Error: Missing parameter // 装饰器执行顺序 // 从后往前执行, 从下往上执行
参考资料