/*Object的变化侦测*/
//对象的属性拦截
const arrayProto = Array.prototype;
const arrayMethods = Object.create(arrayProto);
function defineReactive(data,key,val){
if(typeof val === 'object'){
new Observer(val)
}
let childOb = observe(val)
let dep = new Dep();
Object.defineProperty(data,key,{
enumerable:true,
configurable:true,
get:function(){
// console.log(1)
dep.depend()
if(childOb){
// console.log("--get--")
// console.log(childOb)
childOb.dep.depend()
}
return val;
},
set:function(newVal){
console.log("--set--")
if(val === newVal){
return
}
val = newVal
dep.notify()
}
})
}
//依赖收集在哪里
class Dep{
constructor(){
this.subs = [];
}
addSub(sub){
this.subs.push(sub)
}
removeSub(sub){
remove(this.subs,sub)
}
depend(){
if(window.target){
this.addSub(window.target)
}
}
notify(){
// console.log("3-1")
// console.log(this.subs)
const subs = this.subs.slice()
// console.log(subs)
for(let i =0;i <subs.length;i++){
subs[i].update()
}
}
}
function remove(arr,item){
if(arr.length){
const index = arr.indexOf(item)
if(index >-1){
return arr.splice(index,1)
}
}
}
//依赖类
class Watcher {
constructor(vm,expOrFn,cb){
// console.log("2-1")
//vm是数据对象value
//expOrFn是key
//cb是回调函数
this.vm = vm;
this.getter = parsePath(expOrFn);
//this.getter为返回函数A
this.cb = cb;
this.value = this.get();
}
get(){
// console.log(this)
window.target = this;
let value = this.getter.call(this.vm,this.vm)
window.target = undefined;
return value
}
update(){
// console.log("update")
// console.log(this)
const oldValue = this.value;
// console.log(oldValue)
this.value = this.get();
// console.log(this.value)
this.cb.call(this.vm,this.value,oldValue)
}
}
const bailRE = /[^\w.$]/;
function parsePath(path){
if(bailRE.test(path)){
return
}
const segments = path.split('.')
//返回函数A 闭包函数
return function(obj){
//obj为数据对象value
//segments为key
// console.log("2-2")
// console.log(obj)
// console.log("-----")
// console.log(segments)
for(let i =0;i <segments.length;i++){
// console.log("2-3")
if(!obj)return
// console.log("2-4")
obj = obj[segments[i]]
}
// console.log("2-5")
// console.log(obj)
return obj
}
}
const hasProto = '__proto__' in {};
const arrayKeys = Object.getOwnPropertyNames(arrayMethods);
//侦测所有的key
class Observer {
constructor(value){
this.value = value;
//数组添加
this.dep = new Dep()
def(value,'__ob__',this)
console.warn(value)
console.warn(Array.isArray(value))
if(Array.isArray(value)){
const argument = hasProto?protoAugment:copyAugment;
argument(value,arrayMethods,arrayKeys)
observeArray(value)
}
//数组添加
if(!Array.isArray(value)){
this.walk(value)
}
}
walk(obj){
const keys = Object.keys(obj)
for(let i = 0;i<keys.length;i++){
defineReactive(obj,keys[i],obj[keys[i]])
}
}
}
//vue类
class Vue{
constructor(options){
new Observer(options)
//给数据添加订阅者
Object.keys(options).forEach(key=>{//按照options的属性循环实例化watcher
new Watcher(options,key,()=>{
console.log("这是回调方法")
});
})
}
}
// obj.time = "17";
/**
* 数据初始化首先 实例化Obsever 并将对象数据作为参数传入 在observer实例中循环参数
* 对象的值value,并对value调用defineReactive方法中实例化Dep 之后重新定义get和set。
* get方法中收集依赖 set方法中派发依赖
* 其次循环数据value 给value添加订阅者 并通过数据项get方法将value 加入dep实例中
*
* **/
// 数组的变化侦测ss
['push','pop','shift','unshift',
'splice','sort','reverse'].forEach(function(method){
const original = arrayProto[method]
def(arrayMethods,method,function(...args){
const result = original.apply(this,args)
const ob = this.__ob__;
console.log("--push--")
let inserted
switch(method){
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
if(inserted) observeArray(inserted)
ob.dep.notify()
return result
})
})
function def(obj,key,val,enumerable){
Object.defineProperty(obj,key,{
value:val,
enumerable:!!enumerable,
writable:true,
configurable:true
})
}
//Observer类
function protoAugment(target,src,keys){
target.__proto__ = src;
}
function copyAugment(target,src,keys){
for(let i = 0;i < keys.length;i++){
const key = keys[i];
}
}
function observeArray(items){
for(let i =0; i < items.length;i++){
observe(items[i])
}
}
function observe(value,asRootData){
if(!isObject(value)){
return
}
let ob
// if(hasOwn(value,'__ob__') && value.__ob__ instanceof Observer ){
// ob = value.__ob__;
// }else{
// ob = new Observer(value)
// }
ob = new Observer(value)
return ob
}
function isObject(val) {
return val != null && typeof val === 'object'
// return val != null && typeof val === 'object' && Array.isArray(val) === false;
};
// let obj = {
// time:"12",
// hour:"21",
// secend:20,
// street:"灵魂",
// };
let obj = {
array1:[1,3,5,7]
}
// let array1 = [1,3,5,7]
new Vue(obj)
// console.log("--1--")
// console.log(obj.array1[0])
// console.log(obj.array1[1])
obj.array1.push(9)
console