为什么data是函数,而components是对象? data函数如果没有返回值会报错吗? 答:会
vue源码位置:src\core\instance\state.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 function initData (vm: Component ) { let data = vm.$options.data data = vm._data = typeof data === 'function' ? getData(data, 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 ) } 。。。 。。。 。。。 observe(data, true ) }
Vue源码位置:packages\weex-template-compiler\build.js
1 2 3 function isPlainObject (obj ) { return _toString.call(obj) === '[object Object]' }
data函数
执行之后将返回值重新赋值给data
,如果data
不是个object
,name
就会报出一个警告
为什么props定义的数据不能和data同名?
vue源码路径:vue\src\core\instance\state.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 const keys = Object .keys(data) const props = vm.$options.props const methods = vm.$options.methods let i = keys.length while (i--) { const key = keys[i] if (process.env.NODE_ENV !== 'production' ) { if (methods && hasOwn(methods, key)) { warn( `Method "${key} " has already been defined as a data property.` , vm ) } } if (props && hasOwn(props, key)) { process.env.NODE_ENV !== 'production' && warn( `The data property "${key} " is already declared as a prop. ` + `Use prop default value instead.` , vm ) } else if (!isReserved(key)) { proxy(vm, `_data` , key) } }
可以看到先获取data
的key
,然后再去调用hasOwn
方法去判断methods
和props
里面是否有重复的key
,有的话就会发出警告。最后都通过了之后就会调用proxy(vm, '_data', key)
,用封装的proxy
方法对vm实例
做了一层代理,使得我们可以直接通过this
直接调用key
vue2代理的实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 const sharedPropertyDefinition = { enumerable : true , configurable : true , get : noop, set : noop }export function proxy (target: Object , sourceKey: string, key: string ) { sharedPropertyDefinition.get = function proxyGetter ( ) { return this [sourceKey][key] } sharedPropertyDefinition.set = function proxySetter (val ) { this [sourceKey][key] = val } Object .defineProperty(target, key, sharedPropertyDefinition) }
使用的是Object.defineProperty
来实现的
Vue的初始化
Vue源码位置:src\core\instance\index.js
1 2 3 4 5 initMixin(Vue) stateMixin(Vue) eventsMixin(Vue) lifecycleMixin(Vue) renderMixin(Vue)
最先执行的是initMixin()
,我们看看里面有啥。
Vue源码位置:src\core\instance\init.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 vm._self = vm initLifecycle(vm) initEvents(vm) initRender(vm) callHook(vm, 'beforeCreate' ) initInjections(vm) initState(vm) initProvide(vm) callHook(vm, 'created' )
initState()
是从state.js
文件里面导入的,我们再去看看里面有什么。
src\core\instance\state.js
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 export function initState (vm: Component ) { vm._watchers = [] const opts = vm.$options if (opts.props) initProps(vm, opts.props) if (opts.methods) initMethods(vm, opts.methods) if (opts.data) { initData(vm) } else { observe(vm._data = {}, true ) } if (opts.computed) initComputed(vm, opts.computed) if (opts.watch && opts.watch !== nativeWatch) { initWatch(vm, opts.watch) } }
可见在beforeCreate
与created
之间初始化了inject
,props
,methods
,data
,computed
,watch
基于Vue2的proxy,自己实现一个代理 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 const noop = {} const propertyDefinition = { enumerable :true , configurable :true , get :noop, set :noop }const Proxy = function (target,sourceKey,key ) { propertyDefinition.get = function getter ( ) { return target[sourceKey][key] } propertyDefinition.set = function setter (val ) { target[sourceKey][key] = val } Object .defineProperty(target,key,propertyDefinition) }function Vue (data ) { this ._data = data Object .keys(this ._data).forEach(key => { Proxy (this ,'_data' ,key) }) }const vueIns = new Vue({a :1 ,b :2 }) vueIns._data.b = 'hhh' vueIns.a = 2222 console .log(vueIns._data.a)console .log(vueIns.b)
Vue的实例为什么不能挂载在body或根节点上?挂载了会报错吗? 答:挂载节点会被虚拟dom生成的Dom替换,会报错
Vue源码位置:src\platforms\web\entry-runtime-with-compiler.js
1 2 3 4 5 6 if (el === document .body || el === document .documentElement) { process.env.NODE_ENV !== 'production' && warn( `Do not mount Vue to <html> or <body> - mount to normal elements instead.` ) return this }
什么是虚拟节点,简述虚拟dom构成? vue和react虚拟dom的区别?