高频面试题: vue 中的 data 为啥是函数?
答案是:是不是一定是函数,得看场景。并且,也无需担心什么时候该将 data 写为函数还是对象,因为 vue 内部已经做了处理,并在控制台输出错误信息。
一、new Vue场景
new Vue({
el: "#app",
// 方式一:对象
data: {
obj: {
name: "qb",
}
},
// 方式二:工厂函数
// data () {
// return {
// obj: {
// name: "qb",
// }
// }
// },
template: `<div>{{obj.name}}</div>`
});
这种场景主要为项目入口或者多个 html 页面各实例化一个 Vue 时,这里的 data 即可用对象的形式,也可用工厂函数返回对象的形式。因为,这里的 data 只会出现一次,不存在重复引用而引起的数据污染问题。
二、组件场景
Vue测试数据ponent("countComponent", {
data() {
return {
count: 1
};
},
template: `<div>
<button @click='changeCount'>递增</button>
<span>{{count}}</span>
</div>`,
methods: {
changeCount() {
this.count++;
}
}
});
new Vue({
el: "#app",
template: `<div>
<countComponent></countComponent>
<countComponent></countComponent>
</div>`
});
首先定义全局组件 countComponent ,然后将该组件重复使用两次,当定义全局组件的时候,会执行 Vue 的 component 方法:
// ASSET_TYPES定义在文件shared/constants.js文件中
export const ASSET_TYPES = [
'component',
'directive',
'filter'
]
// 以下ASSET_TYPES遍历绑定方法的定义在initGlobalAPI(Vue)全局方法挂载阶段完成
import { ASSET_TYPES } from 'shared/constants'
import { isPlainObject, validateComponentName } from 'util/index'
export function initAssetRegisters (Vue: GlobalAPI) {
/**
* Create asset registration methods.
*/
ASSET_TYPES.forEach(type => {
Vue[type] = function (
id: string,
definition: Function | Object
): Function | Object | void {
if (!definition) {
return this.options[type + 's'][id]
} else {
/* istanbul ignore if */
if (process.env.NODE_ENV !== 'production' && type === 'component') {
validateComponentName(id)
}
if (type === 'component' && isPlainObject(definition)) {
definition.name = definition.name || id
definition = this.options._base.extend(definition)
}
if (type === 'directive' && typeof definition === 'function') {
definition = { bind: definition, update: definition }
}
this.options[type + 's'][id] = definition
return definition
}
}
})
}
这里的场景是 component ,那么会执行到 definition = this.options._base.extend(definition) 进行组件构造函数的实现,这里的 this.options._base 就是构造函数 Vue , extend 方法为:
// Vue.extend 方法的定义在initGlobalAPI(Vue)全局方法挂载阶段完成
export function initExtend (Vue: GlobalAPI) {
Vue.extend = function (extendOptions: Object): Function {
extendOptions = extendOptions || {}
const Super = this
const SuperId = Super.cid
const cachedCtors = extendOptions._Ctor || (extendOptions._Ctor = {})
if (cachedCtors[SuperId]) {
return cachedCtors[SuperId]
}
const name = extendOptions.name || Super.options.name
if (process.env.NODE_ENV !== 'production' && name) {
validateComponentName(name)
}
const Sub = function VueComponent (options) {
this._init(options)
}
Sub.prototype = Object.create(Super.prototype)
Sub.prototype.constructor = Sub
Sub.cid = cid++
Sub.options = mergeOptions(
Super.options,
extendOptions
)
// ...
}
}
定义完组件构造函数 Sub 后,在为其合并 options 时,会执行到 mergeOptions :
/**
* Merge two option objects into a new one.
* Core utility used in both instantiation and inheritance.
*/
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
// ...
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
在当前例子中,会通过 const options = {} 定义一个空对象,然后分别将 parent 和 child 上的属性合并到 options 上,此时 data 的合并策略为:
strats.data = function (
parentVal,
childVal,
vm
) {
if (!vm) {
if (childVal && typeof childVal !== 'function') {
process.env.NODE_ENV !== 'production' && warn(
'The "data" option should be a function ' +
'that returns a per-instance value in component ' +
'definitions.',
vm
);
return parentVal
}
return mergeDataOrFn(parentVal, childVal)
}
return mergeDataOrFn(parentVal, childVal, vm)
};
这里 childVal 类型为 object ,即 typeof childVal !== 'function' 成立,进而在开发环境会在控制台输出警告并且直接返回 parentVal ,说明这里压根就没有把 childVal 中的任何 data 信息合并到 options 中去。
总结
vue 中已经帮我们控制台输出警告,并且不会让组件中的 data 合并到 options 中去,那么,很友好的处理了开发者的强行将 data 写成对象的可能性。
到此这篇关于vue中定义的data为什么是函数的文章就介绍到这了,更多相关vue中data为什么是函数内容请搜索以前的文章或继续浏览下面的相关文章希望大家以后多多支持!
查看更多关于vue中定义的data为什么是函数的详细内容...