ES6常用知识点

106 阅读7分钟

ES6常用知识点

对象字面量增强

var name = 'Fhup'
var age = 18

var obj = {
  // 1.property shorthand(属性的简写)
  name,
  age,
  // 2.method shorthand(方法的简写)
  foo(){
    console.log(this);
  },
  bar: ()=>{

  },
  // 3.computed property name(计算属性名)
  [name + '666']: 'fhf'
}

console.log(obj);

数组的解构

var arr = [1, 2, 3]

// 对数组的解构: []
var [ x, y, z ] = arr
console.log(x);
console.log(y);
console.log(z);

// babel转换后的代码
// var x = arr[0]
// var y = arr[1]
// var z = arr[2]

// 解构后面的元素(了解),第一个可以省略不写
var [ , itema, itemb] = arr
console.log(itema);
console.log(itemb);

// 解构出第一个元素,剩下的放在一个新数组中
var [item, ...newarrs] = arr
console.log(item, newarrs)

// 解构时加默认值
var [a, b, c, d = '666'] = arr
console.log(d);

对象的解构

var obj = {
  name: 'Fhup',
  age: 18,
  sex: '男'
}

// 对象的解构: {}
// 解构时用key获取值,解构时与顺序无关
var { age, sex,  name } = obj
console.log(name, age, sex);

// 解构后起别名:  用:(冒号)
var { name:myname } = obj
console.log(myname);

// 对象解构默认值
var { address: newAddress = '北京市' } = obj
console.log(newAddress)

模板字符串的使用

// ES6之前的写法
var name = 'Fhup'
var age = 18
var height = 1.88
// console.log('my name is '+ name + ', age = '+ age + ', height = '+ height)

// ES6提供模板字符串 `${}`
console.log(`my name is ${name}`);

function myAge() {
  return age / 2
}

// 可以进行计算,传函数...
console.log(`my age is ${ age * 2 }`) // 36
console.log(`my age is ${ myAge() }`) // 9

标签模板字符串的使用

// 第一个参数依然是模块字符串中整个字符串, 只是被切成多块,放到了一个数组中
// 第二个参数是模块字符串中, 第一个 ${} , 以此类推
function foo(m, n, x) {
  console.log(m, n, x, '---------')
}

foo("Hello", "World", "xxx")

// 另外调用函数的方式: 标签模块字符串
// foo``

// foo`Hello World`
const name = "why"
const age = 18

foo`Hello${name}Wo${age}rld` // [ 'Hello', 'Wo', 'rld' ] why 18

ES6参数的默认值

// 1.ES6之前的参数默认值
/**
 * 缺点:
 * 1.写起来麻烦,阅读性差
 * 2.传入0和'',会有bug.
 */
function foo(m, n) {
  m = m || 'aaa'
  n = n || 'bbb'
  console.log(m, n);
}
// foo(1)
// foo(0, '')

// 2.ES6给参数提供默认值
function bar(m = 'xxx', n = 'yyy') {
  console.log(m, n);
}
// bar()
// bar(0, '')

// 3.对象参数和默认值以及解构
function  printInfo({name} = {name: 'Fhup'}) {
  console.log(name);
}
printInfo()
printInfo({name: '666'})

// 另外一种写法,解构时给默认值
// function  printInfo2({name = 'Fhup'} = {}) {
//   console.log(name);
// }
// printInfo2()
// printInfo2({name: '666'})

// 4.有默认值的形参最好放到最后
function bar(x, y, z = 100) {
  console.log(x, y, z);
}
bar(3, 6)

// 5.获取函数的参数个数.(函数名.length)
function baz(x, y, z, q = 1, e) {}
console.log(baz.length) // 3  个数不包括有默认值和默认值后面的参数

ES6函数的剩余参数

// ...称之为前缀
/**
 * 剩余参数和arguments的区别:
 * 1.剩余参数: 包含没有对应形参的实参, 真正的数组,使用数组的所有操作
 * 2.arguments: 包含了传给函数的所有实参, 类数组,是一个对象
 * arguments是早期为了方便获取参数的一个数据结构,而剩余参数是ES6新提供的,代替arguments
 */
function bar(...args) {
  console.log(args) // 默认值为 []
  console.log(arguments); // 默认值为 [Arguments] {}
}
bar()
bar(1, 2, 3, 4, 5, 6, 7, 8, 9)

// rest paramaters 必须放在最后

箭头函数没有原型

let foo = () => {
  
}

console.log(foo.prototype) // undefined
// console.log(foo.__proto__) // {}
// console.log(Object.getOwnPropertyDescriptors(foo.__proto__));


