1. Object.defineProperty()
首先看 MDN 中是如何定义的
Object.defineProperty()
方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
语法:Object.defineProperty(obj, prop, descriptor)
参数:
obj
要定义属性的对象。prop
要定义或修改的属性的名称或 Symbol 。descriptor
要定义或修改的属性描述符。
返回值: 被传递给函数的对象。
let object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false
});
object1.property1 = 77;
console.log(object1.property1);
// 42
对象里目前存在的属性描述符有两种主要形式:数据描述符
和存取描述符
注意:一个描述符只能是这两者其中之一,不能同时是两者。
数据描述符
具有以下可选键值:
value
:该属性对应的值。可以是任何有效的JavaScript值(数值,对象,函数等)。 默认为 undefined。writable
:当 writable 属性设置为 false 时,该属性被称为“不可写的”。它不能被重新赋值。 默认为 false不可修改。
举个例子🌰就知道了:
let obj = {}
Object.defineProperty(obj,'a',{
value: '666',
writable: false
});
delete obj.a; // false
obj.a = '333'
obj.a // '666'
从上面例子可以看出,obj.a 不可以被删除也不可以被修改。
存取描述符
具有以下可选键值:
get
:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。 默认为 undefined。set
:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。 默认为 undefined。
共享键值
(默认值是指在使用 Object.defineProperty() 定义属性时的默认值):
configurable
:当且仅当该属性的 configurable 键值为 true 时,该属性的描述符才能够被改变,同时该属性也能从对应的对象上被删除(不能保证该属性能被修改,只有当 writable 为 true 时,才能修改该属性)。默认为 false。(configurable属性控制了属性描述对象的可写性。为false时不能修改属性描述对象)enumerable
:enumerable 定义了对象的属性是否可以在for...in
循环和Object.keys()
中被枚举。 默认为 false。
举个例子🌰:
let obj = {name: 'xm', age: 18}
Object.defineProperty(obj,'a',{
value: '666',
enumerable: false
});
for (i in obj){
console.log(i)
}
// name
// age
Object.keys(obj) // ["name", "age"]
Object.defineProperty(obj,'b',{
value: '666',
configurable: true
});
obj.b = '333'
obj.b // '666'
delete obj.b // true
// 可以修改描述符对象中的属性
Object.defineProperty(obj,'b',{
value: '666',
configurable: true,
writable: true
});
obj.b = '333'
obj.b // '333'
// 将属性c的描述符对象设为不可修改
Object.defineProperty(obj,'c',{
value: '666',
configurable: false,
writable: true
});
// 可以将 writable: true 修改为 false,反过来不行,enumerable不能修改
Object.defineProperty(obj,'c',{
configurable: false,
writable: false
});
// 会报错
Object.defineProperty(obj,'c',{
configurable: false,
writable: true
});
「描述符默认值」:
① 拥有布尔值的键 configurable
、enumerable
和 writable
的默认值都是 false。
② 属性值和函数的键 value
、get
和 set
字段的默认值为 undefiend。
注意:如果一个描述符不具有 value、writable、get 和 set 中的任意一个键,那么它将被认为是一个数据描述符。如果一个描述符同时拥有 value 或 writable 和 get 或 set 键,则会产生一个异常。
也就是属性描述符只能有两种形式:
let Person = {};
Object.defineProperty(Person, 'age', {
value: 15,
writable: false, // 是否可以修改
configurable: false, //是否可配置
enumerable: true //是否可被枚举
})
let Person2 = {};
Object.defineProperty(Person2, 'name', {
get() {
return name
},
set(val) {
name = val
},
enumerable: false, //是否可配置
})
我们还可以自定义 Setters
和 Getters
下面的例子展示了如何实现一个自存档对象。当设置temperature 属性时,archive 数组会收到日志条目。
function Archiver() {
var temperature = null;
var archive = [];
Object.defineProperty(this, 'temperature', {
get: function() {
console.log('get!');
return temperature;
},
set: function(value) {
temperature = value;
archive.push({ val: temperature });
}
});
this.getArchive = function() { return archive; };
}
var arc = new Archiver();
arc.temperature; // 'get!'
arc.temperature = 11;
arc.temperature = 13;
arc.getArchive(); // [{ val: 11 }, { val: 13 }]
还可以简单的实现一个 Vue
双向数据绑定。
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
</head>
<body>
<div id="app">
<input type="text" id="a" />
<span id="b"></span>
</div>
</body>
<script>
var obj = {}; //定义一个空对象
var val = "zhao"; //赋予初始值
Object.defineProperty(obj, "val", {
//定义要修改对象的属性
get: function () {
return val;
},
set: function (newVal) {
val = newVal; //定义val等于修改后的内容
document.getElementById("a").value = val; //让文本框的内容等于val
document.getElementById("b").innerHTML = val; //让span的内容等于val
},
});
document.addEventListener("keyup", function (e) {
//当在文本框输入内容时让对象里你定义的val等于文本框的值
obj.val = e.target.value;
});
</script>
</html>
2. Object.defineProperties()
MDN定义:Object.defineProperties()
方法直接在一个对象上定义新的属性或修改现有属性,并返回该对象。
语法:Object.defineProperties(obj, props)
参数与 Objec.defineProperty()
相似。
- obj 在其上定义或修改属性的对象。
- props 要定义其可枚举属性或修改的属性描述符的对象。对象中存在的属性描述符主要有两种:数据描述符和访问器描述符(更多详情,请参阅Object.defineProperty())。
描述符与 Objec.defineProperty()
相同
返回值:传递给函数的对象。
从语法和参数上来看 Objec.defineProperty()
与 Object.defineProperties 十分相似,区别是一个只能定义一个属性,一个可以定义多个属性。
例子:
var obj = {};
Object.defineProperties(obj, {
'property1': {
value: true,
writable: true
},
'property2': {
value: 'Hello',
writable: false
}
});