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 发生改变时,会调用
制定的回调函数。
–注意点:
•MutationObserver API 是异步触发的,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) 输出结果