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',
});
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
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 {}
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 发生改变时,会调用MutationObserver
API 是异步触发的,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>