在 Vue
中,我们定义数据使用 data
.
在 Vue
的根节点里,它是一个对象.
var app = new Vue({
el: '#app',
data: {
msg: 'this is msg'
})
在components
中,它是一个函数,内部返回一个对象
export default {
name: 'cart-buy-button',
data () {
return {
testNum: 0,
addCounter: 0,
removeCounter: 0
}
}
}
因为 vue 根节点,在整个vue单页面实例中,它有且只有一个,所以
data
可以设置成一个Object{}
但是子组件可能会多次实例化和调用,所以为了确保子组件的数据的独立性和隔离性,需要使用data(){return{}}
的方法.每次返回一个新的对象.
数据流的单向流动.
在 Vue
中,我们使用插值表达式,往某个非表单
元素中插入 data
里的数据时,数据是单向流动的.
{{msg2}}
var app = new Vue({
el: '#app',
data: {
msg2: 'this is msg'
},
methods: {
changeDataMsg() {
this.msg2 = Math.random(1000).toString().substring(0, 2) + this.msg2
}
}
结果:
在初学vue的时候,觉得挺新奇.
过了几天,觉得就是这样的.
在过了几天就发现,原来是
Vue
在实例化的时候会把data
里的属性使用ES5
提供的Object.defineProperty
重新定义一遍,并设置其属性的get
和set
也就是说,我们给定的data属性,其内部是有可能这么一段代码.
let obj = {
name: '李四',
age: 22
}
let defaultName = '李四'
Object.defineProperty(obj, 'name', {
set(newVal) {
defaultName = newVal
// 检测到新值,更新 dom
},
get() {
return defaultName
}
})
let defaultAge = 22
Object.defineProperty(obj, 'age', {
set(newVal) {
defaultAge = newVal
// 检测到新值,更新 dom
},
get() {
return defaultAge
}
})
也就是说,所有(不管是根Vue还是components)的实例的data
属性,都会被使用 Object.defineProperty
重新定义.这也就是为什么Vue
对于表单元素的双向绑定
和非表单元素的单向数据流
属性的基础.
关于 Object.defineProperty 可以参考我之前写的一篇
Object.defineProperty 解析
非 data 属性呢?
我们都知道,js是一本特别灵活的语言,可以很随意的给对象添加属性,而需要实现声明.
created() {
// 在非data里定义的数据,没有被 Object.defineProperty重新定义,所以无法检测到get,set,也不无法更新dom.
this.defineOnCreatedProperty = '这是在 created 钩子函数里定义的变量'
},
在 created
钩子函数里,随意的给当前实例添加一个 defineOnCreatedProperty
属性,是否也支持单向数据流
&双向绑定
呢?
{{defineOnCreatedProperty}}
changeCreatedData() {
this.defineOnCreatedProperty = '能否检测到改变????'
}
结果:
怎么点,都不能像 data
里定义的数据那样,支持数据流的特性.
原因也很简单:
非
data
里声明,而是你自己定义的属性,那它就是一个普通的属性,vue不会去对待它(使用Object.defineProperty)去重新定义.所以,就无法检测到变化,不能检测到变化,就无法支持所有的数据流特性了.
总结
- vue的数据流,是里用的
ES5
提供的Object.defineProperty
方法来重新定义data
数据,以便获取属性的get/set
来检测属性的变化,以实现数据流. - 自己随便定义的属性,比如
this.defineOnCreatedProperty
没有定义在data
,没有Object.defineProperty
去重新定义此属性以监控set/get
,当然就无法实现所谓的数据流了.