1.data为什么要是函数?
首先可以通过下列代码来展示部分,其中区别在于,构造函数定义时,会在内部的data设置一个值,这个值是对象类型,在栈中时存储着一个指向内存中该对象的堆的地址,新建一个实列对象时,要获取函数中的data,也就是获取那个堆中的地址,再次创建实例对象时,获取的也是这个地址,但是这个地址指向的数据是同一个,也就是{count:0},所以想要改变其中一个的data时,就要对存储地址进行变动,但是所有的实列都是按照地址寻找值,改变一个其他的也会改变。
所以data属性声明值,必须使用函数类型,这样每次创建实例对象时都能获得他们自己的一个对象值,对应堆的地址不相同,所以互不影响。
该部分代码展示了创建实例对象后的寻找堆的地址时的不同情况。对象类型的每次都会同时改变,但是函数类型的互不影响。
<body>
先用vue来区别data是函数的原因
<div id="app">
<cpn1></cpn1>
<cpn1></cpn1>
<cpn1></cpn1>
<hr>
<cpn2></cpn2>
<cpn2></cpn2>
<cpn2></cpn2>
</div>
<script src="vue.js"></script>
<template id="cpn1"> <!-- template中只能暴露一个div -->
<div>
<button @click="count++">+</button>
<h3>{{count}}</h3>
<button @click="count--">-</button>
</div>
</template>
<template id="cpn2">
<div>
<button @click="count++">+</button>
<h3>{{count}}</h3>
<button @click="count--">-</button>
</div>
</template>
<script type="text/javascript">
var obj = {count:0};
const app = new Vue({
el:'#app',
data:{
},
methods:{
},
components:{
cpn1:{
template:'#cpn1',//挂载
data(){
return obj;
}
},
cpn2:{
template:'#cpn2',
data(){
return{
count:0
}
}
}
}//简单的说 这里涉及的问题是于data存储的数据的地址有关,若是一个对象,他指向的一直都是该地址,是函数的情况是会不断的新建立一个地址
})
</script>
</body>
下面的代码同样是展示堆地址的不同。
在使用复用型组件时,声明data属性的值时,必须要使用函数类型 每次创建实例对象时,他们都是获取属于他们自己的一个对象值,并且对应的堆中的地址都不相同,所以互不影响。
创建实例对象data是对象时,改变一个所有结果都会改变。
创建实例对象data是函数时,改变其中一个不会影响其他的。
<body>
进一步确定data的函数性质
<div></div>
<script type="text/javascript">
var obj = {//此处是堆,用来存放data的数据地址,不会应为实例对象的创建二改变给它的地址信息。
name:'张三',
age:20
}
function box1(){
return obj;
}
function box2(){
return{
name:'张三',
age:20
}
}
var a1 = box1();
var b1 = box1();
var c1 = box1();
a1.name = '李四'
console.log(a1);//{name: '李四', age: 20}
console.log(b1);//{name: '李四', age: 20}
console.log(c1);//{name: '李四', age: 20}
//都发生改变
var a2 = box2();
var b2 = box2();
var c2 = box2();
a2.name = '李四'
console.log(a2);//{name: '李四', age: 20}
console.log(b2);//{name: '张三', age: 20}
console.log(c2);//{name: '张三', age: 20}
//三个结果共出现三个地址位置,从而互不影响
//在使用复用型组件时,声明data属性的值时,必须要使用函数类型 每次创建实例对象时,他们都是获取属于他们自己的一个对象值,并且对应的堆中的地址都不相同,所以互不影响。
</script>
</body>
2.MVVM模型
M:数据层(model)应用数据以及逻辑,主要指从后端获取的数据,指数据这里
代码中的数据data就是数据层。
V: 视图层(View):页面UI组件,主要由 HTML 和 CSS 来构建
div标签id是app的就是视图层
VM:视图数据模型(ViewModel):数据与视图关联起来,数据和 DOM 已经建立了关联,是响应式的,使编程人员脱离复杂的界面操作
const vm = new Vue()即为试图数据模型。这里是VM层 ViewModel主要功能是实现数据双向绑定:
数据变化后更新视图,既:model有数据更新时UI组件会响应变化
视图变化后更新数据,界面上如果有input输入框,输入数据时,model中的数据也会更新
实际上vue并不是一个完整的MVVM的模型,是借用了这样的思维。
<body>
<div id="app">
<!-- // 视图层(View):页面UI组件,主要由 HTML 和 CSS 来构建 -->
<h3>{{name}}</h3>
<h3>{{age}}</h3>
</div>
<script src="vue.js"></script>
<script type="text/javascript">
//实际上vue并不是一个完整的MVVM的模型,是借用了这样的思维
// 视图数据模型(ViewModel):数据与视图关联起来,数据和 DOM 已经建立了关联,是响应式的,使编程人员脱离复杂的界面操作
const vm = new Vue({
//这里是VM层 ViewModel主要功能是实现数据双向绑定:
// 数据变化后更新视图,既:model有数据更新时UI组件会响应变化
// 视图变化后更新数据,界面上如果有input输入框,输入数据时,model中的数据也会更新
el:'#app',
// 数据层(Model):应用数据以及逻辑,主要指从后端获取的数据,指数据这里
data(){
return{
name:"zhangsan",
age:20
}
}
})
</script>
</body>
3.数据代理object.defineProperty
vue2 利用object.defineProperty劫持对象或对象属性的访问器,在属性值发生变化时获取属性值变化,从而进行后续操作,这就是 vue的底层运行逻辑 响应式原理。
object.defineProperty方法直接在一个对象上定义一个新属性,或者修改一个已存在的属性,并返回这个对象
value设置属性的值
wtitable:值是否可以重写。true/flase
enumerable:目标属性是否可以被枚举。true/flase
configurable:目标属性是否可以被删除,或是否可以再次修改特性
代码中有相应注释
<body>
<!-- vue2 利用object.defineProperty劫持对象或对象属性的访问器,在属性值发生变化时获取属性值变化,从而进行后续操作 -->
<!-- vue的底层运行逻辑 响应式原理-->
<!-- object.defineProperty方法直接在一个对象上定义一个新属性,或者修改一个已存在的属性,并返回这个对象 -->
<!-- value设置属性的值 -->
<!-- wtitable:值是否可以重写。true/flase -->
<!-- enumerable:目标属性是否可以被枚举。true/flase -->
<!-- configurable:目标属性是否可以被删除,或是否可以再次修改特性 -->
<div id="app">web</div>
<script type="text/javascript">
// var a = {name:'zhangsan'};
// var b = {age:25};
// Object.defineProperty(a,'age',{
// get(){
// return b.age
// },
// set(val){
// b.age = val
// }
// })
// a.age = 30
// console.log(b);//{age: 30},通过a来修改b
// ------------------------------------------------------
// vue中的格式
// const vm = new Vue({
// el:'#app',
// data(){
// return{
// }
// },
// methods:{
// }
// })
// -------------响应式原理写法----------------------
// let data = {
// msg: '张三'
// }//这个代表上面的数据data
// let vm = {} //这个代表上面的vm,试图数据模型
// Object.defineProperty(vm,'msg',{
// // enumerable:true,//可枚举的,这里可以不加但是后续的需要加上
// // configurable:true,//可以被删除或再改一次
// get(){
// return data.msg
// },
// set(newval){
// data.msg = newval;
// document.querySelector("#app").textContent = newval
// }
// })
// vm.msg = "你好,响应式原理"
//改变了页面的渲染效果了
let data = {
msg:'Hello Vue',
count:0
}
let vm = {}
function defineProperty(){
// Object.keys()//对象变成数组,值为对象的键值
// Object.value()//对象的值变为数组
Object.keys(data).forEach(key=>{//遍历对象的写法,对象不是一个值,多个的新情况需要加上【】来指定
Object.defineProperty(vm,key,{
enumerable:true,//可枚举的
configurable:true,//可以被删除或修改一次
get(){
return data[key];//这里的中括号是指别的,js中动态属性以中括号的形式包起来,这里的key可能是msg有可能是count
},
set(newval){
data[key] = newval;
document.querySelector("#app").textContent = newval
}
})
})
}
defineProperty(data)
// vm.msg = "你好,响应式原理"
vm.count = 11111111
//这就是底层原理,vue2的响应式原理,主要通过object.de.....进行数据代理来操作vm去改变data的值。
// 优势:无需显示调用,只要数据发生变化直接通知变化并驱动试图更新
// 2.在set函数中精确得知变化数据,而不用逐个遍历属性获取变化值,减少性能消耗
// Object.defineProperty()可以监测到属性的获取,修改,但是新增,删除监测不到。
</script>
</body>
Object.defineProperty的缺点,改变数值不能发生响应式变化。这里和数组的操作是一致的。通过几个修饰词改变。
<body>
<div id="app">
<!-- <div @click="qq">
{{isAgree.msg}}
</div>
<div>
{{isAgree.ww}}
</div>
<div>
{{isAgree.qq}}
</div> -->
<h2 v-for="(item,index) in isAgree.web" :key="index">{{item}}</h2>
<button @click="updateweb">点击</button>
</div>
<script src="vue.js"></script>
<script type="text/javascript">
const vm = new Vue({
el:'#app',
data(){
return{
isAgree:{
msg:'zhangsan',
web:['html','js']
}
}
},
methods:{
qq(){
// this.isAgree.ww = 'list';//直接添加无效
// console.log(this.isAgree.ww);//list 改变了,但是没有响应式反应
// vue.set(目标,属性名)向响应式对象中添加一个propert,并确保这个新的property同样是响应式的,且触发试图更新
Vue.set(this.isAgree,'ww','list');
//this.$set(this.isAgree,'qq','4');//两个都行
Vue.delete(this.isAgree,'msg');
// this.$delete(this.isAgree,'ww')
// delete this.isAgree.msg;//直接删除无效
// console.log(this.isAgree.msg);//删除了
},
updateweb(){
//Object.de....是操作数组的
this.isAgree.web[0] = 'lili'
console.log(this.isAgree.web[0]);
}
},
computed:{
},
watch:{
}
})
//在组件的标签上加上native才能点击监听组件事件
</script>
</body>
本文探讨了Vue中为何将data设为函数,通过实例对比对象和函数在创建实例时数据独立性的差异,以及MVVM模型(Model-View-ViewModel)在Vue中的应用。重点讲解了数据代理(如`Object.defineProperty`)在实现响应式数据更新中的作用,以及如何使用`Vue.set`处理复杂数据结构的变更。
1066

被折叠的 条评论
为什么被折叠?



