关于前端:10分钟了解ES6ES2015ES2019那些重要的特性

45次阅读

共计 12676 个字符,预计需要花费 32 分钟才能阅读完成。

ES2015(ES6)

ES2015 是 2015 年公布的 ECMA Script(JS) 语言版本,也是第 6 个版本,所以也称之为 ES6。在尔后 ECMA Script 每年公布一个大版本新减少一些重要个性,咱们称之为 ES6+。

本文次要总结了 ES2015-ES2019 的次要个性,一个学习前端的童鞋应该是罕用且了解的一些个性。

ES2015 的次要作用:

  • 解决原有语法的一些有余
  • 对原有语法进行加强
  • 全新的对象、全新的办法、全新的性能

    Promise、Proxy、Object.assign 等

  • 全新的数据类型和数据结构

    Symbol、Set、Map 等

ES2015 罕用的环境反对状况

  • nodejs 查问:https://node.green/
  • 浏览器查问:http://kangax.github.io/compa…

PC 浏览器对 ES2015 的反对状况

  • Chrome:51 版起便能够反对 97% 的 ES6 新个性。
  • Firefox:53 版起便能够反对 97% 的 ES6 新个性。
  • Safari:10 版起便能够反对 99% 的 ES6 新个性。
  • Edge:Edge 15 能够反对 96% 的 ES6 新个性。Edge 14 能够反对 93% 的 ES6 新个性。
  • IE:IE7 ~ 11 根本不反对 ES6

挪动端浏览器对 ES2015 的反对状况

  • iOS:10.0 版起便能够反对 99% 的 ES6 新个性。
  • Android:根本不反对 ES6 新个性(5.1 仅反对 25%)

服务器对 ES2015 的反对状况,具体查看:https://node.green/

  • Node.js:6.5 版起便能够反对 97% 的 ES6 新个性。(6.0 反对 92%)

var(比照 let、const)

  • 只有全局作用域、函数作用域,不存在严格的块级作用域
  • 存在变量晋升
  • 变量的申明和定义能够离开进行
  • 变量能够反复申明

let(块级作用域)

  • 存在块级作用域
  • 不能变量晋升
  • 变量的申明和定义能够离开进行
  • 变量不能反复申明

const 常量

  • 存在块级作用域
  • 不能变量晋升
  • 变量的申明和定义必须在同一个语句中
  • 变量不能反复申明
  • 不能批改申明过的变量值(例如:能够批改对象的属性值,不能批改对象地址)
  • 最佳实际:不必 var,主用 const,配合 let

数组解构

const [foo, bar, baz] = arr
console.log(foo, bar, baz)

const [, , baz] = arr
console.log(baz)

// 解构残余的数组元素
// 只能在最初一个地位应用扩大运算符
const [foo, ...rest] = arr
console.log(rest)

// 解构时元素较少,依照程序取元素
const [foo] = arr
console.log(foo)

// 解构时设置默认值
const [foo, bar, baz = 123, more = 'default value'] = arr
console.log(bar, more)

对象解构

const obj = {name: 'zce', age: 18}

// 变量名反复时,能够重命名和设置默认值
const name = 'tom'
const {name: objName = 'jack'} = obj
console.log(objName)

模板字符串

  • 反对换行符
  • 反对嵌入变量、表达式
const name = 'tom'
// 能够通过 ${} 插入表达式,表达式的执行后果将会输入到对应地位
const msg = `hey, ${name} --- ${1 + 2} ---- ${Math.random()}`
console.log(msg)

字符串的扩大办法

  • includes 蕴含字符串
  • startsWith 是否以某字符串结尾
  • endsWith 是否以某字符串完结
const message = 'Error: foo is not defined.'

console.log(// message.startsWith('Error')
  // message.endsWith('.')
  message.includes('foo')
)

办法的参数默认值

  • 在 function 参数前面应用 = 设置默认值
  • 只有当形参传递是 undefined 或者没有传递值时,才会设置默认值(false 也不会)
  • 如果只有局部默认值,须要将设置默认值的代码放到前面;否则无奈失常应用
// 默认参数肯定是在形参列表的最初
function foo (bar,enable = true) {console.log('foo invoked - enable:')
  console.log(enable)
}

foo(false)

办法的残余参数

  • 只能呈现在形参的最初一位
  • 只能应用一次
  • args 是一个数组,区别于 arguments 是一个伪数组
function foo (first, ...args) {console.log(args)
}

foo(1, 2, 3, 4)

开展数组

const arr = ['foo', 'bar', 'baz']

// console.log(//   arr[0],
//   arr[1],
//   arr[2],
// )

