Vue03_vue属性_数据代理
Vue中
$ 开始的属性是供程序员开发使用的
_ 开始的属性是vue 框架底层使用的
可以直接访问data 中的属性
使用数据代理机制实现
数据代理机制: 通过访问代理对象的属性 间接 访问 目标对象的属性
数据代理机制 核心 Object.defineProperty 为对象添加一个属性
Object.defineProperty(obj, prop, descriptor)
obj |
要定义属性的对象 |
prop |
要定义或修改的属性的名称 |
descriptor |
要定义或修改的属性描述符 |
返回值 | 被传递给函数的对象 |
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//属性的 值value:"毛选"});</script>
</body>
</html>
book.name 赋值 无效
writable: true属性可修改,false属性不可修改
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//属性的 值value:"毛选",//可修改属性的值writable: true});</script>
</body>
</html>
getter setter 方法
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//属性的 值value:"毛选",//可修改属性的值writable: true,//有get set 配置项时,value writable 配置项不允许使用//getter方法配置项,在获取添加的这个属性 的值时 该方法会被调用get:function(){},//setter方法配置项,在修改 添加的这个属性的 值时 该方法会被调用//省略 :function 的简写set(){}});</script>
</body>
</html>
有get set 配置项时,value writable 配置项不允许使用
获取 添加 属性的 值
getter 方法被调用
修改 添加 属性的 值
setter 方法被调用
getter 方法必须有返回值,获取属性值时获取到的就是getter方法的返回值
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//getter方法配置项,在获取添加的这个属性 的值时 该方法会被调用get:function(){//getter 方法必须有返回值,获取属性值时获取到的就是getter方法的返回值return "毛选";},//setter方法配置项,在修改 添加的这个属性的 值时 该方法会被调用//省略 :function 的简写set(){console.log("setter");}});</script>
</body>
</html>
setter方法 参数 接收为属性赋的值
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//getter方法配置项,在获取添加的这个属性 的值时 该方法会被调用get:function(){//getter 方法必须有返回值,获取属性值时获取到的就是getter方法的返回值return "毛选";},//setter方法配置项,在修改 添加的这个属性的 值时 该方法会被调用//省略 :function 的简写//参数 接收 为 属性赋的值set(value){console.log("赋值" + value);}});</script>
</body>
</html>
book.name 获取属性值时,其实获取的是变量 tmp 的值
book.name="value" 给属性赋值时,其实是为变量tmp赋值
book.name 就代理了 变量 tmp
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body><div id = "app"><input v-model="msg" /></div><script type="text/javascript">//创建一个对象let book = {};let tmp ;//给 book 对象添加属性newBook = Object.defineProperty(//需要添加属性的对象book,//要添加的属性 名"name",{//getter方法配置项,在获取添加的这个属性 的值时 该方法会被调用get:function(){//getter 方法必须有返回值,获取属性值时获取到的就是getter方法的返回值return tmp;},//setter方法配置项,在修改 添加的这个属性的 值时 该方法会被调用//省略 :function 的简写//参数 接收 为 属性赋的值set(value){tmp = value;}});</script>
</body>
</html>
第一次获取tmp的值,undefined
book.name获取的其实是tmp 的值(调用getter方法),一样为 undefined
book.name="局外人",调用setter方法,为tmp赋值,
再次获取book.name 和 tmp 的值, 为 局外人
数据代理机制的实现:
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id = "app"><input v-model="msg" />
</div><script type="text/javascript">//目标对象let target = {name: "罗小黑"};//代理对象let proxy = {};//给代理对象新增一个属性Object.defineProperty(proxy,'name',{get(){//间接访问目标对象的属性return target.name;},set(value){//将值赋给目标对象的属性target.name = value;}});</script>
</body>
</html>
vue 数据代理对属性名的要求
不能以 $ or _ 开始
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/vue.js"></script>
</head>
<body>
<div id = "app"></div><script type="text/javascript">const vm = new Vue({el: "#app",data: {msg: "msg",_msg: "_msg",$msg: "$msg"}});</script>
</body>
</html>
vm 对象中只有msg属性,没有_msg,$msg 属性,以$ or _ 开始的属性名 vue 不会做数据代理 $ _ 开始的属性名 是 vue框架 自己要用
模拟 vue 数据代理
//定义一个类
class Vue {//定义构造函数constructor(option){//获取所有的属性名let propertys = Object.keys(option.data);//添加代理属性propertys.forEach(/* ()=> {} 形式为箭头函数 其内没有this ,会从上一级作用域寻找 this 变量function(){} 中的this 为调用该方法的对象,此处箭头函数中的this 从上一级作用域找到的 this 是 constructor 创建的对象*/(propertyName,index) => {Object.defineProperty(this,propertyName,{get(){return option.data[propertyName];},set(val){option.data[propertyName] = val;}});});}
}
<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><title>Title</title><!--引入vue,引入之后vue.js 创建了一个全局变量Vue--><script type="text/javascript" src="../js/myVue01.js"></script>
</head>
<body>
<div id = "app"></div><script type="text/javascript">const vm = new Vue({data:{msg: "my_Vue"}});</script>
</body>
</html>