1.Object.definePropery
Object.defineProperty()方法会直接在对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
备注:
(1)应当直接在Object构造器对象上调用此方法,而不是在任意一个Object类型的实例
上调用。
语法:
Object.defineProperty(obj, prop, descriptor)
参数:
obj:要定义属性的对象
prop:要定义或修改的属性的名称或Symbol
descriptor:要定义或修改的属性描述符
返回值:被传递给函数的对象。
描述:
该方法允许精确地添加或修改对象的属性。通过赋值操作添加的普通属性是可枚举的,
在枚举对象属性时会被枚举到 (for...in或Object.keys方法),可以改变这些属性的值,
也可以删除这些属性。这个方法允许修改默认的额外选项(或配置)。默认情况下,
使用Object.defineProperty()添加的属性值是不可修改的。
描述符(descriptor):
:
(1) configurable(数据属性描述符、存取属性描述符公有):
当且仅当该属性的configurable键值为true时,该属性的描述符才能够被改变,
同时该属性也能从对应的对象上被删除。
默认值: false
(2) enumerable(数据属性描述符、存取属性描述符公有)
当且仅当该属性的enumerable键值为true时,该属性才会出现在对象的枚举属性中。
默认值:false
当设置为false时,该对象中的属性无法被for...in和Object.keys枚举出来,其它方式能
正常取值
(3) value(数据属性描述符)
该属性对应的值。可以是任何有效的javaScript值(数值,对象,函数等)
默认值:undefined
(4) writable(数据属性描述符)
当且仅当该属性的writable键值为true时,属性的值,也就是上面的value,才能
被赋值运算符改变。
默认值为false
(5) get(存取属性描述符)
属性的getter函数,如果没有getter,则为undefined。当访问该属性时,会调用此函数
执行时不传入任何参数,但是会传入this对象(由于继承关系,这里的this并不一定是
定义该属性的对象)。该函数的返回值会被用作属性的值
默认为:undefined
(6) set(存取属性描述符)
属性的setter函数,如果没有setter,则为undefined。当属性值被修改时,会调用此函数
该方法接受一个参数(也就是被赋予的新值),会传入赋值时的this对象。
验证Object.defineProperty描述符:
value
writable
configurable
enumerable
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
</body>
</html>
<script type="text/javascript">
let number = 18
let person = {
age: 20
}
// 演示writable的默认值
Object.defineProperty(person,'age', {
value: 18, //默认值是undefined
writable:false,//控制属性能否被修改,默认值是false
})
person.age = 30
console.log("验证writable: false",person.age)
// 演示enumerable
Object.defineProperty(person,"age", {
value: 18,
enumerable: false, //控制属性能否被枚举
})
console.log("验证enumerable: false,通过console",person)
for (let key in person) {
// 枚举不了age
console.log(`key:${key},value:${person[key]}`)
}
// 枚举不了age
console.log("Object.keys(person)",Object.keys(person))
// 演示configurable
Object.defineProperty(person, "age", {
configurable: false, //控制描述符能否被修改以及属性能否被删除
})
console.log("删除person对象中的age前",person)
delete person.age
console.log("删除person对象中的age后",person)
</script>
2.数据代理
数据代理,也叫数据劫持。指的是在访问或修改对象的某个属性时,通过一段代码拦截这个行为,进行额外的操作或者修改返回结果。比较典型的是Object.defineProperty()和ES2015中新增的Proxy对象。另外,还有已经被废弃的Object.observe(),废弃的原因正是Proxy的出现。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<title>何为数据代理</title>
</head>
<body>
</body>
</html>
<script type="text/javascript" >
let obj = {x:100}
let obj2 = {y:200}
/**
对obj2对象中的x属性进行数据劫持,实际我们使用了一个中间变量obj.x
这是为了避免重复触发get
*/
Object.defineProperty(obj2,'x',{
get(){
return obj.x
},
set(value){
obj.x = value
}
})
// 以下代码因为没有使用中间变量,当对obj3.x进行读取和赋值的操作时会报无限触发,报异常
let obj3 = { x: 100 }
Object.defineProperty(obj3,'x', {
get() {
return obj3.x
},
set(value) {
obj3.x = value
}
})
</script>
当对obj3.x进行读取和赋值的操作时会报无限触发,报异常的测试