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)