vue2数据响应式原理

wuchangjian2021-11-06 17:19:24编程学习

目录

  • Object.defineProperty() 方法
  • defineReactive函数
  • 递归侦测对象全部属性

Object.defineProperty() 方法

  1. Object.defineProperty() 方法会直接在一个对象上定义一个新属性,或者修改一个对象的现有属性,并返回此对象。
const object1 = {};
// 在object1对象上定义property1属性的值value为42
Object.defineProperty(object1, 'property1', {
  value: 42// value代表属性的值
});
object1.property1 = 77;// 默认不能改变属性值
console.log(object1.property1);// 42
  1. 为什么要用Object.defineProperty() 方法 你用object1.property1=42不是更简洁吗:我们可以使用Object.defineProperty() 方法来定义一些隐藏的属性
    (1)writable:当且仅当该属性的 writable 键值为 true 时,属性的值,也就是上面的 value,才能被赋值运算符 改变。默认为 false。
const object1 = {};
Object.defineProperty(object1, 'property1', {
  value: 42,
  writable: true
});
object1.property1 = 77;
console.log(object1.property1);// 77

(2)enumerable:当且仅当该属性的 值为 true 时,该属性才会出现在对象的枚举属性中 才可以用for…in…遍历。默认为 false。

  1. get:属性的 getter 函数,如果没有 getter,则为 undefined。当访问该属性时,会调用此函数。执行时不传入任何参数,但是会传入 this 对象(由于继承关系,这里的this并不一定是定义该属性的对象)。该函数的返回值会被用作属性的值。默认为 undefined。
    set:属性的 setter 函数,如果没有 setter,则为 undefined。当属性值被修改时,会调用此函数。该方法接受一个参数(也就是被赋予的新值),会传入赋值时的 this 对象。默认为 undefined。
const object1 = {};
Object.defineProperty(object1, 'property1', {
  value: 42// value代表属性的值
});
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('你在访问object1的property2属性')
  },
  set(){
	console.log('你在设置object1的property2属性')
  }
});
console.log(object1);// property1: 42因为你没给property2赋值
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性
console.log(object1.property2)// undefined

defineReactive函数

getter函数的返回值会被用作属性的值 setter函数接受一个参数(也就是被赋予的新值)

const object1 = {};
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('你在访问object1的property2属性')
	return 7;
  },
  set(newValue){
	console.log('你在设置object1的property2属性', newValue)
  }
});
console.log(object1.property2)// 7
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性 10
console.log(object1.property2)// 7 

为什么返回7而不是10 我明明给object1.property2赋新值了 因为getter中并不能返回你刚修改的值 你只要一访问object1.property2 就会调用get() 返回7 为了解决这个问题 我们需要用一个变量来周转一下

const object1 = {};
let temp;
Object.defineProperty(object1, 'property2', {
  get(){
	console.log('你在访问object1的property2属性')
	return temp;// 用到闭包
  },
  set(newValue){
	console.log('你在设置object1的property2属性', newValue)
	temp = newValue;// 用到闭包
  }
});
console.log(object1.property2)// undefined
object1.property2 = 10;
// 你在访问object1的property2属性
// 你在设置object1的property2属性 10
console.log(object1.property2)// 10 

Object.defineProperty需要变量周转才能使用setter getter 我们把变量和Object.defineProperty封装一下

const object1 = {};
// data:对象 key:对象的属性 val:变量
function defineReactive(data, key, val){
	Object.defineProperty(data, key, {
	  	get(){
			console.log('你在访问object1的property2属性')
			return val;// 用到闭包
 	 	},
  		set(newValue){
			console.log('你在设置object1的property2属性', newValue)
			if(val === newValue) return;
			val = newValue;// 用到闭包
  		},
  		// 你也可以在里面配置一些属性
  		enumerable: true;
  		configurable: true
	});
}
defineReactive(object1, property2, 7)
console.log(object1.property2)// 7
object1.property2 = 10;
console.log(object1.property2)// 10 

defineReactive函数提供了闭包 你可以不另外使用临时变量来使用setter getter

递归侦测对象全部属性

上面只能让property2中的值实现响应式 如果property2是个对象 a中的对象的值其实不能实现响应式的 不能进行get set 下面我们来实现一个类Observer 它可以将一个正常的object转换为每个层级的属性都是响应式的(可以被侦测到)的object 思路如下图
在这里插入图片描述

  1. 创建一个类 你要想的第一件事:该类如何被实例化

相关文章

系统维护工具:System Toolkit Mac中文版(支持macos 12系统)

系统维护工具:System Toolkit Mac中文版(支持macos 12系统)

System Toolkit for Mac是专业的系统维护工具,Syst...

SpringCloud最新2021年面试题大汇总,附答案

SpringCloud最新2021年面试题大汇总,附答案

1、设计微服务的最佳实践是什么? 以下是设计微服务的最佳实践࿱...

云计算提供商锁定的影响以及解决方案

问题 云计算提供厂商锁定是不能完全消除的,如果云计算提供商锁定将会产生很...

mybatis-plus自定义数据源

import com.baomidou.mybatisplus.annotation.I...

发表评论    

◎欢迎参与讨论,请在这里发表您的看法、交流您的观点。