跳过

ES6新特性

发布时间: at 00:44
本文收录在以下合集中:

ES6,全称是 ECMAScript 6,也被称为 ECMAScript 2015,是 JavaScript 的一种标准,于 2015 年正式发布。ES6 是 JavaScript 新一代标准的缩写,引入了很多新的语法和特性,丰富了 JavaScript 的功能和表现力,提升了开发效率。

新特性

1 let和const

引入了块级作用域的变量声明方式,用于替代 var 关键字。

与var区别:不能重复声明,只会在作用域内生效,没有变量提升。

let a = 1 // 声明变量

const PI = 3.14 // 声明常量

2 箭头函数

新的函数声明方式,可以更简洁地编写函数表达式。

// ES6 允许使用  =>  定义函数
//声明函数
let fn = (a, b) => {
  return a + b
}
//调用函数
console.log(fn(1, 2))

箭头函数中 this 是静态的, this 始终指向函数声明时所在作用域下的 this 的值

function getName() {
  console.log(this.name)
}

let getName2 = () => {
  console.log(this.name)
}

// 设置 window对象 的 name 属性
window.name = 'xxyyzz'
const school = {
  name: 'qinghua',
}

getName() // this 指向 window 输出 xxyyzz
getName2() // this 指向 window 输出 xxyyzz

getName.call(school) // 结果是qinghua
getName2.call(school) // 结果还是 xxyyzz

不能作为构造实例化对象

let Person = (name, age) => {
  this.name = name
  this.age = age
}
let person = new Person('xxyyzz', 18)
console.log(person)
// 报错: Person is not a constructor

不能使用 arguments 变量

let fn1 = () => {
  console.log(arguments)
}
fn1(1, 2, 3)
// 报错: arguments is not defined

简写

// 1. 只有一个参数省略括号
let add = n => {
  return n + n
}

// 2. 只有一个return省略花括号
let pow = n => n * n

// 3. 返回对象简写
const fn = uname => ({uname: uname})

3 模板字符串

用反引号(“)来创建多行字符串和插入变量。

// 1. 变量
const hello = 'hello'
const world = 'world'
console.log(`${hello} ${world}`) // hello world

// 2. 字符
let str2 = `<ul>
              <li>1</li>
              <li>2</li>
            </ul>`
console.log(str2)

// 3. 表达式
let a = 3
let b = 4
let str3 = `${a + b}`
console.log(str3)

4 默认参数

在函数声明时可以为参数设置默认值。

function add(a, b, c = 10) {
  return a + b + c
}
let result = add(1, 2)

console.log(result) // 13

// 2. 可以与结构赋值结合
function connect({host = '127.0.0.1', username, password, port}) {
  console.log(host)
  console.log(username)
  console.log(password)
  console.log(port)
}

connect({
  host: 'localhost',
  username: 'root',
  password: 'root',
  port: 3306,
})

5 解构赋值

可以通过解构语法从数组或对象中提取值并赋给变量。

// 1. 数组
const F4 = ['xx', 'yy', 'zz', 'kk']
let [x, y, z, k] = F4
console.log(x) // xx
console.log(y) // yy
console.log(z) // zz
console.log(k) // kk

// 2. 对象
const zs = {
  name: '张三',
  age: 18,
  sing: function () {
    console.log('我会唱歌')
  },
}

let {name, age, sing} = zs // 需要用大括号
console.log(name) // 张三
console.log(age) // 18
console.log(sing) // Function

sing() // 我会唱歌

// 3. 多维解构
const dog = {
  name: 'Gallagher',
  attr: {
    age: 13,
    birth: 'Pinocorni',
  },
}

const {
  name,
  attr: {age, birth},
} = dog

console.log(name) // Gallagher
console.log(age) // 13
console.log(birth) // Pinocorni

6 类关键字class

引入了 class 关键字,可以更方便地创建基于原型的面向对象编程。

ES5中:

// 手机
function Phone(brand, price) {
  this.brand = brand
  this.price = price
}

// 添加方法
Phone.prototype.call = function () {
  console.log('正在呼叫...')
}

// 实例化对象
let honor = new Phone('荣耀', 2499)
console.log(honor)
honor.call()

ES6中:

class Phone {
  // 构造方法
  constructor(brand, price) {
    // constructor 名字不能修改,是固定的
    this.brand = brand
    this.price = price
  }
  // 添加方法,(方法必须使用该语法)
  call() {
    console.log('华为手机正在呼叫...')
  }
}

// 实例化对象
let honor = new Phone('华为', 2499)
console.log(honor)
honor.call()

静态成员

// 类的静态成员
class Phone {
  static name = 'nojiya'
  static change = function () {
    console.log('我可以改变你们')
  }
}