// console.log.apply(console, arr)

console.log(...arr)

箭头函数

插件:Fira Code 字体将箭头画的更好看

const arr = [1, 2, 3, 4, 5, 6, 7]

// arr.filter(function (item) {
//   return item % 2
// })

// 罕用场景,回调函数
arr.filter(i => i % 2)

箭头函数的简写

function(value){return value} 等价于 value=>value

箭头函数的 this 指向

  • 一般函数的 this 指向调用它办法的对象
  • 箭头函数的 this 和它里面函数的 this 指向雷同,即:箭头函数不会扭转 this 的指向
// 箭头函数与 this
// 箭头函数不会扭转 this 指向

const person = {
  name: 'tom',
  // sayHi: function () {//   console.log(`hi, my name is ${this.name}`)//tom,this 指向该函数调用者
  // }
  sayHi: () => {console.log(`hi, my name is ${this.name}`) //undefined,this 和 sayHi()里面的函数 this 雷同},
  sayHiAsync: function () {
    // const _this = this
    // setTimeout(function () {//   console.log(_this.name) // 这里的 this 为 window,所以须要应用_this
    // }, 1000)

    console.log(this)
    setTimeout(() => {// console.log(this.name) // 这里的 this 指向 sayHiAsync 里的 this,即 person
      console.log(this)
    }, 1000)
  }
}
person.sayHi()
person.sayHiAsync()

对象字面量

  • 如果属性名和值的变量名雷同,能够省略一个变量
  • 办法的简写:能够省略“:function”
  • 计算属性名:属性名能够在 [] 外面应用任意表达式
const bar = '345'

const obj = {
  foo: 123,
  // bar: bar
  // 属性名与变量名雷同,能够省略 : bar
  bar,
  // method1: function () {//   console.log('method111')
  // }
  // 办法能够省略 : function
  method1 () {console.log('method111')
    // 这种办法就是一般的函数,this 指向 obj。console.log(this)
  },
  // Math.random(): 123 // 不容许,应用 [] 才行
  // 通过 [] 让表达式的后果作为属性名
  [bar]: 123
}

Object.assign

Object.assign 是不齐全的深拷贝?它到底拷贝了多少货色?
获取不到 obj 中的 get、set 信息

  • 将源对象中的值赋值到指标对象
  • 指标对象和返回值是同一个对象
  • 如果指标对象中有雷同名字的属性,则笼罩该属性
  • 能够传入多个源对象,依照程序顺次笼罩指标对象
const source1 = {
  a: 123,
  b: 123
}

const source2 = {
  b: 789,
  d: 789
}

const target = {
  a: 456,
  c: 456
}

const result = Object.assign(target, source1, source2)

console.log(target)
console.log(result === target) //true,指标对象和返回值是一个对象

Object.is

0 == false              // => true
0 === false             // => false
+0 === -0               // => true
NaN === NaN             // => false
Object.is(+0, -0)       // => false
Object.is(NaN, NaN)     // => true

Proxy 和 Object.defineProperty

Proxy 的作用
对 Object 属性变动进行监听

比照 Object.defineProperty
参考笔记:https://gitee.com/ymcdhr/e-ta…

Reflect(对立的操作 Object 对象办法)

  • Proxy 属性的办法中默认调用了 Reflect 中的办法,例如:
const obj = {
  foo: '123',
  bar: '456'
}

const proxy = new Proxy(obj, {get (target, property) {console.log('watch logic~')
    // Proxy 中如果不写,默认调用了此办法
    return Reflect.get(target, property)
  }
})
  • Relect 提供了对立的操作 Object 对象的办法,MDN 上有残缺的 13 中办法:

https://developer.mozilla.org…

// console.log('name' in obj)
// console.log(delete obj['age'])
// console.log(Object.keys(obj))

console.log(Reflect.has(obj, 'name'))
console.log(Reflect.deleteProperty(obj, 'age'))
console.log(Reflect.ownKeys(obj))

Promise

参考文档:js 单线程机制与异步编程(Promise、Generator、Async、Await)

Class 类的根本语法

// class 关键词

// function Person (name) {
//   this.name = name
// }

// Person.prototype.say = function () {//   console.log(`hi, my name is ${this.name}`)
// }

class Person {
  // 构造函数
  constructor (name) {this.name = name}
  // 成员变量
  age = 18
  // 成员函数
  say () {console.log(`hi, my name is ${this.name}`)
  }
}

const p = new Person('tom')
p.say()

Class 中的静态方法 static

  • 申明静态方法:static 关键字
  • 调用静态方法:Person.say
  • 静态方法的 this 指向为类
// static 办法

class Person {constructor (name) {this.name = name}

  say () {console.log(`hi, my name is ${this.name}`)
  }

  static create (name) {return new Person(name)
  }
}

const tom = Person.create('tom')
tom.say()

Class 的继承

  • 应用 extends 继承
  • 留神 super 的应用,可能拜访父类;通常用来执行父类构造函数。
class Person {constructor (name) {this.name = name}

  say () {console.log(`hi, my name is ${this.name}`)
  }
}

class Student extends Person {constructor (name, number) {super(name) // 调用父类构造函数,否则 name 就没有赋值(重要)this.number = number
  }

  hello () {super.say() // 调用父类成员
    console.log(`my school number is ${this.number}`)
  }
}

const s = new Student('jack', '100')
s.hello()

Set、Map

Set 没有反复元素的数组汇合

罕用的成员办法

  • s.add(item) 增加 item,返回汇合自身,可链式调用
  • s.size 获取 Set 的长度
  • s.has(item)判断是否存在某个 item
  • s.delete(item)删除某个 item
  • s.clear()删除全副
const s = new Set()
s.add(1).add(2).add(3).add(4).add(2)
// console.log(s)

// s.forEach(i => console.log(i))  //forEach、for...of 都能够用来遍历 Set

// for (let i of s) {//   console.log(i)
// }

// console.log(s.size)
// console.log(s.has(100))
// console.log(s.delete(3))
// console.log(s)
// s.clear()
// console.log(s)

罕用来数组去重

// 利用场景:数组去重
const arr = [1, 2, 1, 3, 4, 1]

const result1 = Array.from(new Set(arr))
const result2 = [...new Set(arr)]

console.log(result1,result2)

Map 能应用简单构造作为属性的对象汇合

以前的对象存储对象属性时,会将简单数据转换成字符串(toString()办法),如下:

const obj = {}
obj[true] = 'value'
obj[123] = 'value'
obj[{a: 1}] = 'value'

console.log(Object.keys(obj))

//0: "123"
//1: "true"
//2: "[object Object]"

应用 Map 能够存储简单数据作为对象属性,罕用的办法有如下:

const m = new Map()
const tom = {name: 'tom'}
m.set(tom, 90)
console.log(m)
console.log(m.get(tom))

// m.has()
// m.delete()
// m.clear()

// forEach 能够遍历 Map 中的 item
m.forEach((value, key) => {console.log(value, key)
})

Symbol

一个全新的根底数据类型,每次创立都是举世无双的值

let s = Symbol();

typeof s
// "symbol"

let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 === s2 // false

// for 办法是创立的一样的值,参数会主动转换成字符串
let s3 = Symbol.for('foo');
let s4 = Symbol.for('foo');

s3 === s4 // true

能够转换为字符串,通过 description(ES2019 提供的办法)

let s1 = Symbol('foo');
let s2 = Symbol('foo');

s1 // Symbol(foo)
s2 // Symbol(foo)

s1 === s2 // false

s1.toString() // "Symbol(foo)"
s2.toString() // "Symbol(foo)"
s1.description // "foo" // ES2019 提供的办法

能够作为对象的属性名,能够防止同名抵触

const obj = {}
obj[Symbol()] = '123'
obj[Symbol()] = '456'
console.log(obj)
//Symbol(): "123"
//Symbol(): "456"

应用 Symbol 值定义属性时,Symbol 值必须放在方括号之中,而且不能应用点运算符

let s = Symbol();

// 第一种写法
let a = {};
a[s] = 'Hello!';

// 第二种写法
let a = {[s]: 'Hello!'
};

// 以上写法都失去同样后果
a[s] // "Hello!"

能够作为对象的公有成员,不能在内部间接拜访(因为每次拜访都不一样),只能通过外部 this 拜访

// 案例 2:Symbol 模仿实现公有成员

// a.js ======================================

const name = Symbol()
const person = {[name]: 'zce',
  say () {console.log(this[name])
  }
}
// 只对外裸露 person

// b.js =======================================

// 因为无奈创立出一样的 Symbol 值,// 所以无奈间接拜访到 person 中的「公有」成员
// person[Symbol()]
person.say()

留神:for…in、Obeject.keys、Json.stringify 都无奈在 Symbol 上应用
应用:Object.getOwnPropertySymbols,代替 Obeject.keys 办法用于 Symbol

for…of 对立遍历办法

以前的 for…in 遍历键值对,forEach 存在局限性

  1. 能够用应用 break 终止遍历,forEach 不能跳出循环
  2. 能够遍历 Array 数组、Set 和 Map 对象
  3. 一般对象不能被间接 for…of 遍历,因为它没有 Symbol.iterator 属性
  • 对象(Object)之所以没有默认部署 Iterator 接口,是因为对象的哪个属性先遍历,哪个属性后遍历是不确定的,须要开发者手动指定。
  1. 所有能够应用 for…of 的对象都须要具备 Symbol.iterator 属性
// for...of 循环
const arr = [100, 200, 300, 400]

// for...of 循环能够代替 数组对象的 forEach 办法 但能够应用 break 跳出循环
arr.forEach(item => {console.log(item)
})

for (const item of arr) {console.log(item)
  if (item > 100) {break}
}

// forEach 无奈跳出循环,必须应用 some 或者 every 办法
// arr.forEach() // 不能跳出循环
// arr.some()
// arr.every()

// 遍历 Set 与遍历数组雷同
const s = new Set(['foo', 'bar'])

for (const item of s) {console.log(item)
}

// 遍历 Map 能够配合数组构造语法,间接获取键值
const m = new Map()
m.set('foo', '123')
m.set('bar', '345')

for (const [key, value] of m) {console.log(key, value)
}

// 一般对象不能被间接 for...of 遍历
const obj = {foo: 123, bar: 456}

for (const item of obj) {console.log(item)
}

可迭代接口 iterator(次要给 for…of 应用)

  • 一些数据结构的原型对象 proto 中含有 Symbol.iterator 办法
  • iterator 办法返回一个带 next()办法的指针对象
  • 每次执行 next()办法,它都会返回下一个数据

具备 Symbol.iterator 属性的数据结构

Array、Map、Set、String、TypedArray、函数的 arguments 对象、NodeList 对象

iterator 的遍历过程是这样的。

  • (1)创立一个指针对象,指向以后数据结构的起始地位。也就是说,遍历器对象实质上,就是一个指针对象。
  • (2)第一次调用指针对象的 next 办法,能够将指针指向数据结构的第一个成员。
  • (3)第二次调用指针对象的 next 办法,指针就指向数据结构的第二个成员。
  • (4)一直调用指针对象的 next 办法,直到它指向数据结构的完结地位。

使对象可能应用 for…of

const obj = {// 应用计算属性,用 [] 存表达式属性名
  // 1、Iterable,对象必须要有一个 Symbol.iterator 属性
  [Symbol.iterator]: function () {
    return {// 2、Iterator,返回的对象有一个 next()办法
      next: function () {// 3、IterationResult,next()办法返回一个对象
        return {
          value: 'zce',
          done: true
        }
      }
    }
  }
}

for (const item of obj) {console.log('循环体', item)
}

使对象可能应用 for…of,残缺的代码

const obj = {store: ['foo', 'bar', 'baz'],

  [Symbol.iterator]: function () {
    let index = 0
    const self = this

    return {next: function () {
        const result = {value: self.store[index],
          done: index >= self.store.length
        }
        index++
        return result
      }
    }
  }
}

for (const item of obj) {console.log('循环体', item)
}

迭代器模式(设计模式之一)

迭代器的另外一个主要用途:迭代器模式

Gernator 生成器

参考:js 单线程机制与异步编程(Promise、Generator、Async、Await)

ES Modules

参考:工程化中的 ES Modules/CommonJS/AMD/CMD

ES2016 新增个性

数组的 includes 办法

// Array.prototype.includes -----------------------------------

const arr = ['foo', 1, NaN, false]

// 找到返回元素下标
console.log(arr.indexOf('foo'))
// 找不到返回 -1
console.log(arr.indexOf('bar'))
// 无奈找到数组中的 NaN
console.log(arr.indexOf(NaN))

// 间接返回是否存在指定元素
console.log(arr.includes('foo'))
// 可能查找 NaN
console.log(arr.includes(NaN))

指数运算符

// 指数运算符 ---------------------------------------------------

console.log(Math.pow(2, 10))

console.log(2 ** 10)

ES2017 新增个性

Object 新增办法

Object.values —— 相似 Object.keys,返回对象的值数组
Object.entries —— 以数组的模式返回对象中的键值对,联合 for…of 能够遍历 obj

const obj = {
  foo: 'value1',
  bar: 'value2'
}

// Object.values -----------------------------------------------------------

console.log(Object.values(obj))

// Object.entries ----------------------------------------------------------

console.log(Object.entries(obj))
// 比 iterator 更简略,间接先将 obj 转换成数组,再应用 for...of
for (const [key, value] of Object.entries(obj)) {console.log(key, value)
}

console.log(new Map(Object.entries(obj)))

Object.getOwnPropertyDescriptors —— 获取对象属性的残缺信息,次要配合 ES5 的 get、set 应用
Object.assign 获取不到 set、get 信息

const p1 = {
  firstName: 'Lei',
  lastName: 'Wang',
  get fullName () {return this.firstName + ' ' + this.lastName}
}

// console.log(p1.fullName)

// const p2 = Object.assign({}, p1)
// p2.firstName = 'zce'
// console.log(p2)

const descriptors = Object.getOwnPropertyDescriptors(p1)
// console.log(descriptors)
const p2 = Object.defineProperties({}, descriptors)
p2.firstName = 'zce'
console.log(p2.fullName)

String 新增办法

String.prototype.padStart / String.prototype.padEnd

const books = {
  html: 5,
  css: 16,
  javascript: 128
}

// for (const [name, count] of Object.entries(books)) {//   console.log(name, count)
// }

for (const [name, count] of Object.entries(books)) {console.log(`${name.padEnd(16, '-')}|${count.toString().padStart(3, '0')}`)
}

在函数参数中增加尾逗号

const arr = [
  100,
  200,
  300,
  400,
]
const arr = [
  100,
  200,
  300
]

新增 Async/Await 异步编程语法糖

参考资料:ecma6.0 英文标准
来自于 ES2017 规范;async、await 可能更不便的进行异步编程,且通常须要成对应用;

1、async、await 绝对于 generate 函数降级晋升的中央:

  • (1)内置执行器
  • (2)更好的语义
  • (3)更好的扩展器
  • (4)返回值是 promise

2、async、await 的返回值

  • (1)async 的返回值是 promise 对象;然而须要留神:

    1、async 函数返回一个 Promise 对象。
    2、async 函数外部 return 语句返回的值,会成为 then 办法回调函数的参数。

async function f() {return 'hello world';}

f().then(v => console.log(v))
// "hello world"
  • (2)await 返回值依据前面的参数不同而不同,有两种;

3、await 前面的参数

  • (1)await 前面跟一个 promise 对象;=> 返回 promise 对象的后果;
  • (2)await 前面跟一个值;=> 间接返回该值;

4、错误处理办法

如果 await 前面的 promise 异步操作出错,那么等同于 async 函数返回的 Promise 对象被 reject。最好把 await 命令放在 try…catch 代码块中

async function f() {await new Promise(function (resolve, reject) {throw new Error('出错了');
  });
}

f()
.then(v => console.log(v))
.catch(e => console.log(e))
async function myFunction() {
  try {await somethingThatReturnsAPromise();
  } catch (err) {console.log(err);
  }
}

// 另一种写法

async function myFunction() {await somethingThatReturnsAPromise()
  .catch(function (err) {console.log(err);
  });
}

5、并发 / 循环异步申请的解决

(1)如果是串行执行异步申请,须要同步期待,会比拟耗时;

let foo = await getFoo();
let bar = await getBar();

// 1、循环外面的串行执行:async function dbFuc(db) {let docs = [{}, {}, {}];

  for (let doc of docs) {await db.post(doc);
  }
}

