function Vue(options) {
this._init(options)
}
Vue.prototype._init = function(options) {
var vm = this;
vm.$options = options
initState(vm)
}
function initState(vm) {
const options = vm.$options
if (options.data) {
initData(vm)
}
}
function initData(vm) {
var data = vm.$options.data
vm._data = data = typeof data === 'function' ? data.call(vm) : data || {}
for (const key in data) {
Object.defineProperty(vm, key, {
enumerable: true,
configurable: true,
get() {
return vm['_data'][key]
},
set(newVal) {
vm['_data'][key] = newVal
}
})
}
observe(data)
}
function observe(data) {
if (typeof data !== 'object' || data === null) {
return
}
const ob = new Observer(data)
return ob
}
class Observer {
constructor(data) {
this.data = data
if (Array.isArray(data)) {
this.ARR_METHODS = ['push', 'pop', 'shift', 'unshift', 'sort', 'splice', 'reverse']
const arrayProto = Array.prototype
this.arrayMethods = Object.create(arrayProto)
data.__proto__ = this.arrayMethods
this.rewriteArrayFunction()
this.observeArr(data)
} else {
this.walk(data)
}
}
walk(data) {
const keys = Object.keys(data)
for(let i = 0; i < keys.length; i++) {
var key = keys[i]
var value = data[key]
this.defineReactive(data, key, value)
}
}
defineReactive(data, key, value) {
observe(value)
Object.defineProperty(data, key, {
get() {
return value
},
set(newVal) {
if (newVal === value) {
return
}
observe(newVal)
newVal = value
}
})
}
rewriteArrayFunction(data) {
const _self = this
this.ARR_METHODS.forEach((method) => {
this.arrayMethods[method] = function() {
var args = Array.prototype.slice.call(arguments);
const result = Array.prototype[method].apply(this, args)
let newArr;
switch (method) {
case 'push':
case 'unshift':
newArr = args
break
case 'splice':
newArr = args.slice(2)
break
default:
break
}
newArr && _self.observeArr(newArr)
return result
}
})
}
observeArr(arr) {
console.log(arr, 'arr==')
for(let i = 0; i< arr.length; i++) {
observe(arr[i])
}
}
}
class Dep {
constructor() {
this.subs = []
}
addSub(sub) {
this.subs.push(sub)
}
depend() {
Dep.target.addDep(this)
}
notify() {
const subs = this.subs.slice()
for (let i = 0; i < subs.length; i++) {
subs[i].update()
}
}
}