let phoneSHI = new Phone()
console.log(phoneSHI)
console.log(phoneSHI.name) // undefined
console.log(Phone.name) // nojiya
console.log(Phone.change)

类继承

// ES6中使用class实现类继承
// 手机
class Phone {
  constructor(brand, price) {
    this.brand = brand
    this.price = price
  }
  call() {
    console.log('正在呼叫...')
  }
}

// 智能手机
// extends关键字
class SmartPhone extends Phone {
  constructor(brand, price, color, size) {
    super(brand, price) //super 关键字用于调用父类的构造函数或方法。
    this.color = color
    this.size = size
  }
  photo() {
    console.log('正在拍照...')
  }
}

// 测试
let s = new SmartPhone('荣耀', 1399, '银色', '4.2inch')
console.log(s)
s.call()
s.photo()

class 中的 get 和 set

class Phone {
  get price() {
    console.log('price属性被读取了')
    return 'iloveyou'
  }
  set price(newVal) {
    console.log('price属性被修改了')
  }
}

// 实例化对象
let s = new Phone()
console.log(s.price)

// 赋值
s.price = 'free'

7 Promise

用于处理异步操作的新标准,避免回调地狱的问题。可以返回新的Promise链式调用。

// 创建Promise对象
const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  })
})

// Promise.then
promise.then(value => {
  console.log(value)
})

console.log(result)

// Promise.catch
const promise2 = new Promise((resolve, reject) => {
  setTimeout(() => {
    reject('出错啦!')
  }, 1000)
})

promise2.catch(reason => {
  console.warn(reason)
})

8 模块化

引入了 import 和 export 关键字,提供了更好的模块化管理方式。

  1. 暴露:export
  2. 导入:import

9 扩展运算符...

用三个点(…)可以将数组或对象展开成分散的值。

const boys = ['张三', '李四', '王五']

// 声明一个函数
function show() {
  console.log(arguments)
}
show(...boys) // ['张三', '李四', '王五']

// 案例:合并数组
const arr1 = [1, 2, 3]
const arr2 = [4, 5, 6]

const arr = [...arr1, ...arr2]
console.log(arr) // [1, 2, 3, 4, 5, 6]

10 简化对象声明

可以直接写属性名,而无需写键和值。

let name = '张三'
let change = function () {
  console.log('这是一个方法')
}
const sch = {
  // 1. 定义对象的简写形式
  // 2. 省略了属性值和冒号
  name, // 旧版 name: name
  change, // 旧版 change: change
  // 3.方法前面省略了function关键字
  improve() {
    // 旧版improve: function() {
    console.log('这是一个方法')
  },
}
console.log(sch)

11 rest 参数

rest参数获取剩余的所有参数,只能放在最后,返回一个参数数组

function date1(...args) {
  console.log(args)
}
date1('2021-10-10', '2021-10-11', '2021-10-12') // 得到的是数组

12 生成器函数

通过 function*yield 关键字实现的一种可暂停和恢复执行的函数。

写法的特殊地方就是需要加个 * 星号,靠左,靠右,中间都行

function* gen() {
  console.log('hello generator')
}

let iterator = gen()
console.log(iterator)

yield可以看成是函数代码的分隔符,通过next方法来控制执行

function* gen() {
  console.log('111')
  yield '我是1' // yield为函数代码的分隔符
  console.log('222')
  yield '我是2'
  console.log('333')
  yield '我是3'
  console.log('444')
}

let iterator = gen()
console.log(iterator)
iterator.next() // 111
iterator.next() // 222
iterator.next() // 333
iterator.next() // 444

生成器参考

function* gen(arg) {
  console.log(arg)
  let re1 = yield 111
  console.log(re1)
  let re2 = yield 222
  console.log(re2)
  let re3 = yield 333
  console.log(re3)
}

// 执行获取迭代器对象
let iterator = gen('AAA')
console.log(iterator.next())

// next方法可以传入实参
console.log(iterator.next('BBB')) // 第二次调用传入的参数,将作为第一个yield语句的返回结果
console.log(iterator.next('CCC')) // 第三次调用传入的参数,将作为第二个yield语句的返回结果
console.log(iterator.next('DDD')) // 第四次调用传入的参数,将作为第三个yield语句的返回结果

解决地狱回调

// 地狱回调
setTimeout(() => {
  console.log(111)
  setTimeout(() => {
    console.log(222)
    setTimeout(() => {
      console.log(333)
    }, 3000)
  }, 2000)
}, 1000)

// 解决后
function one() {
  setTimeout(() => {
    console.log(111)
    iterator.next() // 执行下一个任务
  }, 1000)
}

function two() {
  setTimeout(() => {
    console.log(222)
    iterator.next()
  }, 2000)
}

