目录
一、defineReactive函数:
二、递归侦测对象全部属性:
1. 根据传入的值为对象类型 , 修改defineReactive.js函数
2.创建observe.js函数辅助Observer.js函数:
3.创建一个工具函数utils.js
4. 创建Observer.js函数写Observer类
5. 对象测试:
三、数组的响应式处理:
1. array.js函数:
2. Observer.js类:
3. push、unshift、splice这三种方法比较特殊(完善array.js函数):
4. 数组测试:
函数功能:创建闭包环境,完善Object.defineProperty(){}里面的getter()和setter()方法。
不用闭包的情况(需要我们创建临时变量进行新旧值的周转):
var obj = {};
var temp;
Object.defineProperty(obj,'a',{
//getter
get(){
console.log("试图访问obj的"+a+"属性");
return temp;
},
//setter
set(newValue){
console.log("试图改变obj的a属性",newValue);
temp = newValue;
}
});
console.log(obj.a);
obj.a = 9;
obj.a++;
console.log(obj.a);
利用闭包情况:
var obj = {};
function defineReactive(data,key,val){
Object.defineProperty(data,key,{
//可枚举
enumerable:true,
//可被配置
configurable:true,
//getter
get(){
console.log('你试图访问obj的a属性');
return val;
}
//setter
set(newValue){
console.log('你试图修改obj的a属性',newValue);
if(val == newValue){
return;
}
val = newValue;
}
});
}
defineReactive(obj,'a',10);
console.log(obj.a);
obj.a = 69;
obj.a++;
console.log(obj.a);
图示:
如果此时obj的值如下形式则不能使全部值得到响应式。
var obj = {
a:{
m:{
n:5
}
}
}
那么defineReactive.js函数要发生改变。
export default function defineReactive(data,key,val){
if(arguments.length == 2){
val = obj[key];
}
Object.defineProperty(data,key,{
//可枚举
enumerable:true,
//可被配置
configurable:true,
//getter
get(){
console.log('你试图访问obj的a属性');
return val;
}
//setter
set(newValue){
console.log('你试图修改obj的a属性',newValue);
if(val == newValue){
return;
}
val = newValue;
}
});
}
import Observer from "./Observer";
export default function(value){
//如果value不是对象,什么都不做
if(typeof value != 'object'){
return;
}
// 定义ob
var ob;
if(typeof value.__ob__ != 'undefined'){
ob = value.__ob__;
}else{
ob = new Observer(value);
}
return ob;
};
功能:用来添加 __ob__属性,因为其是不可枚举属性。
//定义obj对象的key属性
export const def = function(obj,key,value,enumerable){
Object.defineProperty(obj,key,{
value,
enumerable,
writable:true,
configurable
})
}
函数功能:将一个正常的对象转换为每个层级的属性都是响应式(可被侦测到的)对象。
Observer.js函数:
/*给实例(this,一定要注意,构造函数中的this不是表示类本身,而是表示实例)
添加了__ob__属性,值是这次new的实例
*这里value是传过来的obj
* '__ob__'是传过去的key
* this,是传过去的value
* false是不可枚举的
* */def(value,'__ob__',this,false);
/*
* 功能:将一个正常的object转换为每个层级的属性都是响应式
* (可以被侦测的object)
* */
import {def} from './utils.js'
import defineReactive from './defineReactive'
import {arrayMethods} from './array.js'
import observe from "./observe";
import Dep from './Dep.js'
import Watcher from './Watcher.js'
//一个类如何被实例化
export default class Observer{
//构造器
constructor(value){
//给实例(this,一定要注意,构造函数中的this不是表示类本身,而是表示实例)
//添加了__ob__属性,值是这次new的实例
def(value,'__ob__',this,false);
/*
*这里value是传过来的obj
* '__ob__'是传过去的key
* this,是传过去的value
* false是不可枚举的
* */
console.log(value);
this.walk(value);
}
// 遍历
walk(value){
// 嵌套的子属性在此处遍历
for(let k in value){
defineReactive(value,k);
}
}
}
defineReactive.js函数:
import observe from './observe.js'
export default function defineReactive(data,key,val){
if(arguments.length == 2){
val = obj[key];
}
let childOb = observe(val);
Object.defineProperty(data,key,{
//可枚举
enumerable:true,
//可被配置
configurable:true,
//getter
get(){
console.log("你试图访问obj的"+key+"属性");
return val;
}
//setter
set(newValue){
console.log('你试图修改obj的'+key+'属性',newValue);
if(val == newValue){
return;
}
val = newValue;
childOb = observe(newValue);
}
});
}
index.js文件:
import defineReactive from './defineReactive.js'
import Observer from './Observer.js'
import observe from './observe.js'
var obj = {
a:{
m:{
n:5
}
},
b:10,
c:{
d:{
e:{
f:6666
}
}
},
g:[22,33,12,44,55]
};
observe(obj);
//对象测试
console.log(obj.a.m.n);
obj.a.m.n = 88;
console.log(obj.a.m.n);
以Array.prototype为原型创建了一个arrayMethods对象,此时通过setPrototypeOf使新数组的隐式原型指向arrayMethods
改写数组的七种方法:这七中方法都在Array的原型上(Array.prototype)
push
pop
shift
unshift
splice
sort
resever
//定义新的方法
def(arrayMethods,methodName ,function(){
console.log("");
},false);
import {def} from './utils.js'
//得到Array.prototype
const arrayPrototype = Array.ptototype;
//以Array.prototype为原型,创建了一个ArrayMethods对象,并暴露
export const arrayMethods = Object.create(arrayPrototype);
//要被改写的七个数组方法
const methodsNeedChange = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsNeedChange.forEach(methodName => {
//备份原来的
const original = arrayPrototype[methodName];
//定义新的方法
def(arrayMethods,methodName ,function(){
console.log("123");
original.apply(this,arguments);
},false);
})
/*
* 功能:将一个正常的object转换为每个层级的属性都是响应式
* (可以被侦测的object)
* */
import {def} from './utils.js'
import defineReactive from './defineReactive'
import {arrayMethods} from './array.js'
import observe from "./observe";
import Dep from './Dep.js'
import Watcher from './Watcher.js'
//一个类如何被实例化
export default class Observer{
//构造器
constructor(value){
//给实例(this,一定要注意,构造函数中的this不是表示类本身,而是表示实例)
//添加了__ob__属性,值是这次new的实例
def(value,'__ob__',this,false);
/*
*这里value是传过来的obj
* '__ob__'是传过去的key
* this,是传过去的value
* false是不可枚举的
* */
console.log(value);
//检查是数组还是对象
if(Array.isArray(value)){
/*如果是数组,要将数组的原型指向arrayMethods*/
Object.setPrototypeOf(value,arrayMethods);
// 让这个数组变的observe
this.observeArray(value);
}else{
this.walk(value);
}
}
// 对象遍历
walk(value){
// 嵌套的子属性在此处遍历
for(let k in value){
defineReactive(value,k);
}
}
// 数组的特殊遍历
observeArray(arr){
for(let i= 0,l = arr.length;i
这三种方法可以插入新项,需要将插入的新项也变为observe
import {def} from './utils.js'
/*
* push、pop、shift、unshift、splice、sort、reverse
* 这7中方法被改写了
* **/
//Vue当中数组的响应式是如何实现的?
/*
* 它实际上是以Array.prototype为原型,
* 创建了一个ArrayMethods对象,此时利用Es6中的setPrototypeOf方法
* 来强制使数组的隐式原型指向ArrayMethods
*
*
*
* **/
//得到Array.prototype
const arrayPrototype = Array.prototype;
//以Array.prototype为原型,创建了一个ArrayMethods对象,并暴露
export const arrayMethods = Object.create(arrayPrototype);
//要被改写的七个数组方法
const methodsNeedChange = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
];
methodsNeedChange.forEach(methodName => {
// 备份原来的方法
const original = arrayPrototype[methodName];
// 定义新的方法
def(arrayMethods,methodName,function(){
// 恢复原来的功能,定义返回值
const result = original.apply(this,arguments);
//把类数组对象变为数组
const args = [...arguments];
//把这个数组身上的__ob__取出来,__ob__已经被添加了,为什么被添加了?因为数组肯定不是最高层,比如obj.g
//属性是数组,obj不能是数组,第一次遍历obj这个对象的第一层的时候,已经给g属性(就是这个数组)添加了
// __ob__属性
const ob = this.__ob__;
// 有三种方法 push、unshift、splice能够插入新项,现在要把插入的新项也要变为observe
let inserted = [];
switch(methodName){
case 'push':
case 'unshift':
inserted = arguments;
break;
case 'splice':
// splice格式是splice(下标,数量,插入的新项)
inserted = arguments.splice(2);
break;
}
// 判断有没有要插入的新项,让新项也变为响应的
if(inserted){
//ob的原型上有observerArray方法
ob.observeArray(inserted);
}
return result;
},false);
});
index.js(入口文件夹):
import defineReactive from './defineReactive.js'
import Observer from './Observer.js'
import observe from './observe.js'
import Watcher from './Watcher.js'
var obj = {
a:{
m:{
n:5
}
},
b:10,
c:{
d:{
e:{
f:6666
}
}
},
g:[22,33,12,44,55]
};
observe(obj);
//对象测试
// console.log(obj.a.m.n);
// obj.a.m.n = 88;
// console.log(obj.a.m.n);
//数组测试
obj.g.push(11);
console.log(obj.g);
// new Watcher(obj,'a.m.n',(val)=>{
// console.log('!');
// });
// obj.a.m.n = 88;
// console.log(obj);
注:资料学习《Vue尚硅谷源码解析系列课程》
代码地址:https://gitee.com/c-fff/DataResponsive