> 文章列表 > Vue03_vue属性_数据代理

Vue03_vue属性_数据代理

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>