// TypeError: foo is not a constructor  foo不是构造函数
// const f = new foo()

ES6中展开语法的使用

const names = ['aaa', 'bbb', 'ccc']
const name = 'fhf'
// 1.函数调用时
function foo(x, y, z) {
  console.log(x, y, z);
}

// foo.apply(null, names)

foo(...names)
foo(...name)

// 2.构造数组时
const newNames = [...names, 'ddd']
console.log(newNames)

// 3.对对象进行展开运算符  ES2018(ES9)
let info = { name: 'Fhup', age: 18 }
const obj = { ...info, address: '北京市' }
console.log(obj)

展开语法的浅拷贝

const info = {
  name: 'fhf',
  age: 18,
  friend: { name:'xxx' }
}

const obj = {
  ...info,
  name:'Fhup' // 后面的属性覆盖掉前面的属性
}

// 浅拷贝: 拷贝第一层,第二层保存的还是内存地址
obj.name = 'xxx'
console.log(info.name) // fhf

obj.friend.name = 'yyy'
console.log(info.friend.name) // yyy

console.log(obj);

ES6数值的表示方式

const num1 = 100 // 十进制
const num2 = 0b100 // 二进制
const num3 = 0o100 // 八进制
const num4 = 0x100 // 十六进制

console.log(num1, num2, num3, num4) // 100 4 64 256


// 大数值(ES2021 ES12)
// const num = 1000000000
const num = 1_000_000_000
console.log(num);

Symbol的使用

// 1.ES6之前,对象的属性名(key)
var obj = {
  name: 'Fhup',
  age: 18,
  friend: { name: 'fhf' }
}

// console.log(Object.keys(obj)) // [ 'name', 'age', 'friend' ] 属性名都是字符串
// obj['age'] = 12 // 添加新属性时,很容易造成冲突,覆盖原属性值
// console.log(obj) // { name: 'Fhup', age: 12, friend: { name: 'fhf' } }

// 2.ES6的Symbol解决了上面的问题
// 注意: Symbol是一个函数.直接调用它,每次生成独一无二的值(唯一)
const s1 =  Symbol()
const s2 =  Symbol()
console.log(s1 === s2) // false


// ES2019(ES10),Symbol还可以传入描述
const s3 = Symbol('aaa')
const s4 = Symbol('bbb')
// ES10新增的description
console.log(s3.description) // aaa

// 3.Symbol值作为key
// 3.1 定义时使用Symbol
const bar = {
  [s1]: 'aaa', // 用计算属性
  [s2]: 'bbb'
}
// 3.2 新增属性时这样操作
bar[s3] = 'ccc'

// 3.3 Object.defineProperty()新增属性
Object.defineProperty(bar, s4, {
  enumerable: true,
  writable: true,
  value: 'ddd',
  configurable: true
})

console.log(bar);
console.log(bar[s1], bar[s2]) // aaa bbb
// 不能通过 . 语法来获取,报错.

// 4.使用Symbol作为key,遍历/Object.keys()获取不到这些Symbol值
console.log(Object.keys(bar)) // []

// 获取所有的Symbol的key: Object.getOwnPropertySymbols
console.log(Object.getOwnPropertySymbols(bar)) // [ Symbol(), Symbol(), Symbol(aaa), Symbol(bbb) ]

const keys = Object.getOwnPropertySymbols(bar)
for(const key of keys) {
  console.log(bar[key]);
}

// 5.创建相同的Symbol值
// Symbol.for(key)创建 / Symbol.keyFor(Symbol)获取
const sa = Symbol.for('aaa')
const sb = Symbol.for('aaa')
console.log(sa === sb) // true
console.log(sa) // Symbol(aaa)

const aaa = Symbol.keyFor(sa)
const sc = Symbol.for(aaa)
console.log(sa === sc) // true

Set新增数据结构

// 1.创建Set结构
// 注意: set结构的元素不能重复
// var set = new Set()
// set.add(1)
// set.add(2)
// set.add(3)
// set.add(4)
// set.add(4)

// set.add({}) // 保存二个,指向不同的内存地址
// set.add({})

// const obj = {}
// set.add(obj) //保存一个,指向同一个内存地址
// set.add(obj)

// console.log(set)

// 2.对数组去重.
const arr = [33,22,11,33,66,99,11]
// 2.1 自己的去重方式
// let newArr = []
// for(const item of arr) {
//   if(newArr.indexOf(item) == -1) {
//     newArr.push(item)
//   }
// }
// console.log(newArr) // [ 33, 22, 11, 66, 99 ]
// 2.2 Set去重方式
const arrSet = new Set(arr)
console.log(arrSet) // Set(5) { 33, 22, 11, 66, 99 }
// 2.3 将Set结构转为数组
// const newarr = Array.from(arrSet)
const newarr = [...arrSet]
console.log(newarr) // [ 33, 22, 11, 66, 99 ]

