侧边栏壁纸
博主头像
woku博主等级

成功的路上并不拥挤

  • 累计撰写 50 篇文章
  • 累计创建 13 个标签
  • 累计收到 3 条评论

vue数据劫持-前置知识

woku
2022-03-10 / 0 评论 / 0 点赞 / 169 阅读 / 4,061 字

defineProperty是什么

Object.defineProperty 肯定是Object底下的一个内置方法

define :定义

property:属性

那么defineProperty就是给对象定义属性

为啥要使用defineProperty

给对象定义属性,可以使用

var obj = {
  a: 1,
  b: 2
}

但是我想让这个对象的a这个值不可修该怎么办呢?我想当obj的a属性赋值的时候,做一些其他的事情,该怎么办呢?

defineProperty帮你搞定!

基本使用

参数

  • 第一个参数:要给谁定义属性

  • 第二个参数:定义什么属性

  • 第三个参数:定义的这个属性的描述项 value:值 writable: 是否可修改 enumerable:是否可枚举 configurable:是否可配置

var obj = {
}
Object.defineProperty(obj,'a',{
  value:1,
  writable:true,  
  enumerable:true,
  configurable:true
})
Object.defineProperty(obj,'b',{
  value:2,
  writable: true,
  enumerable:true,
  configurable:true
})
console.log(obj.a)  // 1
console.log(obj.b)  // 2

多个属性一起定义

var obj = {}
Object.defineProperties(obj, {
  a: {
    value:1,
    writable:true,
    enumerable:true,
    configurable:true
  },
  b: {
    value:2,
    writable:true,
    enumerable:true,
    configurable:true
  }
})

// 描述项配置了writable 生效(能不能重新给属性赋值)
obj.a = 3
obj.b = 4
// 描述项配置了enumerable 生效 (能否枚举,遍历变量的属性)
for(var k in obj) {
  console.log(k)
}
// 描述项配置了configurable 生效(能否删除)
delete obj.a
console.log(obj.b)

getter和setter

getter 和 setter配置项中的一个方法,获取属性的时候执行getter方法,设置属性的时候执行setter方法

var obj = {}
var a = 1
Object.defineProperties(obj, {
  a: {
    get() {
      return `a is ${a}`
    },
    set(newV) {
      a = newV
      console.log(`a has been changed ${a}`)
    }
  },
})

console.log(obj.a) //获取值执行get    a is 1
obj.a = 3 //设置值执行set    a has been changed 3

使用getter和setter进行数据拦截
数据拦截:当进行获取值的时候,先断开,执行get函数中的相关逻辑程序
当设置值的时候,先断开,执行set函数中的相关逻辑程序

vue中的defineProperties

vue2中数据响应式原理就是使用的defineProperties,对实例中data的数据进行拦截,设置data时,执行set方法,通过vue中diff算法,比较新老虚拟DOM,最终render

一个简单的响应式demo

  <div class="content">
        <p class="result">0</p>
        <div class="input-grup">
            <input type="text" class="f-ipt">
            <input type="text" class="s-ipt">
        </div>
        <div class="btn-grup">
            <button class="current" data-field="plus">+</button>
            <button data-field="minus">-</button>
            <button data-field="mul">*</button>
            <button data-field="div">/</button>
        </div>
  </div>
class Computer {
    plus(fNumber,sNumber) {
        return fNumber + sNumber
    }
    minus(fNumber,sNumber) {
        return fNumber - sNumber
    }
    mul(fNumber,sNumber) {
        return fNumber * sNumber
    }
    div(fNumber,sNumber) {
        return fNumber / sNumber
    }
}

class Calculate extends Computer{
    constructor(doc) {
        super()
        this.oContent = doc.getElementsByClassName('content')[0]
        this.resultDom = doc.getElementsByClassName('result')[0]
        this.fInput = doc.getElementsByTagName('input')[0]
        this.sInput = doc.getElementsByTagName('input')[1]
        this.btnGroup = this.oContent.getElementsByClassName('btn-grup')[0]
        this.btnItems = this.btnGroup.getElementsByTagName('button')
        this.data = this.defineData()
        this.btnIndex = 0
    }
    init() {
        // 绑定事件
        this.bindEvent()
    }
    bindEvent() {
        this.btnGroup.addEventListener('click', this.onFiedBtnClick.bind(this), false)
        this.fInput.addEventListener('input', this.onInputChange.bind(this), false)
        this.sInput.addEventListener('input', this.onInputChange.bind(this), false)
    }
    defineData() {
        let _obj = {},
            fNumber = '',
            sNumber = '',
            field = 'plus'
        var _this = this
        // 数据拦截
        Object.defineProperties(_obj, {
            fNumber: {
                get() {
                    console.log('get fNumber')
                    return fNumber
                },
                set(newV) {
                    fNumber = newV
                    console.log('fNumber has been changed')
                    _this.getResult(fNumber, sNumber, field)
                }
            },
            sNumber: {
                get() {
                    console.log('get sNumber')
                    return sNumber
                },
                set(newV) {
                    sNumber = newV
                    console.log('sNumber has been changed')
                    _this.getResult(fNumber, sNumber, field)
                }
            },
            field: {
                get() {
                    console.log('get filed')
                    return field
                },
                set(newV) {
                    field = newV
                    console.log('field has been changed')
                    _this.getResult(fNumber, sNumber, field)
                }
            }
        })
        return _obj
    }
    onInputChange(e) {
        var event = e || window.event,
            tar = event.target || event.srcElement,
            tagClassName = tar.className,
            value = Number(tar.value.trim()) || 0
        switch (tagClassName) {
            case 'f-ipt':
                this.data.fNumber = value
                break;
            case 's-ipt':
                this.data.sNumber = value
                break;
        }

    }
    onFiedBtnClick(e) {
        var event = e || window.event,
            tar = event.target || event.srcElement,
            tagName = tar.tagName.toLowerCase()
        tagName === 'button' && this.filedUpdate(tar)

    }
    filedUpdate(tar) {
        this.btnItems[this.btnIndex].className = ''
        this.btnIndex = [].indexOf.call(this.btnItems, tar)
        tar.className += 'current'
        this.data.field = tar.getAttribute('data-field')
       
    }
    getResult(fNumber, sNumber, field) {
        this.resultDom.innerText = this[field](fNumber,sNumber)
    }
}
new Calculate(document).init()
0

评论区