Object.definedProperty()
1. 基本方法
let book = {};
Object.definedProperty(book, 'name', {
value: 'John',
writable: false,
configurable: false,
enumerable: false,
get() {
return newValue;
},
set(newValue) {
book.name = newValue;
},
});
2. 属性作用
value:为当前设定的对象book的属性name的值,此处也可以设定默认值。
如果不设定默认为undefined
-
writable:能否修改对象book的属性name的值。 -
true: 代表当前的值可通过赋值的方式(见下文)和属性重定义的方式(见下文)的方式可进行修改 -
false: 和true的情况相反,也就是不能修改对象的属性的值 -
configurable:表示当前对象的属性能否被删除。 -
true: 可以删除对象的属性 -
false: 不能删除对象的属性 -
enumerable: 定义道德对象的属性是否可以在for...in循环和Object.keys()中进行遍历。 -
(1)
value属性
let person = {};
// 赋值的方式
person.name = 'rose';
// 属性重定义的方式
Object.defineProperty(person, 'name', {
value: 'jack',
});
- (2)
writable属性
// 情况一:writable: false
let person = {};
Object.defineProperty(person, 'name', {
value: 'jack',
writable: false,
});
person.name = 'rose';
console.log('赋值方式person.name', person.name); // jack
Object.defineProperty(person, 'name', {
value: 'jack',
writable: false,
});
console.log('属性重定义方式person.name', person.name); // jack
// 情况二:writable: true
let person = {};
Object.defineProperty(person, 'name', {
value: 'jack',
writable: true,
});
person.name = 'rose';
console.log('赋值方式person.name', person.name); // rose
Object.defineProperty(person, 'name', {
value: 'john',
});
console.log('属性重定义方式person.name', person.name); // john
- (3)
configurable属性
// 情况一:configurable: false
let person = {};
Object.defineProperty(person, 'name', {
value: 'jack',
configurable: false,
});
delete person.name;
console.log('🚀person', person); // person {name: jack}
// 情况二:configurable: true
let person = {};
Object.defineProperty(person, 'name', {
value: 'jack',
configurable: true,
});
delete person.name;
console.log('🚀person', person); // person {}
- (4)
enumerable属性
let person = {};
Object.defineProperty(person, 'name', {
value: 'jack',
enumerable: true,
});
person.gender = 'man';
Object.defineProperty(person, 'age', {
value: '26',
enumerable: false,
});
console.log(Object.keys(person)); // [0:'name',1:'gender']
for (const key in person) {
console.log(key);
} // name gender
-
(5)
get()方法 -
属性的
getter函数,如果没有getter,则为undefined。 当访问改属性时,会调用此函数,
执行时不需要传入任何参数,但是默认会传入 this 对象(由于继承关系,这里的 this 指向的 this
指向不一定是定义改属性的对象)。该函数的返回值会被用作该属性的值。
-
(6)
set()方法 -
属性的
setter函数,如果没有setter,则为undefined。当属性值被修改时,会调用此函数。该
方法接受一个参数(也就是被赋予的新值),会传入赋值的 this 对象。
3. 原理实现
-
在 MVVM 框架中,一是监听数据的变化,二是数据驱动。
-
在通常使用中我们使用
Object.definedProperty()来实现监听数据的变化,或者使用Proxy和 反射。 -
本章通过使用
MutationObserver来实现Object.definedProperty()对数据变化的监听。 -
(1)
API 的使用 -
定义:
MutationObserver构造函数对 DOM 树所做的更改提供了监听的能力。替代了旧的MutaionEvents
功能。
- 返回值:
MutationObserver创建后并返回一个new MutationObserver,当 DOM 发生改变时,会调用
制定的回调函数。
-
注意点:
-
MutationObserverAPI 是异步触发的,DOM 的改变并不会马上触发,而是等到所有对 DOM 改变的操作
完成后,整体的触发一次。
- 面对多次的 DOM 修改,
MutationObserver会将多次的改变记录封装成一个数组进行处理,而不是一条
一条进行处理。
-
MutationObserver在不影响浏览器性能的情况下响应 DOM 的更改。 -
基本方法:
-
disconnect():停止MutationObserver的监听,直到再次observe()再次被调用。 -
observe():开始监听,并通过回调函数让MutationObserver接受通知。 -
takeRecords():从MutationObserver的通知队列中移除所有挂起的通知,并在一个新Array的
MutationObserver 对象中返回它们。
- (2)
代码实现
<!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>Object.definedProperty的实现</title>
</head>
<body>
<div id="app">
<h1 id="h"></h1>
</div>
</body>
</html>
<script>
// 选择要观察的节点
const targetNode = document.getElementById('app');
// 具体要观察节点那些改变
const config = { attributes: true, childList: true, subtree: true };
// 创建一个回调函数的实例,节点发生改变时执行的回调函数
const Observer = new MutationObserver((mutationList, observer) => {
mutationList.forEach((item, index) => {
if (item.type === 'childList') {
console.log('有节点发生改变,当前节点的内容是:', item.target.innerHTML);
} else if (item.type === 'attributes') {
console.log('修改了' + item.attributeName + '属性');
}
});
});
// 开始观察节点是否发生变化
Observer.observe(targetNode, config);
// 停止观察
// observer.disconnect();
</script>
- (3)
输出结果