当前位置:   article > 正文

Object.defineproperty

object.defineproperty

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

        }

setget(即存取器描述:定义属性如何被存取)

get 是获取值的时候的方法,类型为 function ,获取值的时候会被调用,不设置时为 undefined

set 是设置值的时候的方法,类型为 function ,设置值的时候会被调用,undefined

  get或set不是必须成对出现,任写其一就可以

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8" />
  5. <title>Object.defineproperty方法</title>
  6. </head>
  7. <body>
  8. <script type="text/javascript" >
  9. let number = 18
  10. let person = {
  11. name:'张三',
  12. sex:'男',
  13. }
  14. Object.defineProperty(person,'age',{
  15. // value:18,
  16. // enumerable:true, //控制属性是否可以枚举,默认值是false
  17. // writable:true, //控制属性是否可以被修改,默认值是false
  18. // configurable:true //控制属性是否可以被删除,默认值是false
  19. //当有人读取person的age属性时,get函数(getter)就会被调用,且返回值就是age的值
  20. get(){
  21. console.log('有人读取age属性了')
  22. return number
  23. },
  24. //当有人修改person的age属性时,set函数(setter)就会被调用,且会收到修改的具体值
  25. set(value){
  26. console.log('有人修改了age属性,且值是',value)
  27. number = value
  28. }
  29. })
  30. // console.log(Object.keys(person))
  31. console.log(person)
  32. </script>
  33. </body>
  34. </html>

vue2.0是如何监听双向绑定的?

  1. function updateView() {
  2. console.log('视图更新');
  3. dom.innerHtml=data.name;//将data的name属性值渲染在dom元素中.
  4. }
  5. function defineReactive(target, key, value) {
  6. Object.defineProperty(target, key, {
  7. get() {
  8. return value
  9. },
  10. set(newValue) {
  11. if (newValue !== value) {
  12. value = newValue
  13. updateView()
  14. }
  15. }
  16. })
  17. }
  18. function observe(target) {
  19. if (target === null || typeof target !== 'object') {
  20. return target
  21. }
  22. for(let key in target) {
  23. defineReactive(target, key, target[key])
  24. }
  25. }
  26. const data = {
  27. name: '张三',
  28. age: 21
  29. }
  30. observer(data)
  31. data.name = 'lisi'

oberve函数判断源数据是否是对象,然后遍历,将源数据、键值、属性值传入defineReactive函数中

​ defineReactive函数中通过Object.defineProperty对对象的每一项进行监听,如果修改了对象就触发了updateView函数。

Object.defineProperty如何深度监听data变化 ?

如果data是一个复杂对象,应该如何监听呢?我们将data替换成下面代码,再将children进行修改,看是否会触发updateView。

  1. const data = {
  2. name: '张三',
  3. age: 21,
  4. children: {
  5. name: '李四'
  6. }
  7. }
  8. data.children.name = 'lisi'

打开控制台可以看到,并未输出内容,因此,Object.defineProperty不能够深度监听对象。

​ 想到深度监听,我们就可以使用递归转换成监听普通对象,

​ ① 在defineReactive函数中Object.defineProperty调用之前调用oberserv函数,将传过来的属性值进行再次判断

  1. function defineReactive(target, key, value) {
  2.     // 深度监听
  3.     observe(value)
  4.     Object.defineProperty(target, key, {
  5.         get() {
  6.             return value
  7.         },
  8.         set(newValue) {
  9.             if (newValue !== value) {
  10.                 value = newValue
  11.                 updateView()
  12.             }
  13.         }
  14.     })
  15. }

Object.defineProperty监听新增、删除属性

​ 如果我们给data新增属性或者删除属性,我们还能够监听的到吗?

  1. data.sex = 'man'
  2. delete data.name

加入以上代码,如果能监听的到的话,控制台会打印两次“视图更新”,但是我们看控制台并未打印任何内容

​ 因此,Object.defineProperty无法监听新增、删除属性,于是vue2.x通过Vue.setVue.delete来进行新增和删除属性

监听数组变化

  1. const arrProto = Object.create(Array.property)
  2. // 数组的方法名称
  3. let arrFn = [
  4. 'push',
  5. 'pop',
  6. 'shift',
  7. 'unshift',
  8. ...
  9. ]
  10. arrFn.forEach(method => {
  11. arrProto[method] = function() {
  12. // 视图更新
  13. updateView()
  14. Array.propery[method].call(this, ..arguments)
  15. }
  16. })

在observe函数中进行数组判断,并将源数据的原型指向arrProto

  1. function observe(target) {
  2. if (target === null || typeof target !== 'object') {
  3. return target
  4. }
  5. if (Array.isArray(target)) }{
  6. target.__proto__ = arrProto
  7. }
  8. for(let key in target) {
  9. defineReactive(target, key, target[key])
  10. }
  11. }

注: 当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不具备监听原生数组。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/259024
推荐阅读
相关标签
  

闽ICP备14008679号