乐趣区

关于javascript:javascript高级程序设计学习笔记-93代理模式

关注前端小讴,浏览更多原创技术文章

代理模式

相干代码 →

跟踪属性拜访

  • 通过捕捉 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 类型的参数
  • 应用代理写一段代码,让构造函数实例化时必须传参
  • 应用代理写一段代码,让被代理的类在实例化时增加到全局汇合
  • 应用代理写一段代码,让被代理的汇合在每次插入数据时发送音讯
退出移动版