// 2、谬误的串行执行:?why?思考?forEach 外面的 async 应该是异步同时执行的,没有 await?function dbFuc(db) { // 这里不须要 async
  let docs = [{}, {}, {}];

  // 可能失去谬误后果
  docs.forEach(async function (doc) {await db.post(doc);
  });
}

(2)并行执行——期待所有响应,再执行下一个步骤;

async function dbFuc(db) {let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = await Promise.all(promises);
  console.log(results);
}

// 或者应用上面的写法

async function dbFuc(db) {let docs = [{}, {}, {}];
  let promises = docs.map((doc) => db.post(doc));

  let results = [];
  for (let promise of promises) {results.push(await promise);
  }
  console.log(results);
}

(3)并行执行——不期待所有响应,回来一个回调一个;

// 能够不要在 for 外面 await;也不要写成串行的回调;// 是在 for 外面写异步办法的调用?例如:let docs = [{}, {}, {}];

  for (let doc of docs) {db.post(doc).then((res)=>{});
  }

6、async、await 原理(利用 generator 实现 async、await)

async、await 底层封装起来了看不见代码实现
能够利用 iterator 或者 generator 函数,进行封装实现;参考代码:(未完待续)

ES2019 前定义的数据类型:8 种

6+1 种原始数据类型 + bigInt(下个版本)

  1. null
  2. undefined
  3. number
  4. string
  5. boolean
  6. Symbol(ES2015)
  7. BigInt(stage-4,下个版本出标准化)

1 种援用数据类型
Object

特地鸣谢:拉勾教育前端高薪训练营

正文完
 0