赞
踩
Object.defineproperty 的作用就是直接在一个对象上定义一个新属性,或者修改一个已经存在的属性.。并返回此对象。
Object.defineproperty 参数
Object.defineproperty方法需要传递3个参数
Object.defineproperty(obj, prop, desc )
参数1:obj 需要定义属性的当前对象
参数2:prop 当前需要定义的属性名
参数3:desc 描述符 一般是一个对象{
value:18, // 属性值
enumerable:true, //控制属性是否可以枚举,默认值是false
writable:true, //控制属性是否可以被修改,默认值是false
configurable:true //控制属性是否可以被删除,默认值是false
}
set
和get
(即存取器描述:定义属性如何被存取)
get
是获取值的时候的方法,类型为 function
,获取值的时候会被调用,不设置时为 undefined
set
是设置值的时候的方法,类型为 function
,设置值的时候会被调用,undefined
get或set不是必须成对出现,任写其一就可以
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8" />
- <title>Object.defineproperty方法</title>
- </head>
- <body>
- <script type="text/javascript" >
- let number = 18
- let person = {
- name:'张三',
- sex:'男',
- }
-
- Object.defineProperty(person,'age',{
- // value:18,
- // enumerable:true, //控制属性是否可以枚举,默认值是false
- // writable:true, //控制属性是否可以被修改,默认值是false
- // configurable:true //控制属性是否可以被删除,默认值是false
-
- //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
- get(){
- console.log('有人读取age属性了')
- return number
- },
-
- //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
- set(value){
- console.log('有人修改了age属性,且值是',value)
- number = value
- }
-
- })
-
- // console.log(Object.keys(person))
-
- console.log(person)
- </script>
- </body>
- </html>
vue2.0是如何监听双向绑定的?
- function updateView() {
- console.log('视图更新');
- dom.innerHtml=data.name;//将data的name属性值渲染在dom元素中.
- }
-
- function defineReactive(target, key, value) {
- Object.defineProperty(target, key, {
- get() {
- return value
- },
- set(newValue) {
- if (newValue !== value) {
- value = newValue
- updateView()
- }
- }
- })
- }
-
- function observe(target) {
- if (target === null || typeof target !== 'object') {
- return target
- }
- for(let key in target) {
- defineReactive(target, key, target[key])
- }
- }
-
- const data = {
- name: '张三',
- age: 21
- }
-
- observer(data)
-
- data.name = 'lisi'
oberve函数判断源数据是否是对象,然后遍历,将源数据、键值、属性值传入defineReactive函数中
defineReactive函数中通过Object.defineProperty对对象的每一项进行监听,如果修改了对象就触发了updateView函数。
Object.defineProperty如何深度监听data变化 ?
如果data是一个复杂对象,应该如何监听呢?我们将data替换成下面代码,再将children进行修改,看是否会触发updateView。
- const data = {
- name: '张三',
- age: 21,
- children: {
- name: '李四'
- }
- }
-
- data.children.name = 'lisi'
-
打开控制台可以看到,并未输出内容,因此,Object.defineProperty不能够深度监听对象。
想到深度监听,我们就可以使用递归转换成监听普通对象,
① 在defineReactive函数中Object.defineProperty调用之前调用oberserv函数,将传过来的属性值进行再次判断
- function defineReactive(target, key, value) {
- // 深度监听
- observe(value)
- Object.defineProperty(target, key, {
- get() {
- return value
- },
- set(newValue) {
- if (newValue !== value) {
- value = newValue
- updateView()
- }
- }
- })
- }
如果我们给data新增属性或者删除属性,我们还能够监听的到吗?
-
- data.sex = 'man'
- delete data.name
-
加入以上代码,如果能监听的到的话,控制台会打印两次“视图更新”,但是我们看控制台并未打印任何内容
因此,Object.defineProperty无法监听新增、删除属性,于是vue2.x通过Vue.set和Vue.delete来进行新增和删除属性
- const arrProto = Object.create(Array.property)
- // 数组的方法名称
- let arrFn = [
- 'push',
- 'pop',
- 'shift',
- 'unshift',
- ...
- ]
- arrFn.forEach(method => {
- arrProto[method] = function() {
- // 视图更新
- updateView()
- Array.propery[method].call(this, ..arguments)
- }
- })
在observe函数中进行数组判断,并将源数据的原型指向arrProto
- function observe(target) {
- if (target === null || typeof target !== 'object') {
- return target
- }
- if (Array.isArray(target)) }{
- target.__proto__ = arrProto
- }
- for(let key in target) {
- defineReactive(target, key, target[key])
- }
- }
注: 当data中的某一项是数组时,在observe函数中遍历进入defineReactive中,然后进行深度监听,如果是数组的话,就会将此数组的原型指向为arrProto,此时当前数组调用的数组方法,就会执行updateView()和数组原型的方法。
例如,执行data.nums.push(4),
① 进入observe函数
② for…in…循环
③ 进入defineReactive
④ 深度监听,进入observe
⑤ 判断是否是数组
⑥ 将数组的原型指向arrProto
⑦ 执行updateView
⑧ 执行Array.prototype的push方法
Object.defineProperty的缺点
如果data的层级过深,就会一次性递归到底,计算量很大。
Object.defineProperty无法监听新增、删除属性。 (vue中需使用$set();方法新增双向绑定属性)
Object.defineProperty不具备监听原生数组。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。