响应式原理

313 阅读2分钟
  • 真正使用vue的时候,给属性赋值,获取属性值,都是直接使用Vue实例
// es5中的方法
Object.defineProperty(对象,'设置什么属性名',{
	configurable:true/false, 是否是可配置的
    writable:true/false, 是否是可编辑的                
    enumerable: true/false, 控制属性是否可枚举,是不是可以被 for-in 取出来
    set(){}, 赋值触发
	get(){}, 取值触发,
    value:
})

注意:
	writable和get/set 是没办法同时存在的
let o ={};
o.name = 'zs';
等价于下面的写法:
Object.defineProperty(o,'name',{
    configurable: true,
    writable: true,
    enumerable: true,
    value: 'zs'
})

将对象处理成响应式的

原理:其实就是使用Object.defineProperty() 对数据进行处理,将数据编程响应式的

<script>
			let o = {};
			o.name = 'zs';
			let _age;
			Object.defineProperty(o,'age',{
				configurable: true,
				enumerable: true,
				get: function() {
					return _age; 
				},
				set: function(newVal) {
					_age = newVal;
				}
			});
			// 注意:如果同时使用get与set需要使用一个中间变量存储数据
			
			/**
			    上面代码存在的问题:
			        1、将 _age 暴露在全局
			*/ 
		   
		   // 将对象转换为响应式的
		   let obj = {
			   name: 'zs',
			   age: 20,
			   gender: '女'
		   }
		   function defineProperty(target,key,value,enumerable) {
			  // 在这里相当于使用了 闭包 ,因为 value 是在函数内部使用的 
               Object.defineProperty(target,key,{
				   configurable: true,
				   enumerable: !!enumerable,
				   get: function() {
					   console.log(`获取${key}的值`);
					   return value;
				   },
				   set: function(newVal) {
					   console.log(`设置${key}的值为:${newVal}`);
					   value = newVal;
				   }
			   })
		   }
		   // 将对象处理成响应式的
		   let keys = Object.keys(obj);
		   for (let i = 0; i < keys.length; i++) {
				defineProperty(obj,keys[i],obj[keys[i]],true);
		   }
		</script>


/*
	上面代码存在的问题:
		1、只能将简单的数据进行响应式处理,像对象里面嵌套对象,数组里面嵌套对象,这种情况是没办法实现数	据响应式的
*/
// 解决上面代码存在的问题,添加 reactify 函数
function reactify(obj) {
    let keys = Object.keys(obj);
    for (let i = 0; i < keys.length; i++) {
        let key = keys[i];
        let val = obj[key];
        /**
			需要判断这个属性的属性值,是否是引用类型(也就是对象数据类型object),是否是数组类型
			    1、如果是引用数据类型,需要调用defineReactive 将数据响应式化
			    2、如果是数组类型,需要循环遍历数组,然后将数组里面的元素响应式化
		*/ 
        if(Array.isArray(val)) {
            for(let j = 0; j < val.length; j++) {
                reactify(val[j]);
            }
        } else {
            defineReactive(obj,key,val,true);
        }
    }
}
reactify(obj);