// 3.size属性
console.log(arrSet.size) // 5

// 4.Set的方法
// add
arrSet.add(3000)
arrSet.add(7000)
// delete
const isDelete = arrSet.delete(7000) //删除时传入元素
console.log(arrSet, isDelete)
// has
console.log(arrSet.has(3000)) // true
// clear
// arrSet.clear()
// console.log(arrSet);
// 遍历
arrSet.forEach(item => {
  console.log(item);
})
for(const item of arrSet) {
  console.log(item);
}

WeakSet的使用

/**
 * WeakSet只能存放对象类型,不能存放基本数据类型.
 * 对存入的对象建立弱引用(weak refer). GC垃圾回收器回收时: 强引用不会被回收,弱引用被回收销毁.
 * Set() 建立强引用
 * WeakSet() 建立弱引用
 * 不可进行遍历
 */

const ws = new WeakSet()
const obj = {
  name: 'Fhup'
}
ws.add(obj)


// WeakSet的应用场景
const personSet = new WeakSet()
class Person{
  constructor() {
    personSet.add(this)
  }

  run() {
    if(!personSet.has(this)){
      throw new Error('不能通过非构造方法创建的对象调用run方法~')
    }
    console.log('run~~~', this);
  }
}

const p = new Person()
// p.run()

// p = null时,weakSet添加的值会自动销毁

p.run.apply(this)

Map新增数据结构

/**
 * Map: 存储映射关系
 * 对象的key为: 字符串和Symbol
 * Map的key为: 使用对象作为key,或者其他的数据类型都可以.
 */
// 1.JS的对象不能使用对象作为key的
const obj1 = { name: 'Fhup1' }
const obj2 = { name: 'Fhup2' }
// const obj = {
//   [obj1]: 'aaa',
//   [obj2]: 'bbb'
// }
// console.log(obj) // { '[object Object]': 'bbb' } 将对象转为字符串作为key,后面替换前面的
// console.log(obj[obj1]) // aaa

// 2.Map可使用对象作为key
const map = new Map()
map.set(obj1, 'aaa')
map.set(obj2, 'bbb')
map.set(1, 'ccc')
console.log(map);

// 格式: [[key, value],[key, value]]   参数类型为: entries类型
const map2 = new Map([[1,1], [2,2], [3,3]])
console.log(map2, '---') // Map(3) { 1 => 1, 2 => 2, 3 => 3 }

// 3.Map常见的属性和方法.
console.log(map.size) // 属性
// set(key)
map.set('Fhup', 'me')
console.log(map);
// get(key)
console.log(map.get('Fhup'))
// has(key)
console.log(map.has('Fhup')) // true
// delete(key)
console.log(map.delete('Fhup'))
// clear()
// map.clear()

// 4.遍历map
map.forEach((item, key) => {
  console.log(item, key);
}) 

for(const item of map) {
  console.log(item[0], item[1])
}

// 对item进行解构
for(const [key, value] of map) {
  console.log(key, value)
}

WeakMap的使用

/**
 * WeakMap: 
 * 1.key只能使用对象,不接受其他类型
 * 2.对对象的引用还是弱引用.没有其他的引用,GC可回收该对象
 * Map: 强引用, WeakMap: 弱引用
 * 不可进行遍历
 */
// const wm = new WeakMap()
// const xxx = {name: 'Fhup'}
// wm.set(xxx, 'aaa')

// // 3.常见的方法+
// console.log(wm.get(xxx)) // aaa
// console.log(wm.has(xxx)) // true
// console.log(wm.delete(xxx)) // true


// 4.应用场景(Vue3响应式原理)
const obj = {
  name: 'Fhup',
  age: 18
}

function objnameFn1() {
  console.log('objnameFn1~执行');
}
function objnameFn2() {
  console.log('objnameFn2~执行');
}
function objageFn1() {
  console.log('objageFn1~执行');
}
function objageFn2() {
  console.log('objageFn2~执行');
}
// obj中的name或者age改变时,执行下面各自的函数
// 1.先创建WeakMap()
const wm = new WeakMap()
// 2.对obj收集的数据结构
const map = new Map()
map.set('name', [objnameFn1, objnameFn2])
map.set('age', [objageFn1, objageFn2])
wm.set(obj, map)
// 3.obj.name发生改变
obj.name = '666'
const targetmap = wm.get(obj)
const fns = targetmap.get('name')
for(const fnitem of fns) {
  fnitem()
}