let/const

  1. # let const
  2. ES6以前,JS只有var一种声明方式,但是在ES6之后,就多了letconst这两种方式。
  3. var定义的变量没有块级作用域的概念,而letconst则会有,因为这三个关键字创建是不一样的。
  4. {
  5. var a = 10
  6. let b = 20
  7. const c = 30
  8. }
  9. a // 10
  10. b // Uncaught ReferenceError: b is not defined
  11. c // c is not defined
  12. let d = 40
  13. const e = 50
  14. d = 60
  15. d // 60
  16. e = 70 // VM231:1 Uncaught TypeError: Assignment to constant variable.

Class

  1. # Class
  2. // ES6之前写法
  3. function Person(name, age) {
  4. this.name = name
  5. this.age = age
  6. }
  7. Person.prototype.information = function () {
  8. return 'My name is ' + this.name + ', I am ' + this.age
  9. }
  10. // ES6写法
  11. class Person {
  12. constructor(name, age) {
  13. this.name = name
  14. this.age = age
  15. }
  16. information() {
  17. return 'My name is ' + this.name + ', I am ' + this.age
  18. }
  19. }

Arrow function

  1. # Arrow function
  2. 箭头函数表达式的语法比函数表达式更简洁,并且没有自己的thisargumentssuper new.target
  3. 这些函数表达式更适用于那些本来需要匿名函数的地方,并且它们不能用作构造函数。
  4. ES6以前,我们写函数一般是:
  5. var list = [1, 2, 3, 4, 5, 6, 7]
  6. var newList = list.map(function (item) {
  7. return item * item
  8. })
  9. 但是在ES6里,我们可以:
  10. const list = [1, 2, 3, 4, 5, 6, 7]
  11. const newList = list.map(item => item * item)
  12. 看,是不是简洁了不少,而且箭头函数做回调的时候没有this的指向问题。

Function parameter defaults

  1. # Function parameter defaults
  2. ES6之前,如果我们写函数需要定义初始值的时候,需要这么写:
  3. function config (data) {
  4. var data = data || 'data is empty'
  5. }
  6. 这样看起来也没有问题,但是如果参数的布尔值为false时就会出问题,例如我们这样调用config
  7. config(0)
  8. config('')
  9. 那么结果就永远是后面的值
  10. 如果我们用函数参数默认值就没有这个问题,写法如下:
  11. const config = (data = 'data is empty') => {}

Template string (模版字符串)

  1. # Template string
  2. ES6之前,如果我们要拼接字符串,则需要像这样:
  3. var name = 'kris'
  4. var age = 24
  5. var info = 'My name is ' + this.name + ', I am ' + this.age
  6. 但是在ES6之后,我们只需要写成以下形式:
  7. const name = 'kris'
  8. const age = 24
  9. const info = `My name is ${name}, I am ${age}`

Destructuring assignment

  1. # Destructuring assignment
  2. 我们通过解构赋值, 可以将属性/值从对象/数组中取出,赋值给其他变量。
  3. 比如我们需要交换两个变量的值,在ES6之前我们可能需要:
  4. var a = 10
  5. var b = 20
  6. var temp = a
  7. a = b
  8. b = temp
  9. 但是在ES6里,我们有:
  10. let a = 10
  11. let b = 20
  12. [a, b] = [b, a]
  13. 是不是方便很多

Module

  1. # Module
  2. ES6之前,JS并没有模块化的概念,有的也只是社区定制的类似CommonJSAMD之类的规则。例如基于CommonJSNodeJS
  3. // circle.js
  4. // 输出
  5. const { PI } = Math
  6. exports.area = (r) => PI * r ** 2
  7. exports.circumference = (r) => 2 * PI * r
  8. // index.js
  9. // 输入
  10. const circle = require('./circle.js')
  11. console.log(`半径为 4 的圆的面积是 ${circle.area(4)}`)
  12. ES6之后我们则可以写成以下形式:
  13. // circle.js
  14. // 输出
  15. const { PI } = Math
  16. export const area = (r) => PI * r ** 2
  17. export const circumference = (r) => 2 * PI * r
  18. // index.js
  19. // 输入
  20. import {
  21. area
  22. } = './circle.js'
  23. console.log(`半径为 4 的圆的面积是: ${area(4)}`)

