Vue数据监听Object.definedProperty()方法的实现

116 阅读3分钟

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) 输出结果

Object.definedProperty.png