defineProperty 与 proxy

Object.defineProperty(obj, prop, descriptor)

  • obj: 要在定义属性的对象。
  • prop: 要定义或修改的属性的名称(也就是我们熟称的key)。
  • descriptor: 将被定义或修改的属性的描述符。

descriptor一览属性

  • configurable: (可配置属性) 默认为true (能否通过delete删除属性,如果为false的话,下次就不能在配置,会报错)
  • Enumerable: (可枚举属性) 默认true (能否通过for in 循环返回属性)
  • writable: (可以填写属性) 默认true (表示能否修改属性的值)
  • value:(值属性)默认undefined (写入的值会保存在这里)
  • set(): 设置值的时候会触发
  • get():获取值的时候会触发
  • 注意事项:
    1、通过objec.difneproperty创建的属性,只设置了value,那么它其他属性默认都为false,
    2、如果是通过访问属性,set和get 创建,configurable: false enumerable: false
    3、使用get 、set用它就不能出现 wriable 、value
    4、使用wriable || value中的任何一 个,就不能出现set 和 get
/**
 * 第一个例子
*/
var obj = {};
// 给obj 添加一个num属性
Object.defineProperty(obj, "num", {
    value : 1,
    writable : true,
    enumerable : true,
    configurable : true
});
console.log(obj)  // {num:1}
obj.num = 2
console.log(obj)  // {num:2}
// 给obj 继续添加str 属性
Object.defineProperty(obj, "str", {
    value : 'A',
});
obj.str = 'B'
console.log(obj)  // {num: 2, str: "A"}  你会发现str 并没有被改变, 注意:这里如果只设置了value, 其它特性属性默认都false

/**
 * 第二个例子
*/
let obj1 = { // 这种声明的对象,特性属性默认都是false
  name: '张三',
  age: 19
} 
// 给已有的元素的对象,修改特性属性
Object.defineProperty(obj1,'name',{
  configurable: false  
})
delete obj1.name  // 删除name属性
console.log(obj1) //{name: "张三", age: 19}  你会发现name并没有被删除,说明特性属性是生效的。

/**
 * 第三个例子
*/
let obj2 = {
  name:'李四',
  age: '20'
}
let Val = ''
Object.defineProperty(obj2,'age',{
  get(){
   return Val // 获取触发
  },
  set(newVal){
    console.log(newVal)
    Val = newVal  // 修改或设置触发
    // obj2['age'] = newVal   注意这里不能这样写,会一直死循环下去,因为每次修改都会触发set
  }
})
obj2.age = 18
console.log(obj2)

/**
 * 第四个例子
*/
/**
 * 利用set和get的特性实现一个监听对象属性变换函数
 * @obj  监听的对象
 * @keyName 监听的对象属性key名称
 * @callback 成功监听到属性变换后的回调函数
*/
function watchFn(obj,keyName,callback){
  // 初始化值
  let val = obj[keyName]
  
  // 核心
  Object.defineProperty(obj,keyName,{
    get(){
      return val
    },
    set(newVal){
      // 返回给回调
      callback(newVal,val)
      // 改变属性
      val = newVal
    }
  })
}
// 创建一个对象来监听它
let obj3 = {
  name: 'xiaoji',
  age: 19
}

// 监听函数 
watchFn(obj3,'name',function(newVal,oldVal){
  console.log(newVal,oldVal)
})

// 为了更好的体验,使用了异步函数

setTimeout(function(){
  obj3.name = 'AAA'
},2000)

proxy

  • Proxy 可以理解成,在目标对象之前架设一层“拦截”,外界对该对象的访问,都必须先通过这层拦截,因此提供了一种机制,可以对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操作,可以译为“代理器”。
let obj = { // 这里可以代理数组 || 对象 || 函数
  name: 'xiaji',
  age: 19,
  _link: '写代码'
}
obj = new Proxy(obj,{
  // 获取值的时候做拦截
  get(target,prop){
    // console.log(target,prop)
    // 拿到参数后,可以做你要拦截的事情,最后return 出去
    return prop in target? target[prop]:prop
  },
  set(target,prop,val){
    // console.log(target,prop,val)
    target[prop] = val
    return true
  },
  ownKeys(target){
    // console.log(target)
    // 拦截所有前缀为_的属性
    return Object.keys(target).filter(item => !item.startsWith('_'))
  }
  //.....一共有13种拦截就不一一举例了,自己动手了解,比看代码强!
});
console.log(obj.AA) // AA   拦截的钩子函数是:get
obj.age = 20  
console.log(obj.age) // 20  拦截的钩子函数是:set
console.log(Object.keys(obj))  //  ["name", "age"]    拦截的钩子函数是:ownKeys
});

钩子函数

  • 钩子函数 :一共 13 种。
  • get(target, propKey, receiver):拦截对象属性的读取,比如proxy.foo和proxy[‘foo’]。
  • set(target, propKey, value, receiver):拦截对象属性的设置,比如proxy.foo = v或proxy[‘foo’] = v,返回一个布尔值。
  • has(target, propKey):拦截propKey in proxy的操作,返回一个布尔值。
  • deleteProperty(target, propKey):拦截delete proxy[propKey]的操作,返回一个布尔值。
  • ownKeys(target):拦截Object.getOwnPropertyNames(proxy)、Object.getOwnPropertySymbols(proxy)、Object.keys(proxy)、for…in循环,返回一个数组。该方法返回目标对象所有自身的属性的属性名,而Object.keys()的返回结果仅包括目标对象自身的可遍历属性。
  • getOwnPropertyDescriptor(target, propKey):拦截Object.getOwnPropertyDescriptor(proxy, propKey),返回属性的描述对象。
  • defineProperty(target, propKey, propDesc):拦截Object.defineProperty(proxy, propKey, propDesc)、Object.defineProperties(proxy, propDescs),返回一个布尔值。
  • preventExtensions(target):拦截Object.preventExtensions(proxy),返回一个布尔值。
  • getPrototypeOf(target):拦截Object.getPrototypeOf(proxy),返回一个对象。
  • isExtensible(target):拦截Object.isExtensible(proxy),返回一个布尔值。
  • setPrototypeOf(target, proto):拦截Object.setPrototypeOf(proxy, proto),返回一个布尔值。如果目标对象是函数,那么还有两种额外操作可以拦截。
  • apply(target, object, args):拦截 Proxy 实例作为函数调用的操作,比如proxy(…args)、proxy.call(object, …args)、proxy.apply(…)。
  • construct(target, args):拦截函数调用 Proxy 实例作为构造函数调用的操作,比如new proxy(…args)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值