Spread operator

  1. # Spread operator
  2. ES6Spread Operator 是三个点儿... 用来组装对象或者数组
  3. 扩展操作符可以在函数调用/数组构造时, 将数组表达式或者string在语法层面展开;还可以在构造字面量对象时, 将对象表达式按key-value的方式展开。
  4. 比如在ES5的时候,我们要对一个数组的元素进行相加,在不使用reduce或者reduceRight的场合,我们需要:
  5. function sum(x, y, z) {
  6. return x + y + z;
  7. }
  8. var list = [5, 6, 7]
  9. var total = sum.apply(null, list)
  10. 但是如果我们使用扩展操作符,只需要如下:
  11. const sum = (x, y, z) => x + y + z
  12. const list = [5, 6, 7]
  13. const total = sum(...list)
  14. 非常的简单,但是要注意的是扩展操作符只能用于可迭代对象
  15. 如果是下面的情况,是会报错的:
  16. var obj = {'key1': 'value1'}
  17. var array = [...obj] // TypeError: obj is not iterable

Object attribute shorthand

  1. # Object attribute shorthand
  2. ES6之前,如果我们要将某个变量赋值为同样名称的对象元素,则需要:
  3. var cat = 'Miaow'
  4. var dog = 'Woof'
  5. var bird = 'Peet peet'
  6. var someObject = {
  7. cat: cat,
  8. dog: dog,
  9. bird: bird
  10. }
  11. 但是在ES6里我们就方便很多:
  12. let cat = 'Miaow'
  13. let dog = 'Woof'
  14. let bird = 'Peet peet'
  15. let someObject = {
  16. cat,
  17. dog,
  18. bird
  19. }
  20. console.log(someObject)
  21. //{
  22. // cat: "Miaow",
  23. // dog: "Woof",
  24. // bird: "Peet peet"
  25. //}
  26. 非常方便

