一: vue 源码解析之响应原理 Obj.defineProperty
参数:
enumerable, //是否枚举 就是可遍历的意思
writable:true, // 是否可写
configurable:true // 是否被删除
get
set
案例1 对象响应
-----------defineReactive 函数 -----------
function defineReactive(data,key,val){
console.log("我是defineReactive",data,key)
if(arguments.length==2){
val=data[key];
}
let childOb=observe(val)
Object.defineProperty(data,key,{
get:function(){ // 不用和value值同时使用
console.log('我访问了name属性')
return val
},
set:function(newValue){
console.log('视图改变值为',newValue)
if(newValue === val){
return;
}
val=newValue;
childOb=observe(newValue)
}
})
}
-----------def 函数 -----------
function def(obj,key,value,enumerable){
Object.defineProperty(obj,key,{
value,
enumerable, //是否枚举 就是可遍历的意思
writable:true, // 是否可写
configurable:true // 是否被删除
})
}
------- Observer作用:将一个正常的Object转换每个层级的属性都是响应式(可祯听的)object-----
class Observer {
constructor (val) {
console.log('我是构造器Observer',val)
def(val,'__ob__',this,false)
this.walk(val)
}
//遍历
walk(val){
for(let k in val){
defineReactive(val,k)
}
}
}
-----------observe函数----------------------------
function observe(value){
if(typeof value !='object') return;
var ob;
if(typeof value.__ob__!=='undefined'){
ob=value.__ob__;
}else{
ob= new Observer(value)
}
return ob;
}
----------------- 调用------------------------
let obj={
a:{
a1:{
a2:{
a3:10
}
}
},
b:{
b1:6
},
c:{
c1:7
},
};
observe(obj)
案例2 在前面基础添加数组的响应
array.js文件
const arrayPrototype = Array.prototype;
export const arrayMethods = Object.create(arrayPrototype)
const methodsNeedChange = [
'push',
'pop',
'shift',
'unshift',
'splice',
'sort',
'reverse'
]
methodsNeedChange.forEach(methodName => {
//备份原来的 因为 push
const orginal = arrayPrototype[methodName]
// 定义新方法
def(arrayMethods, methodName, function() {
const result = orginal.apply(this, arguments)
let arg2 = [...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 = arg2;
case 'splice':
// splice格式splice(下标,数量,插入新项)
inserted = arg2.slice(2);
break;
}
// 判断有没有要出入新项,让新项也变成响应
if (inserted) {
ob.observeArray(inserted)
}
console.log('拉拉')
return result;
}, false)
})
function def(obj, key, value, enumerable) {
Object.defineProperty(obj, key, {
value,
enumerable, //是否枚举 就是可遍历的意思
writable: true, // 是否可写
configurable: true // 是否被删除
})
}
调用文件
definePropretyFun(){
function defineReactive(data,key,val){
console.log("我是defineReactive",data,key)
if(arguments.length==2){
val=data[key];
}
let childOb=observe(val)
Object.defineProperty(data,key,{
get:function(){ // 不用和value值同时使用
console.log('我访问了name属性')
return val
},
set:function(newValue){
console.log('视图改变值为',newValue)
if(newValue === val){
return;
}
val=newValue;
childOb=observe(newValue)
}
})
}
function def(obj,key,value,enumerable){
console.log(obj,key,value,enumerable)
Object.defineProperty(obj,key,{
value,
enumerable, //是否枚举 就是可遍历的意思
writable:true, // 是否可写
configurable:true // 是否被删除
})
}
// Observer作用:将一个正常的Object转换每个层级的属性都是响应式(可祯听的)object
class Observer {
constructor (val) {
console.log('我是构造器Observer',val)
def(val,'__ob__',this,false)
if(Array.isArray(val)){
// 如果是数组,要强制将该数组的原型执行 arrayMethods
Object.setPrototypeOf(val,arrayMethods)
//让这个数组变的obsever
this.observeArray(val);
}else{
this.walk(val)
}
}
//遍历
walk(val){
for(let k in val){
defineReactive(val,k)
}
}
// 数组的特殊遍历
observeArray(arr){
for(let i=0,l=arr.length;i<l;i++){
// 逐项进行observe
observe(arr[i])
}
}
}
function observe(value){
if(typeof value !='object') return;
var ob;
if(typeof value.__ob__!=='undefined'){
ob=value.__ob__;
}else{
ob= new Observer(value)
}
return ob;
}
let obj={
a:{
a1:{
a2:{
a3:10
}
}
},
b:{
b1:6
},
c:{
c1:7
},
d:[1,2,3]
};
observe(obj)
obj.d.push(4)
obj.d.splice(2,1,88) // 把下标2 删除,改成 88
obj.d.splice(1,1,[21,32])
console.log(obj.d)