《javascript高级程序设计》学习笔记 | 9.3.代理模式

Posted 小讴

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了《javascript高级程序设计》学习笔记 | 9.3.代理模式相关的知识,希望对你有一定的参考价值。

关注前端小讴,阅读更多原创技术文章

代理模式

相关代码 →

跟踪属性访问

  • 通过捕获getsethas等操作,可以监控对象何时何处被访问过
const user = {
  name: \'Jake\',
}
const proxy = new Proxy(user, {
  get(target, property, receiver) {
    console.log(`Getting ${property}`)
    return Reflect.get(...arguments)
  },
  set(target, property, value, receiver) {
    console.log(`Setting ${property}=${value}`)
    return Reflect.set(...arguments)
  },
})
proxy.name // \'Getting name\',触发get()拦截
proxy.age = 27 // \'Setting age=27\',触发set()拦截

隐藏属性

  • 代理的内部实现对外部代码不可见,可隐藏目标对象的指定属性
const hiddenProperties = [\'foo\', \'bar\'] // 要隐藏的键
const targetObject = {
  // 目标对象
  foo: 1,
  bar: 2,
  baz: 3,
}
const proxy2 = new Proxy(targetObject, {
  get(target, property) {
    if (hiddenProperties.includes(property)) {
      return undefined // 隐藏属性
    } else {
      return Reflect.get(...arguments)
    }
  },
  has(target, property) {
    if (hiddenProperties.includes(property)) {
      return undefined // 隐藏属性
    } else {
      return Reflect.get(...arguments)
    }
  },
})

// get()拦截
console.log(proxy2.foo) // undefined,在代理内部被隐藏
console.log(proxy2.bar) // undefined,在代理内部被隐藏
console.log(proxy2.baz) // 3

// has()拦截
console.log(\'foo\' in proxy2) // false,在代理内部被隐藏
console.log(\'bar\' in proxy2) // false,在代理内部被隐藏
console.log(\'baz\' in proxy2) // true

属性验证

  • 所有的赋值操作都会触发set()捕获器,可根据所赋的值决定允许还是拒绝赋值
const target = {
  onlyNumberGoHere: 0,
}
const proxy3 = new Proxy(target, {
  set(target, property, value) {
    if (typeof value !== \'number\') {
      return false
    } else {
      return Reflect.set(...arguments)
    }
  },
})
proxy3.onlyNumberGoHere = 1 // 拦截操作,所赋的值为Number类型
console.log(proxy3.onlyNumberGoHere) // 1,赋值成功
proxy3.onlyNumberGoHere = \'2\' // 拦截操作,所赋的值为String类型
console.log(proxy3.onlyNumberGoHere) // 1,赋值失败

函数与构造函数参数验证

  • 可对函数和构造函数参数进行审查,让函数只接收某数类型的值
function median(...nums) {
  return nums.sort()[Math.floor(nums.length / 2)]
}
const proxy4 = new Proxy(median, {
  apply(target, thisArg, argumentsList) {
    for (const arg of argumentsList) {
      if (typeof arg !== \'number\') {
        // 只接收Number类型
        throw \'Non-number argument provided\'
      }
    }
    return Reflect.apply(...arguments)
  },
})
console.log(proxy4(4, 7, 1)) // 4
console.log(proxy4(4, 7, \'1\')) // Error: Non-number argument provided
  • 可要求实例化时必须给构造函数传参
class User {
  constructor(id) {
    this._id = id
  }
}
const proxy5 = new Proxy(User, {
  construct(target, argumentsList, newTarget) {
    if (argumentsList[0] === undefined) {
      // 必须传参
      throw \'User cannot be instantiated without id\'
    }
    return Reflect.construct(...arguments)
  },
})
new proxy5(1)
// new proxy5() // Error: \'User cannot be instantiated without id\'

数据绑定与可观察对象

  • 通过代理把运行时原本不相关的部分联系到一起:可将被代理的类绑定到一个全局集合,让所有创建的实例都被添加到该集合中
const userList = []
class User2 {
  constructor(name) {
    this._name = name
  }
}
const proxy6 = new Proxy(User2, {
  construct() {
    const newUser = Reflect.construct(...arguments)
    userList.push(newUser) // 将实例添加到全局集合
    return newUser
  },
})
new proxy6(\'John\')
new proxy6(\'Jacob\')
new proxy6(\'Jake\')
console.log(userList) // [ User2 { _name: \'John\' }, User2 { _name: \'Jacob\' }, User2 { _name: \'Jake\' } ]
  • 可把集合绑定到一个事件分派程序,每次插入新实例时发送消息
const eventList = []
function emit(newValue) {
  console.log(newValue)
  /* 
    John
    Jacob
  */
}
const proxy7 = new Proxy(eventList, {
  set(target, property, value, receiver) {
    console.log(target, property, value)
    /* 
      [] 0 John
      [ \'John\' ] length 1
      [ \'John\' ] 1 Jacob
      [ \'John\', \'Jacob\' ] length 2
    */
    const result = Reflect.set(...arguments)
    if (result && property !== \'length\') {
      emit(value)
    }
    return result
  },
})
proxy7.push(\'John\')
proxy7.push(\'Jacob\')

总结 & 问点

  • 使用代理写一段代码,监控对象在何时何处被访问
  • 使用代理写一段代码,隐藏目标对象的指定属性
  • 使用代理写一段代码,根据所赋的值决定允许或拒绝给对象赋值
  • 使用代理写一段代码,让函数只接收 String 类型的参数
  • 使用代理写一段代码,让构造函数实例化时必须传参
  • 使用代理写一段代码,让被代理的类在实例化时添加到全局集合
  • 使用代理写一段代码,让被代理的集合在每次插入数据时发送消息

以上是关于《javascript高级程序设计》学习笔记 | 9.3.代理模式的主要内容,如果未能解决你的问题,请参考以下文章

JavaScript 高级程序设计学习笔记

javascript 高级程序设计 学习笔记01章 javascript的认知

1 《JavaScript高级程序设计》学习笔记

《JavaScript高级程序设计(第四版)》学习笔记第3章

《JavaScript高级程序设计(第四版)》学习笔记第3章

JavaScript高级程序设计(第三版)学习笔记222425章