function three() {
  setTimeout(() => {
    console.log(333)
    iterator.next()
  }, 3000)
}

// 定义生成器函数
function* gen() {
  yield one()
  yield two()
  yield three()
}

// 调用生成器函数
let iterator = gen()
iterator.next()

13 Map和Set

新的数据结构,提供了更方便的数据存储和操作方式。

Map 键值对集合

let myMap = new Map()

// 添加键值对(元素)
myMap.set('name', '张三')
myMap.set('age', 18)

let key = {
  school: 'university',
}
myMap.set(key, ['清华大学', '北京大学'])
console.log(myMap)

// 获取Map中的元素个数
console.log(myMap.size)

// 删除元素
myMap.delete('age')
console.log(myMap)

// 获取元素
console.log(myMap.get('name'))
console.log(myMap.get(key))

// 判断Map中是否存在某个元素
console.log(myMap.has('name'))
console.log(myMap.has('age'))

// 遍历Map
for (let v of myMap) {
  console.log(v)
}

// 清空Map
myMap.clear()
console.log(myMap)

Set 不重复集合

let mySet = new Set()
console.log(mySet)
console.log(typeof mySet)

let mySet2 = new Set(['好事', '坏事', '大事', '好事']) // 自动去重
console.log(mySet2)

// 元素个数
console.log(mySet2.size)

// 添加元素
mySet2.add('小事')
console.log(mySet2)

// 删除元素
mySet2.delete('坏事')
console.log(mySet2)

// 检测是否有该元素
console.log(mySet2.has('大事')) // 返回结果是boolean类型

// 清空set
mySet2.clear()
console.log(mySet2)

// 遍历Set:  集合实现了iterator接口,所以可以使用for...of进行遍历
for (let item of mySet2) {
  console.log(item)
}

14 Symbol

ES6(ECMAScript 2015)引入了一种新的原始数据类型 Symbol。Symbol 是一种独一无二且不可变的数据类型,每个通过 Symbol 函数创建的 Symbol 值都是唯一的,即使符号名相同也不会相等。Symbol 主要用于对象属性的标识符,可以作为对象的属性名,用来解决属性名冲突的问题。

下面是 Symbol 的一些特点和用法:

  1. 独一无二性:每个 Symbol 值都是唯一的,不会与其他的 Symbol 值相等。这使得 Symbol 可以用作对象的属性名,保证属性的唯一性。

  2. 不可改变性:Symbol 是不可变的,一旦创建就不能修改其值。

  3. Symbol 作为对象属性名:使用 Symbol 作为对象的属性名,可以确保属性不会被意外覆盖。可以通过 Symbol() 方法创建一个 Symbol 值,然后作为属性名定义在对象中。

  4. 内置 Symbol 值:ES6 提供了一些预定义好的 Symbol 值,如 Symbol.iteratorSymbol.toStringTag 等,用于标识特定行为,可以在对象上使用这些 Symbol 值进行定制。

  5. Symbol.for() 和 Symbol.keyFor():ES6 还提供了两个与全局 Symbol 相关的静态方法 Symbol.for() 和 Symbol.keyFor()。Symbol.for() 方法接收一个字符串作为参数,如果存在相同字符串的 Symbol 值则返回,否则新建一个;Symbol.keyFor() 方法则是返回与 Symbol 关联的键。

// 1. 创建Symbol
let s = Symbol()
console.log(s, typeof s) // Symbol() 'symbol'

// 2. 每一个都是独一无二的
let s2 = Symbol('张三')
let s3 = Symbol('张三')

console.log(s2, s3)
console.log(s2 === s3) // false

// 3. Symbol.for 创建可以得出相同值
let s4 = Symbol.for('李四')
let s5 = Symbol.for('李四')

console.log(s4, s5)
console.log(s4 === s5) // true

// 4. 作为对象属性
let info = {
  name: '张三',
  [Symbol('age')]: 20,
  [Symbol('say')]: function () {
    console.log('我要说话了!')
  },
}

15 迭代器

ES6 引入了迭代器(Iterator)的概念,迭代器是一种能够让我们遍历数据结构的方法。通过迭代器,我们可以按照特定顺序逐个访问数据结构中的元素,而不必关心数据结构的具体实现细节。

