一、Object.defineProperty是什么?
Object.defineProperty 是ES5Proxy 为开发者提供JavaScript已有却不能调用的功能,在ES5之前,js环境中的对象包含许多不可枚举和可枚举的属性,但是开发者不能自己定义可枚举和不可枚举,于是ES5引入了Object.definePeoperty()方法来支持去做js引擎早就可以实现的事情
1.Object.defineProperty 参数
Object.defineProperty(obj, prop, descriptor)
- obj 要定义的对象
- prop 要定义或修改的属性的名称或 Symbol
- descriptor要定义或修改的属性描述符。
使用 Object.defineProperty() 添加的属性值是不可修改的
代码如下(示例):
let obj = {};
let newObj = Object.defineProperty(obj, "OBJ", {
value: { a: 1, b: 2, c: 3 },
});
obj === newObj // true
newObj.OBJ // { a: 1, b: 2, c: 3 }
//使用 Object.defineProperty() 添加的属性值是不可修改的
newObj.OBJ = 111;
newObj.OBJ // { a: 1, b: 2, c: 3 }
// 不可枚举的
添加的属性值是不可修改的
let obj = {};
let newObj = Object.defineProperty(obj, "b", {
value: { a: 1},
});
newObj.b // {a:1}
newObj.b = 123
newObj.b // {a:1}
添加的属性值是不可修改的怎么变为可修改?
当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符改变。
默认为 false。
let obj = {};
let newObj = Object.defineProperty(obj, "b", {
value: { a: 1},
writable: true,
});
newObj.b // {a:1}
newObj.b = 123
newObj.b // 123
删除属性
let obj = {};
let newObj = Object.defineProperty(obj, "b", {
value: { a: 1},
});
delete newObj.OBJ;
newObj.OBJ // { a: 1},
的怎么变为可删除属性?
当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除。
默认为 false
let obj = {};
let newObj = Object.defineProperty(obj, "b", {
value: { a: 1},
configurable :true
});
delete newObj.OBJ;
newObj.OBJ // undefined
delete 操作符可以从对象中删除某个属性,成功返回true,不成功返回false
如果尝试删除不可配置的属性则会抛出异常
'use strict';
let target = {
name:'target',
value:12
}
Object.defineProperty(target,'name',{configurable:false})
// Uncaught TypeError: Cannot delete property 'name'
log(delete target.name)
Uncaught TypeError: Cannot delete property ‘name’ of #
这个错误在 Proxy 中可以得到解决
枚举和循环Object
let obj = { a: 1, b: 2, c: 3 };
Object.keys(obj) // [a,b,c]
for(let key in obj){
console.log(key) //a,b,c
}
禁止枚举和循环Object
let obj = {};
let newObj = Object.defineProperty(obj, "OBJ", {
enumerable: false,
value: { a: 1, b: 2, c: 3 },
// enumerable: false,
});
console.log(Object.keys(newObj)); // []
// 不进,没有迭代属性
for (const key in newObj) {
console.log(key);
}
使用get 和set 来监听但前对象的使用
使用get 和set的时候需要注意不能够代理对象的任何属性设置value,和writable 否者会出错 TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute, #
但是可以添加 enumerable 枚举属性 以及 configurable 是否可以被删除
let obj = {};
Object.defineProperty(obj, "a", {
get: (data) => {
console.log("getget", data);
},
set: (data) => {
console.log("setset", data);
},
});
obj.a = 1999;
obj.a;
一、Proxy是什么?
ES6添加了一些内置的3对象,赋予开发者更多的访问JavaScript引擎的能力,Proxy(代理)是可以拦截并且改变底层JavaScript引擎操作的包装器
Object.defineProperty 基本语法对比Proxy
let obj = {};
let neObj = Object.defineProperty(obj,'b',{})
console.log(obj === neObj); // true 因为修改的同一个数据源
let target = {};
let py = new Proxy(target, {});
console.log(py == target); //false py 是Proxy代理过的新的 Proxy 对象 target只是一个普通的对象
赋值对比
let target = {};
let py = new Proxy(target, {});
py.name = "自夏";
target.name = "哥哥";
console.log(py.name, target.name); //哥哥 哥哥
let obj = {};
let neObj = Object.defineProperty(obj, "b", { value: "bbba" });
console.log(obj.b, neObj.b); // bbba bbba
obj.b = "obj.b";
neObj.b = "neObj.b";
console.log(obj.b, neObj.b); // bbba bbba
数据劫持 vue3
get(traTarget,key,receiver)
traTarget 代理目标对象
key 要读取属性的key 字符串或者是Symbol
receiver 操作发生的对象
set(traTarget,key ,value,receiver)
traTarget 代理目标对象
key 要写入的属性键(key)字符串或者是Symbol
value 要写入的属性值
receiver 操作发生的对象
deleteProperty(traTarget,propname)
traTarget 代理目标对象
propname 要删除的key
let user = {
name:'selfsummer'
}
let newUser = new Proxy(user,{
// 获取数据会触发
get(traTarget,key,receiver){
console.log(traTarget,key,receiver);
return traTarget[key]
},
// 设置属性值,和添加属性值 会触发
set(traTarget,key ,value,receiver){
console.log(traTarget,key ,value,receiver);
return traTarget[key] = value
},
// 删除属性
deleteProperty(traTarget,propname){
console.log(traTarget,propname);
return delete traTarget[propname]
}
})
console.log(newUser.name);
console.log(newUser.sex = 'zixia');
console.log(newUser.name);
delete newUser.name
set
可以拦截写入属性的操作
const {log} = console
let user = {
name:'selfsummer'
}
let newUser = new Proxy(user,{
// 设置属性值,和添加属性值 会触发
set(traTarget,key ,value,receiver){
console.log(traTarget,key ,value,receiver);
log(isNaN(key),value)
// 当前是是存在该对象中
if(traTarget.hasOwnProperty(key)){
if(isNaN(value)){
throw new TypeError('存在修改的属性要修改必须是数字')
}
}
// return traTarget[key] = value
return Reflect.set(traTarget,key ,value,receiver)
},
})
newUser.name = 123
// newUser.name = '自夏' 错误
log(newUser.name) //自夏
log(user.name) //自夏
newUser.sex = '🚹'
get
可以拦截读取属性
let user = {name:'selfsummer'}
let newUser = new Proxy(user,{
get(traTarget,key,receiver){
if(!(key in traTarget)){
throw new TypeError(`要读取的属性 ${key} 不存在 ${traTarget}`)
}
return traTarget[key]
},
}
newUser.sex // 报错
newUser.name //selfsummer
has
每当用 in 操作时都会调用 has 函数,并传入了二个参数
Reflect.has 也接受has 相同的参数,并且返回 in 操作默认返回值
Proxy 中的has函数 也可使用 in 操作符来实现,但是默认实现的函数是由 Reflect.has(traTarget,key) 来实现的 traTarget 为要要检测的对象 key 为要检测的属性
let user = {
name:'selfsummer'
}
let newUser = new Proxy(user,{
/**
* @param {Object} traTarget 读取属性的对象
* @param {Object} key 要检查的属性
*/
has(traTarget,key){
log(traTarget,key)
// 使用in 来实现
// key in traTarget
return Reflect.has(traTarget,key)
}
}
deleteProperty
在 Proxy 中 使用delete 操作符来删除对象 回去调用 deleteProperty 他接受二个参数 (traTarget,key)
Reflect.deleteProperty()
方法为 deleteProperty 默认实现方法,接受同样而二个参数
let user = {
name:'selfsummer'
}
const proxy = new Proxy(user,{
deleteProperty(target,key){
//return delete traTarget[propname] 于下面代码实现效果相同
return Reflect.deleteProperty(target,key)
}
})
name in proxy // true
delete proxy.name // false
总结
提示:这里对文章进行总结:
例如:以上就是今天要讲的内容,本文仅仅简单介绍了pandas的使用,而pandas提供了大量能使我们快速便捷地处理数据的函数和方法。