ECMAScript 新特性(二)

137 阅读2分钟

src=http___pic1.win4000.com_wallpaper_2018-08-15_5b73f524df035.jpg&refer=http___pic1.win4000.jfif

Proxy

优势

1.监视数据的读写

const person = {
  name: 'zce',
  age: 20
}

const personProxy = new Proxy(person, {
 deleteProperty (target, property) {
    console.log('delete', property)
    delete target[property]
  }
  // 监视属性读取
  get (target, property) {
    return property in target ? target[property] : 'default'
  },
  // 监视属性设置
  set (target, property, value) {
    if (property === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError(`${value} is not an int`)
      }
    }
    target[property] = value
}
console.log(personProxy.name) // zce
console.log(personProxy.xxx) //default
delete personProxy.age  // delete age

image.png

2.监视数组操作

const list = []

const listProxy = new Proxy(list, {
  set (target, property, value) {
    console.log('set', property, value)
    target[property] = value
    return true // 表示设置成功
  }
})

listProxy.push(100)
输出: 
set 0 100
set length 1

3.非侵入的方式监管了对象的读写

// Object.defineProperty监听特定属性
const person = {}

Object.defineProperty(person, 'name', {
  get () {
    console.log('name 被访问')
    return person._name
  },
  set (value) {
    console.log('name 被设置')
    person._name = value
  }
})
Object.defineProperty(person, 'age', {
  get () {
    console.log('age 被访问')
    return person._age
  },
  set (value) {
    console.log('age 被设置')
    person._age = value
  }
})

person.name = 'jack'

// Proxy可以对整个对象的属性进行监管,不需要指定特定的属性
const personProxy = new Proxy(person, {
  get (target, property) {
    console.log('get', property)
    return target[property]
  },
  set (target, property, value) {
    console.log('set', property, value)
    target[property] = value
  }
})

personProxy.name = 'jack'

Reflect(统一的对象操作API)

  • 是一个静态类
  • 统一提供了一套用于操作对象的API(13种)
const obj = {
  name: 'zce',
  age: 18
}

'name' in obj  等同于  Reflect.has(obj, 'name')
delete obj['age']  等同于  Reflect.deleteProperty(obj, 'age')
Object.keys(obj)  等同于  Reflect.ownKeys(obj)
// 其他方法继续深究

class类

  • 基本用法
 class Person {
  constructor (name) {  // 构造函数
    this.name = name
  }
  say () {  // 实例方法,通过实例对象去调用
    console.log(this); // Person { name: 'tom' } this指向的某一个实例对象
    console.log(`hi, my name is ${this.name}`)
  }
  static create (name) {  // 静态方法(static),通过类型本身去调用,
    console.log(this);   // [Function: Person]   this指向的是当前的类型
    return new Person(name)
      }
}
const tom = Person.create('tom')
tom.say()
  • extends继承
// 继承父类就拥有了父类的所有成员
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) // 调用父类构造函数
    this.number = number
  }

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

const s = new Student('jack', '100')
s.hello()
输出:
hi, my name is jack
my school number is 100

Set

  • 不接受重复的数据,可用于去重
  • add方法可进行链式调用
  • 遍历采用forEach或者是for...of
  • size获取长度
  • has判断集合当中是否存在某个特定的值
  • delete 删除集合中某个指定的值,删除成功返回true
  • clear清除所有值
const s = new Set()

s.add(1).add(2).add(3).add(4).add(2)
console.log(s)  //  Set { 1, 2, 3, 4 }
s.forEach(i => console.log(i))
for (let i of s) {
  console.log(i)
}
console.log(s.size)  // 4
console.log(s.has(100))  // false
console.log(s.delete(3))  // true
s.clear()
  • 数组去重

const arr = [1, 2, 1, 3, 4, 1]
const result = [...new Set(arr)]  // [1,2,3,4]

弱引用版本 WeakSet
差异 :
Set 中会对所使用到的数据产生引用,即便这个数据在外面被消耗,由于Set 引用了这个数据,所以依然不会回收;
而 WeakSet 的特点就是不会产生引用, 一旦数据销毁,就可以被回收,所以不会产生内存泄漏问题。

Map

  • 用来映射两个任意类型数据之间的对应关系
  • Map的键可以是任意类型的,而对象的键只能是字符串类型
const m = new Map()
const tom = { name: 'tom' }
m.set(tom, 90)  // 键为对象

m.has() // 判断某个键是否存在
m.delete() // 删除某个键
m.clear() // 清空

Symbol

  • 解决属性名冲突的问题
  • 两个 Symbol 永远不会相等
  • 使用 Symbol 为对象添加唯一不重复的键
  • 模拟实现私有成员
console.log(Symbol() === Symbol())  // false
Symbol('foo') // foo为描述的文本
const obj = {
  [Symbol()]: 123  // 计算属性名
}

const name = Symbol()
const person = {
  [name]: 'zce',  // 私有成员
  say () {
    console.log(this[name])
  }
}

person[Symbol()] // 由于无法创建一样的Symbol值,无法直接访问到 person 中的「私有」成员
person.say()

BigInt类型用于存放更长的数据,总共有8种数据类型

  • Symbol.for 相同的字符串返回相同的Symbol值
const s1 = Symbol.for('foo')
const s2 = Symbol.for('foo')
console.log(s1 === s2)

 Symbol.for(true) === Symbol.for('true')  // true 都会转成字符串
  • 内置 Symbol 常量
console.log(Symbol.iterator)  // Symbol(Symbol.iterator)
console.log(Symbol.hasInstance) // Symbol(Symbol.hasInstance)

// 自定义toString标签
const obj = {
   [Symbol.toStringTag]: 'XObject'
}
console.log(obj.toString())  // [object XObject]
  • 通过getOwnPropertySymbols获取对象中Symbol属性
const obj = {
  [Symbol()]: 'symbol value',
  foo: 'normal value'
}

for (var key in obj) {  // 遍历不出来Symbol的属性
  console.log(key)
}
console.log(Object.keys(obj)) // 获取不到Symbol属性
console.log(JSON.stringify(obj)) // 获取不到Symbol属性

console.log(Object.getOwnPropertySymbols(obj))