let vm = new Vue({
el: ‘#app‘,
data: {
a: 1,
b: [1, 2, 3]
}
})
import { initMixin } from ‘./init‘
import { stateMixin } from ‘./state‘
import { renderMixin } from ‘./render‘
import { eventsMixin } from ‘./events‘
import { lifecycleMixin } from ‘./lifecycle‘
import { warn } from ‘../util/index‘
function Vue (options) {
if (process.env.NODE_ENV !== ‘production‘ &&
!(this instanceof Vue)) {
warn(‘Vue is a constructor and should be called with the `new` keyword‘)
}
this._init(options)
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
export default V
function Vue (options) {
if (process.env.NODE_ENV !== ‘production‘ && // 这个 if 判断,是当你不用new操作符来实例化Vue构造函数时,会爆出警告
!(this instanceof Vue)) {
warn(‘Vue is a constructor and should be called with the `new` keyword‘)
}
this._init(options) // 主要就是这一句,
}
initMixin(Vue)
stateMixin(Vue)
eventsMixin(Vue)
lifecycleMixin(Vue)
renderMixin(Vue)
// initMixin(Vue) src/core/instance/init.js **************************************************
Vue.prototype._init = function (options?: Object) {}
// stateMixin(Vue) src/core/instance/state.js **************************************************
Vue.prototype.$data
Vue.prototype.$set = set
Vue.prototype.$delete = del
Vue.prototype.$watch = function(){}
// renderMixin(Vue) src/core/instance/render.js **************************************************
Vue.prototype.$nextTick = function (fn: Function) {}
Vue.prototype._render = function (): VNode {}
Vue.prototype._s = _toString
Vue.prototype._v = createTextVNode
Vue.prototype._n = toNumber
Vue.prototype._e = createEmptyVNode
Vue.prototype._q = looseEqual
Vue.prototype._i = looseIndexOf
Vue.prototype._m = function(){}
Vue.prototype._o = function(){}
Vue.prototype._f = function resolveFilter (id) {}
Vue.prototype._l = function(){}
Vue.prototype._t = function(){}
Vue.prototype._b = function(){}
Vue.prototype._k = function(){}
// eventsMixin(Vue) src/core/instance/events.js **************************************************
Vue.prototype.$on = function (event: string, fn: Function): Component {}
Vue.prototype.$once = function (event: string, fn: Function): Component {}
Vue.prototype.$off = function (event?: string, fn?: Function): Component {}
Vue.prototype.$emit = function (event: string): Component {}
// lifecycleMixin(Vue) src/core/instance/lifecycle.js **************************************************
Vue.prototype._mount = function(){}
Vue.prototype._update = function (vnode: VNode, hydrating?: boolean) {}
Vue.prototype._updateFromParent = function(){}
Vue.prototype.$forceUpdate = function () {}
Vue.prototype.$destroy = function () {}
import Vue from ‘./instance/index‘
import { initGlobalAPI } from ‘./global-api/index‘
import { isServerRendering } from ‘core/util/env‘
initGlobalAPI(Vue)
Object.defineProperty(Vue.prototype, ‘$isServer‘, { //为 Vue.prototype 添加$isServer属性
get: isServerRendering
})
Vue.version = ‘__VERSION__‘ // 在VUE 身上挂载了 version的静态属性
export default Vue
Vue.config
Vue.util = util
Vue.set = set
Vue.delete = del
Vue.nextTick = util.nextTick
Vue.options = {
components: {
KeepAlive
},
directives: {},
filters: {},
_base: Vue
}
Vue.use
Vue.mixin
Vue.cid = 0
Vue.extend
Vue.component = function(){}
Vue.directive = function(){}
Vue.filter = function(){}
Vue.prototype.$isServer
Vue.version = ‘__VERSION__‘
1、覆盖 Vue.config 的属性,将其设置为平台特有的一些方法
2、Vue.options.directives 和 Vue.options.components 安装平台特有的指令和组件
3、在 Vue.prototype 上定义 __patch__ 和 $mount
// 安装平台特定的utils
Vue.config.isUnknownElement = isUnknownElement
Vue.config.isReservedTag = isReservedTag
Vue.config.getTagNamespace = getTagNamespace
Vue.config.mustUseProp = mustUseProp
// 安装平台特定的 指令 和 组件
Vue.options = {
components: {
KeepAlive,
Transition,
TransitionGroup
},
directives: {
model,
show
},
filters: {},
_base: Vue
}
Vue.prototype.__patch__
Vue.prototype.$mount
const mount = Vue.prototype.$mount
Vue.compile = compileToFunctions
1、Vue.prototype 下的属性和方法的挂载主要是在 src/core/instance 目录中的代码处理的
2、Vue 下的静态属性和方法的挂载主要是在 src/core/global-api 目录下的代码处理的
3、web-runtime.js 主要是添加web平台特有的配置、组件和指令,web-runtime-with-compiler.js 给Vue的 $mount 方法添加 compiler 编译器,支持 template。
Vue.prototype._init = function (options?: Object) {
const vm: Component = this
// a uid
vm._uid = uid++
let startTag, endTag
/* istanbul ignore if */
if (process.env.NODE_ENV !== ‘production‘ && config.performance && mark) {
startTag = `vue-perf-init:${vm._uid}`
endTag = `vue-perf-end:${vm._uid}`
mark(startTag)
}
// a flag to avoid this being observed
vm._isVue = true
// merge options
if (options && options._isComponent) {
// optimize internal component instantiation
// since dynamic options merging is pretty slow, and none of the
// internal component options needs special treatment.
initInternalComponent(vm, options)
} else { // 大部分情况下是走了这个分支,也是vue第一步要做的事情,使用mergeOptions来合并参数选项
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
}
/* istanbul ignore else */
if (process.env.NODE_ENV !== ‘production‘) {
initProxy(vm)
} else {
vm._renderProxy = vm
}
// expose real self
vm._self = vm
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, ‘beforeCreate‘)
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, ‘created‘)
/* istanbul ignore if */
if (process.env.NODE_ENV !== ‘production‘ && config.performance && mark) {
vm._name = formatComponentName(vm, false)
mark(endTag)
measure(`${vm._name} init`, startTag, endTag)
}
if (vm.$options.el) {
vm.$mount(vm.$options.el)
}
}
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
export function resolveConstructorOptions (Ctor: Class<Component>) { //ctor 就是 VUE 构造函数
let options = Ctor.options // vue 构造函数身上的 options 属性
if (Ctor.super) { // 判断是否定义了 Vue.super ,这个是用来处理继承的,我们后续再讲
const superOptions = resolveConstructorOptions(Ctor.super)
const cachedSuperOptions = Ctor.superOptions
if (superOptions !== cachedSuperOptions) {
// super option changed,
// need to resolve new options.
Ctor.superOptions = superOptions
// check if there are any late-modified/attached options (#4976)
const modifiedOptions = resolveModifiedOptions(Ctor)
// update base extend options
if (modifiedOptions) {
extend(Ctor.extendOptions, modifiedOptions)
}
options = Ctor.options = mergeOptions(superOptions, Ctor.extendOptions)
if (options.name) {
options.components[options.name] = Ctor
}
}
}
return options
}
// 这是原来的代码
vm.$options = mergeOptions(
resolveConstructorOptions(vm.constructor),
options || {},
vm
)
// 实际上传过去的参数是下面这些
vm.$options = mergeOptions(
// Vue.options
{
components: {
KeepAlive,
Transition,
TransitionGroup
},
directives: {
model,
show
},
filters: {},
_base: Vue
},
// 调用Vue构造函数时传入的参数选项 options
{
el: ‘#app‘,
data: {
a: 1,
b: [1, 2, 3]
}
},
// this
vm
)
function initData (vm: Component) {
let data = vm.$options.data // 第一步还是要先拿到数据,vm.$options.data 这时候还是通过 mergeOptions 合并处理后的 mergedInstanceDataFn 函数
data = vm._data = typeof data === ‘function‘
? data.call(vm)
: data || {}
if (!isPlainObject(data)) {
data = {}
process.env.NODE_ENV !== ‘production‘ && warn(
‘data functions should return an object:\n‘ +
‘https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function‘,
vm
)
}
// proxy data on instance
const keys = Object.keys(data)
const props = vm.$options.props
let i = keys.length
while (i--) {
if (props && hasOwn(props, keys[i])) {
process.env.NODE_ENV !== ‘production‘ && warn(
`The data property "${keys[i]}" is already declared as a prop. ` +
`Use prop default value instead.`,
vm
)
} else {
proxy(vm, keys[i]) // 目的是在实例对象上对数据进行代理,这样我们就能通过 this.a 来访问 data.a 了
}
}
// observe data
observe(data)
data.__ob__ && data.__ob__.vmCount++
}
function proxy (vm: Component, key: string) {
if (!isReserved(key)) {
Object.defineProperty(vm, key, { // vm是实例,key是data属性上的属性,
configurable: true,
enumerable: true,
get: function proxyGetter () {
return vm._data[key]
},
set: function proxySetter (val) {
vm._data[key] = val
}
})
}
}
observe(data)
var o = {};
Object.definedProperty(o, ‘a‘, {
value: ‘b‘
})
configurable:true | false,
enumerable:true | false,
value:任意类型的值,
writable:true | false
var obj = {}
//第一种情况:writable设置为false,不能重写。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false
});
//更改newKey的值
obj.newKey = "change value";
console.log( obj.newKey ); //hello
//第二种情况:writable设置为true,可以重写
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:true
});
//更改newKey的值
obj.newKey = "change value";
console.log( obj.newKey ); //change value
var obj = {}
//第一种情况:enumerable设置为false,不能被枚举。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:false
});
//枚举对象的属性
for( var attr in obj ){
console.log( attr );
}
//第二种情况:enumerable设置为true,可以被枚举。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:true
});
//枚举对象的属性
for( var attr in obj ){
console.log( attr ); //newKey
}
//-----------------测试目标属性是否能被删除------------------------
var obj = {}
//第一种情况:configurable设置为false,不能被删除。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:false,
configurable:false
});
//删除属性
delete obj.newKey; //可以用delete 关键字来删除某一个对象上的属性
console.log( obj.newKey ); //hello
//第二种情况:configurable设置为true,可以被删除。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:false,
configurable:true
});
//删除属性
delete obj.newKey;
console.log( obj.newKey ); //undefined
//-----------------测试是否可以再次修改特性------------------------
var obj = {}
//第一种情况:configurable设置为false,不能再次修改特性。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:false,
configurable:false
});
//重新修改特性
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:true,
enumerable:true,
configurable:true
});
console.log( obj.newKey ); //报错:Uncaught TypeError: Cannot redefine property: newKey
//第二种情况:configurable设置为true,可以再次修改特性。
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:false,
enumerable:false,
configurable:true
});
//重新修改特性
Object.defineProperty(obj,"newKey",{
value:"hello",
writable:true,
enumerable:true,
configurable:true
});
console.log( obj.newKey ); //hello
var o = {}; // 不能是O.name=" dudu "了
var val = ‘dudu‘; // o 对象上的属性是其他人家的一个变量
Object.definedProperty(o,‘name‘,{ // Object.definedProperty( ) 方法通过定set get 方法,强行给拉郎配
get:function(){ return val }; //get: return val 把人家变量给返回了,就是人家的人了
set;function(value){ val = value } //set: val = value 把人家变量赋值为传进来的参数,就是人间人了
})
var O = {};
Object.definedProperty(o,"name",{
set:function(){console.log(‘set‘)}; //在获取对象该属性的时候触发,
get:function(){console.log(‘get‘)}; // 在设置对象该属性的时候触发 , 并不会真正的设置;因为冲突了value,默认是falue
})
var data = {
a: 1,
b: {
c: 2
}
}
observer(data) // 在这里遍历改写了get,set
new Watch(‘a‘, () => {
alert(9)
})
new Watch(‘a‘, () => {
alert(90)
})
new Watch(‘b.c‘, () => {
alert(80)
})
class Watch {
constructor (exp, fn) {
// ……
data[exp] // 触发了data 身上的get 方法
}
}
dep {
subs: [watcher1,watcher2,watcher3], // subs 属性是一个数组,用来维护众多订阅器
addSubs: function(){ this.subs.push( …… ) },
notify: function() {
for(let i = 0; i< this.subs.length; i++){
this.subs[i].fn()
}
}
}
class Dep {
constructor () {
this.subs = []
}
addSub () {
this.subs.push(……)
}
notify () {
for(let i = 0; i < this.subs.length; i++){
this.subs[i].fn()
}
}
}
function defineReactive (data, key, val) { // 这个函数就是用来重写对象属性的get set 方法
observer(val) // 递归的调用从而遍历
let dep = new Dep() // 在这里实例化一个dep实例
Object.defineProperty(data, key, {
enumerable: true,
configurable: true,
get: function () {
dep.addSub() //每当有订阅者订阅,我就新增一个
return val
},
set: function (newVal) {
if(val === newVal){
return
}
observer(newVal)
dep.notify() // 新增
}
})
}
Dep.target = null //类似于全局变量的一个东西,用来放 这次实例化的watcher
function pushTarget(watch){
Dep.target = watch
}
class Watch {
constructor (exp, fn) {
this.exp = exp
this.fn = fn
pushTarget(this) // 让Dep.target赋值为本次实例化的实例
data[exp] //紧接着就触发get 方法
}
}
get: function () {
dep.addSub() //好吧,我又被触发了一次,
return val
},
class Dep {
constructor () {
this.subs = []
}
addSub () {
this.subs.push(Dep.target)
}
notify () {
for(let i = 0; i < this.subs.length; i++){
this.subs[i].fn()
}
}
}
原文:http://www.cnblogs.com/dujuncheng/p/6934786.html