下面是关于 ES6 迭代器的一些重要信息和特点:

  1. 迭代器协议:ES6 迭代器是基于迭代器协议(Iterator Protocol)实现的,在一个对象上部署了 Symbol.iterator 方法,该对象就被视为可迭代对象(iterable),可以通过迭代器进行遍历。

  2. 迭代器对象:迭代器对象必须具有一个 next() 方法,每次调用 next() 方法后都会返回一个包含 value 和 done 两个属性的对象,value 表示下一个元素的值,done 表示是否遍历结束。

  3. 可迭代对象:实现了迭代器协议的对象被称为可迭代对象,例如数组、字符串、Map、Set 和自定义对象等,它们可以通过 for…of 循环、展开运算符(…)、解构赋值等方式进行遍历。

  4. Symbol.iterator 方法:可迭代对象都会具有一个 Symbol.iterator 方法,调用该方法会返回一个迭代器对象,从而实现迭代访问。

  5. for…of 循环:ES6 引入的 for…of 循环可以遍历可迭代对象,自动调用迭代器的 next() 方法,简化了遍历操作。

  6. 内置数据结构:ES6 的内置数据结构如数组、Map、Set 等都实现了迭代器协议,因此可以直接使用 for…of 循环来遍历这些数据结构。

迭代器工作原理:

  1. 创建一个指针对象,指向当前数据结构的起始位置。也就是说,遍历器对象本质上,就是一个指针对象。

  2. 第一次调用指针对象的next方法,可以将指针指向数据结构的第一个成员。

  3. 第二次调用指针对象的next方法,指针就指向数据结构的第二个成员。

  4. 不断调用指针对象的next方法,直到它指向数据结构的结束位置。

  5. 每一次调用next方法都会返回一个包含value和done两个属性的对象。其中,value属性是当前成员的值,done属性是一个布尔值,表示遍历是否结束。

// 1. for...of
const arr = [1, 2, 3, 4, 5]
for (let element of arr) {
  console.log(element)
  // 输出:1 2 3 4 5
}

// 2. 迭代器
const arr = [1, 2, 3, 4, 5]
let iterator = arr[Symbol.iterator]()

console.log(iterator.next()) // { value: 1, done: false }
console.log(iterator.next()) // { value: 2, done: false }
console.log(iterator.next()) // { value: 3, done: false }
console.log(iterator.next()) // { value: 4, done: false }
console.log(iterator.next()) // { value: 5, done: false }
console.log(iterator.next()) // { value: undefined, done: true }

// 3. 自定义迭代器
// 声明一个对象
const banji = {
  name: '终极一班',
  stus: ['xiaoming', 'xiaoning', 'xiaotian', 'knight'],
  [Symbol.iterator]() {
    // 索引变量
    let index = 0
    return {
      next: () => {
        if (index < this.stus.length) {
          // 构建一个yield返回值
          const result = {value: this.stus[index], done: false}
          // 下标自增
          index++
          return result
        }
        // 返回结束标志
        return {value: undefined, done: true}
      },
    }
  },
}

for (let v of banji) {
  console.log(v)
}

16 数值扩展

  1. Number.EPSILON 是JavaScript表示的最小精度, EPSILON 属性的值接近于 2.2204460492503131e-16
  2. 引入进制
  3. Number.isFinite()
  4. Number.isNaN()
  5. Number.parserInt()、Number.parseFloat(),将字符串转为整数(浮点数)
  6. Number.isInteger(),判断一个数是否为整数
  7. Math.trunc(),将数字的小数部分抹掉
  8. Math.sign(),判断一个数是正数、负数、还是零,返回:1,-1
// 1. EPSILON 属性的值接近于 2.2204460492503131e-16
function equal(a, b) {
  if (Math.abs(a - b) < Number.EPSILON) {
    return true
  } else {
    return false
  }
}
console.log(0.1 + 0.2) // 0.30000000000004
console.log(0.1 + 0.2 === 0.3) // false
console.log(equal(0.1 + 0.2, 0.3)) // true

// 2. 二进制、八进制、十进制、十六进制
let b = 0b10
let o = 0o10
let d = 10
let x = 0x10
console.log(b, o, d, x) // 2 8 10 16

// 3. 判断极大数
function isFinite(num) {
  return Number.isFinite(num)
}
console.log(isFinite(5)) // true
console.log(isFinite(5.0)) // true
console.log(isFinite(5.1)) // true
console.log(isFinite(Infinity)) // false

// 4. 判断NaN
function isNaN(num) {
  return Number.isNaN(num)
}
console.log(isNaN(5)) // false
console.log(isNaN(NaN)) // true

17 对象方法扩展

  1. Object.is 对象是否完全相等
  2. Object.assign 对象的合并
  3. Object.setPrototypeOf 设置原型对象
  4. Object.getPrototypeOf 获取原型对象

转化

并不是所有的浏览器都能向chrome一样都能识别ES6新特性,所以需要进行转换

# 安装工具: babel-cli babel-preset-env browserify
npm i babel-cli babel-preset-env browserify -D
npx babel src/js -d dist/js --presets=babel-preset-env
npx browserify dist/js/app.js -o dist/bundle.js

参考

ES6 新特性(0基础,精简版,学ES6看这篇就够了!!!)

ES6(ECMAScript 2015)