Promise

  1. # Promise
  2. Promise ES6提供的一种异步解决方案,比回调函数更加清晰明了。
  3. Promise 翻译过来就是承诺的意思,这个承诺会在未来有一个确切的答复,并且该承诺有三种状态,分别是:
  4. 1.等待中(pending2.完成了 resolved3.拒绝了(rejected
  5. 这个承诺一旦从等待状态变成为其他状态就永远不能更改状态了,也就是说一旦状态变为 resolved 后,就不能再次改变
  6. new Promise((resolve, reject) => {
  7. resolve('success')
  8. // 无效
  9. reject('reject')
  10. })
  11. 当我们在构造 Promise 的时候,构造函数内部的代码是立即执行的
  12. new Promise((resolve, reject) => {
  13. console.log('new Promise')
  14. resolve('success')
  15. })
  16. console.log('finifsh')
  17. // new Promise -> finifsh
  18. Promise 实现了链式调用,也就是说每次调用 then 之后返回的都是一个 Promise,并且是一个全新的 Promise,原因也是因为状态不可变。如果你在 then 使用了 return,那么 return 的值会被 Promise.resolve() 包装
  19. Promise.resolve(1)
  20. .then(res => {
  21. console.log(res) // => 1
  22. return 2 // 包装成 Promise.resolve(2)
  23. })
  24. .then(res => {
  25. console.log(res) // => 2
  26. })
  27. 当然了,Promise 也很好地解决了回调地狱的问题,例如:
  28. ajax(url, () => {
  29. // 处理逻辑
  30. ajax(url1, () => {
  31. // 处理逻辑
  32. ajax(url2, () => {
  33. // 处理逻辑
  34. })
  35. })
  36. })
  37. 可以改写成:
  38. ajax(url)
  39. .then(res => {
  40. console.log(res)
  41. return ajax(url1)
  42. }).then(res => {
  43. console.log(res)
  44. return ajax(url2)
  45. }).then(res => console.log(res))

for…of

  1. # for...of
  2. for...of语句在可迭代对象(包括 ArrayMapSetStringTypedArrayarguments 对象等等)上创建一个迭代循环,调用自定义迭代钩子,并为每个不同属性的值执行语句。
  3. 例子如下:
  4. const array1 = ['a', 'b', 'c'];
  5. for (const element of array1) {
  6. console.log(element)
  7. }
  8. // "a"
  9. // "b"
  10. // "c"

Symbol

  1. # Symbol
  2. Symbol类型是为了解决属性名冲突的问题,顺带还具备模拟私有属性的功能。
  3. symbol 是一种基本数据类型,Symbol()函数会返回symbol类型的值,该类型具有静态属性和静态方法。它的静态属性会暴露几个内建的成员对象;它的静态方法会暴露全局的symbol注册,且类似于内建对象类,但作为构造函数来说它并不完整,因为它不支持语法:"new Symbol()"
  4. 每个从Symbol()返回的symbol值都是唯一的。一个symbol值能作为对象属性的标识符;这是该数据类型仅有的目的。
  5. 例子如下:
  6. const symbol1 = Symbol();
  7. const symbol2 = Symbol(42);
  8. const symbol3 = Symbol('foo');
  9. console.log(typeof symbol1); // "symbol"
  10. console.log(symbol3.toString()); // "Symbol(foo)"
  11. console.log(Symbol('foo') === Symbol('foo')); // false

迭代器(Iterator)/ 生成器(Generator)

  1. # 迭代器(Iterator)/ 生成器(Generator
  2. iterator:它是这么一个对象,拥有一个next方法,这个方法返回一个对象{done,value},这个对象包含两个属性,一个布尔类型的done和包含任意值的value
  3. iterable: 这是这么一个对象,拥有一个obj[@@iterator]方法,这个方法返回一个iterator
  4. generator: 它是一种特殊的iterator。反的next方法可以接收一个参数并且返回值取决与它的构造函数(generator function)。generator同时拥有一个throw方法
  5. generator 函数: generator的构造函数。此函数内可以使用yield关键字。在yield出现的地方可以通过generatornextthrow方法向外界传递值。generator 函数是通过function*来声明的
  6. yield 关键字:它可以暂停函数的执行,随后可以再进进入函数继续执行
  7. 迭代器(Iterator)是一种迭代的机制,为各种不同的数据结构提供统一的访问机制。任何数据结构只要内部有 Iterator 接口,就可以完成依次迭代操作。
  8. 一旦创建,迭代器对象可以通过重复调用next()显式地迭代,从而获取该对象每一级的值,直到迭代完,返回{ value: undefined, done: true }
  9. 虽然自定义的迭代器是一个有用的工具,但由于需要显式地维护其内部状态,因此需要谨慎地创建。生成器函数提供了一个强大的选择:它允许你定义一个包含自有迭代算法的函数, 同时它可以自动维护自己的状态。生成器函数使用 function*[2]语法编写。最初调用时,生成器函数不执行任何代码,而是返回一种称为Generator的迭代器。通过调用生成器的下一个方法消耗值时,Generator函数将执行,直到遇到yield关键字。
  10. 可以根据需要多次调用该函数,并且每次都返回一个新的Generator,但每个Generator只能迭代一次。
  11. 所以我们可以有以下例子:
  12. function* makeRangeIterator(start = 0, end = Infinity, step = 1) {
  13. for (let i = start; i < end; i += step) {
  14. yield i;
  15. }
  16. }
  17. var a = makeRangeIterator(1,10,2)
  18. a.next() // {value: 1, done: false}
  19. a.next() // {value: 3, done: false}
  20. a.next() // {value: 5, done: false}
  21. a.next() // {value: 7, done: false}
  22. a.next() // {value: 9, done: false}
  23. a.next() // {value: undefined, done: true}

Set/WeakSet

  1. # Set/WeakSet
  2. Set 对象允许你存储任何类型的唯一值,无论是原始值或者是对象引用。
  3. 所以我们可以通过Set实现数组去重
  4. const numbers = [2,3,4,4,2,3,3,4,4,5,5,6,6,7,5,32,3,4,5]
  5. console.log([...new Set(numbers)])
  6. // [2, 3, 4, 5, 6, 7, 32]
  7. WeakSet 结构与 Set 类似,但区别有以下两点:
  8. WeakSet 对象中只能存放对象引用, 不能存放值, Set 对象都可以。•WeakSet 对象中存储的对象值都是被弱引用的, 如果没有其他的变量或属性引用这个对象值, 则这个对象值会被当成垃圾回收掉. 正因为这样, WeakSet 对象是无法被枚举的, 没有办法拿到它包含的所有元素。
  9. 所以代码如下:
  10. var ws = new WeakSet()
  11. var obj = {}
  12. var foo = {}
  13. ws.add(window)
  14. ws.add(obj)
  15. ws.has(window) // true
  16. ws.has(foo) // false, 对象 foo 并没有被添加进 ws 中
  17. ws.delete(window) // 从集合中删除 window 对象
  18. ws.has(window) // false, window 对象已经被删除了
  19. ws.clear() // 清空整个 WeakSet 对象

Map/WeakMap

  1. # Map/WeakMap
  2. Map 对象保存键值对。任何值(对象或者原始值) 都可以作为一个键或一个值。
  3. 例子如下,我们甚至可以使用NaN来作为键值:
  4. var myMap = new Map();
  5. myMap.set(NaN, "not a number");
  6. myMap.get(NaN); // "not a number"
  7. var otherNaN = Number("foo");
  8. myMap.get(otherNaN); // "not a number"
  9. WeakMap 对象是一组键/值对的集合,其中的键是弱引用的。其键必须是对象,而值可以是任意的。
  10. Map的区别与SetWeakSet的区别相似,具体代码如下:
  11. var wm1 = new WeakMap(),
  12. wm2 = new WeakMap(),
  13. wm3 = new WeakMap();
  14. var o1 = {},
  15. o2 = function(){},
  16. o3 = window;
  17. wm1.set(o1, 37);
  18. wm1.set(o2, "azerty");
  19. wm2.set(o1, o2); // value可以是任意值,包括一个对象
  20. wm2.set(o3, undefined);
  21. wm2.set(wm1, wm2); // 键和值可以是任意对象,甚至另外一个WeakMap对象
  22. wm1.get(o2); // "azerty"
  23. wm2.get(o2); // undefined,wm2中没有o2这个键
  24. wm2.get(o3); // undefined,值就是undefined
  25. wm1.has(o2); // true
  26. wm2.has(o2); // false
  27. wm2.has(o3); // true (即使值是undefined)
  28. wm3.set(o1, 37);
  29. wm3.get(o1); // 37
  30. wm3.clear();
  31. wm3.get(o1); // undefined,wm3已被清空
  32. wm1.has(o1); // true
  33. wm1.delete(o1);
  34. wm1.has(o1); // false

Proxy/Reflect

  1. # Proxy/Reflect
  2. Proxy 对象用于创建一个对象的代理,从而实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)。
  3. Proxy 对象用于定义基本操作的自定义行为(如属性查找,赋值,枚举,函数调用等)。
  4. Reflect 是一个内置的对象,它提供拦截 JavaScript 操作的方法。这些方法与 Proxy 的方法相同。Reflect不是一个函数对象,因此它是不可构造的。
  5. ProxyReflect是非常完美的配合,例子如下:
  6. const observe = (data, callback) => {
  7. return new Proxy(data, {
  8. get(target, key) {
  9. return Reflect.get(target, key)
  10. },
  11. set(target, key, value, proxy) {
  12. callback(key, value);
  13. target[key] = value;
  14. return Reflect.set(target, key, value, proxy)
  15. }
  16. })
  17. }
  18. const FooBar = { open: false };
  19. const FooBarObserver = observe(FooBar, (property, value) => {
  20. property === 'open' && value
  21. ? console.log('FooBar is open!!!')
  22. : console.log('keep waiting');
  23. });
  24. console.log(FooBarObserver.open) // false
  25. FooBarObserver.open = true // FooBar is open!!!
  26. 当然也不是什么都可以被代理的,如果对象带有configurable: false writable: false 属性,则代理失效。

Math对象的扩展

  1. # Math对象的扩展
  2. •二进制表示法 : 0b0B开头表示二进制(0bXX0BXX)
  3. •二进制表示法 : 0b0B开头表示二进制(0bXX0BXX)
  4. •八进制表示法 : 0o0O开头表示二进制(0oXX0OXX)
  5. Number.EPSILON : 数值最小精度
  6. Number.MIN_SAFE_INTEGER : 最小安全数值(-2^53)
  7. Number.MAX_SAFE_INTEGER : 最大安全数值(2^53)
  8. Number.parseInt() : 返回转换值的整数部分
  9. Number.parseFloat() : 返回转换值的浮点数部分
  10. Number.isFinite() : 是否为有限数值
  11. Number.isNaN() : 是否为NaN
  12. Number.isInteger() : 是否为整数
  13. Number.isSafeInteger() : 是否在数值安全范围内
  14. Math.trunc() : 返回数值整数部分
  15. Math.sign() : 返回数值类型(正数1、负数-1、零0)
  16. Math.cbrt() : 返回数值立方根
  17. Math.clz32() : 返回数值的32位无符号整数形式
  18. Math.imul() : 返回两个数值相乘
  19. Math.fround() : 返回数值的32位单精度浮点数形式
  20. Math.hypot() : 返回所有数值平方和的平方根
  21. Math.expm1() : 返回e^n - 1
  22. Math.log1p() : 返回1 + n的自然对数(Math.log(1 + n))
  23. Math.log10() : 返回以10为底的n的对数
  24. Math.log2() : 返回以2为底的n的对数
  25. Math.sinh() : 返回n的双曲正弦
  26. Math.cosh() : 返回n的双曲余弦
  27. Math.tanh() : 返回n的双曲正切
  28. Math.asinh() : 返回n的反双曲正弦
  29. Math.acosh() : 返回n的反双曲余弦
  30. Math.atanh() : 返回n的反双曲正切

Array对象的扩展

  1. # Array对象的扩展
  2. Array.prototype.from:转换具有Iterator接口的数据结构为真正数组,返回新数组。
  3. console.log(Array.from('foo')) // ["f", "o", "o"]
  4. console.log(Array.from([1, 2, 3], x => x + x)) // [2, 4, 6]
  5. Array.prototype.of():转换一组值为真正数组,返回新数组。
  6. Array.of(7) // [7]
  7. Array.of(1, 2, 3) // [1, 2, 3]
  8. Array(7) // [empty, empty, empty, empty, empty, empty]
  9. Array(1, 2, 3) // [1, 2, 3]
  10. Array.prototype.copyWithin():把指定位置的成员复制到其他位置,返回原数组
  11. const array1 = ['a', 'b', 'c', 'd', 'e']
  12. console.log(array1.copyWithin(0, 3, 4)) // ["d", "b", "c", "d", "e"]
  13. console.log(array1.copyWithin(1, 3)) // ["d", "d", "e", "d", "e"]
  14. Array.prototype.find():返回第一个符合条件的成员
  15. const array1 = [5, 12, 8, 130, 44]
  16. const found = array1.find(element => element > 10)
  17. console.log(found) // 12
  18. Array.prototype.findIndex():返回第一个符合条件的成员索引值
  19. const array1 = [5, 12, 8, 130, 44]
  20. const isLargeNumber = (element) => element > 13
  21. console.log(array1.findIndex(isLargeNumber)) // 3
  22. Array.prototype.fill():根据指定值填充整个数组,返回原数组
  23. const array1 = [1, 2, 3, 4]
  24. console.log(array1.fill(0, 2, 4)) // [1, 2, 0, 0]
  25. console.log(array1.fill(5, 1)) // [1, 5, 5, 5]
  26. console.log(array1.fill(6)) // [6, 6, 6, 6]
  27. Array.prototype.keys():返回以索引值为遍历器的对象
  28. const array1 = ['a', 'b', 'c']
  29. const iterator = array1.keys()
  30. for (const key of iterator) {
  31. console.log(key)
  32. }
  33. // 0
  34. // 1
  35. // 2
  36. Array.prototype.values():返回以属性值为遍历器的对象
  37. const array1 = ['a', 'b', 'c']
  38. const iterator = array1.values()
  39. for (const key of iterator) {
  40. console.log(key)
  41. }
  42. // a
  43. // b
  44. // c
  45. Array.prototype.entries():返回以索引值和属性值为遍历器的对象
  46. const array1 = ['a', 'b', 'c']
  47. const iterator = array1.entries()
  48. console.log(iterator.next().value) // [0, "a"]
  49. console.log(iterator.next().value) // [1, "b"]
  50. •数组空位:ES6明确将数组空位转为undefined或者empty
  51. Array.from(['a',,'b']) // [ "a", undefined, "b" ]
  52. [...['a',,'b']] // [ "a", undefined, "b" ]
  53. Array(3) // [empty × 3]
  54. [,'a'] // [empty, "a"]

https://es6.ruanyifeng.com/#docs/let

https://juejin.cn/post/6844903959283367950