Vuejs核心代码解析之初始化(一)
首先看最简单的一个two way :
//初始化过程
var vm = new Vue({
data:{
'show':'init'
}
});
//编译过程
vm.$mount('#node');
上面是一个最简单的双向绑定,今天要说的就是“初始化的过程”,这个过程相对比较简单, 主要有以下:
- 初始化
- 为vm添加data访问器
- 创建Observer, 并未data定义__ob__属性
- 创建__ob__访问器,与编译触发相关联
以下代码解释:
exports._init = function (options) {
options = options || {}
this.$el = null
this.$root = options._root || this
this._watcherList = [] // all watchers as an array
this._watchers = {} // internal watchers as a hash
this._directives = [] // all directives
// 标记,避免被观察
this._isRebirth = true
// events bookkeeping
this._events = {} // registered callbacks
this._eventsCount = {} // for $broadcast optimization
this._eventCancelled = false // for event cancellation
// block instance properties
this._isBlock = false
this._blockStart = // @type {CommentNode}
this._blockEnd = null // @type {CommentNode}
// lifecycle state
this._isCompiled =
this._isDestroyed =
this._isReady =
this._isAttached =
this._isBeingDestroyed = false
this._unlinkFn = null
// children
this._children = []
this._childCtors = {}
// transcluded components that belong to the parent.
// need to keep track of them so that we can call
// attached/detached hooks on them.
this._transCpnts = []
// props used in v-repeat diffing
this._new = true
this._reused = false
// merge options.
options = this.$options = mergeOptions(
this.constructor.options,
options,
this
)
// set data after merge.
this._data = options.data || {}
// initialize data observation and scope inheritance.
this._initScope()
}
与双向绑定关键为最后2个:
// set data after merge.
this._data = options.data || {}
// initialize data observation and scope inheritance.
this._initScope()
执行_initScope 初始化访问器
//initScope
exports._initScope = function () {
//add accessor
this._initData()
}
/**
* Initialize the data.
*/
exports._initData = function () {
// proxy data on instance
var data = this._data
var i, key
var keys = Object.keys(data)
i = keys.length
while (i--) {
key = keys[i]
if (!_.isReserved(key)) {
//vm.prop 与 vm._data.prop 代理
this._proxy(key)
}
}
// observe data
Observer.create(data).addVm(this)
}
initData 主要分为两部分:
- vm.prop 与 vm._data.prop 之间创建访问器
- 创建Observer, 以及推入vms
//vm.prop 与 vm._data.prop 之间创建访问器
exports._proxy = function (key) {
// need to store ref to self here
// because these getter/setters might
// be called by child instances!
var self = this
Object.defineProperty(self, key, {
configurable: true,
enumerable: true,
get: function proxyGetter () {
return self._data[key]
},
set: function proxySetter (val) {
self._data[key] = val
}
})
}
Observer
function Observer (value, type) {
this.id = ++uid
this.value = value
this.active = true
this.deps = []
_.define(value, '__ob__', this)
if (type === OBJECT) {
this.walk(value)
}
}
//跳过$和_
p.walk = function (obj) {
var keys = Object.keys(obj)
var i = keys.length
var key, prefix
while (i--) {
key = keys[i]
prefix = key.charCodeAt(0)
if (prefix !== 0x24 && prefix !== 0x5F) { // skip $ or _
this.convert(key, obj[key])
}
}
}
//最重要的一步,当然这部要配合 vm.$mount来看
p.convert = function (key, val) {
var ob = this
var childOb = ob.observe(val)
var dep = new Dep()
if (childOb) {
childOb.deps.push(dep)
}
Object.defineProperty(ob.value, key, {
enumerable: true,
configurable: true,
get: function () {
// Observer.target is a watcher whose getter is
// currently being evaluated.
if (ob.active && Observer.target) {
Observer.target.addDep(dep)
}
return val
},
set: function (newVal) {
if (newVal === val) return
// remove dep from old value
var oldChildOb = val && val.__ob__
if (oldChildOb) {
oldChildOb.deps.$remove(dep)
}
val = newVal
// add dep to new value
var newChildOb = ob.observe(newVal)
if (newChildOb) {
newChildOb.deps.push(dep)
}
dep.notify()
}
})
}
vue的初始化还算简单,compile阶段还正在学习中。。!!!
</>