Object.defineProperty理解及运用

目前阶段,国内前端’基础框架 - vue’异常火热,不论是面试、工作运用都不可或缺,其便利之处就在于页面内容随数据变化而自动变化,在此记录使用defineProperty自动渲染的示例,并根据此例来加深对于自动渲染的的理解

defineProperty & defineProperties

作用: 直接在一个对象上定义一个(多个)新属性,或者修改一个(多个)对象的现有属性,并返回此对象

value: 绑定属性的数值

writable: 是否可重写数据

enumerable: 是否可枚举对象键名(是否可被Object.keys())

configurable: 对象属性是否可被删除

defineProperty与defineProperties的区别就在于各自绑定属性的数量,defineProperties可同时绑定多个,而defineProperty绑定一个属性:

function Test1() {
      let obj = {},
          name = ''
      Object.defineProperty(obj, 'name', {
        // enumerable: false,
        // value: '伽罗',
        // writable: false,
        // configurable: false,
        get() {
          console.log('Test1: get new value(name): ' + name);
          return name;
        },

        set(newVal) {
          name = newVal;
          console.log('Test1: set new value(name): ' + newVal);
        }
      })
      return obj;
    }
    let t1 = new Test1()
    t1.name = '张三'
function Test2() {
      let obj = {},
          name= '',
          age = 18
      Object.defineProperties(obj, {
        name: {
          get() {
            console.log('Test2: get new value(name): ' + name);
            return name;
          },
          set(newVal) {
            name = newVal;
            console.log('Test2: set new value(name): ' + newVal);
          }
        },

        age: {
          get() {
            console.log('Test2: get new value(age): ' + age);
            return age;
          },
          set(newVal) {
            age = newVal;
            console.log('Test2: set new value(age): ' + newVal);
          }
        }
      })
      return obj;
    }
    let t2 = new Test2()
    t2.name = '张三'
    t2.age = 20

通过上述两个小例子可以看出各自的运用方式,但需要注意的一点是:
getter、setter和value、writable属性不能同时存在,否则会显示 Uncaught TypeError: Invalid property descriptor. Cannot both specify accessors and a value or writable attribute

想要查看详细信息可点击Object.defineProperty前往查看详情
后续是借助此功能编写的计算器功能,能够直接复制到本地运行查看效果
html内容:

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>计算器</title>
  <style>
    body{
      padding: 10px 20px;
    }
    input{
      height: 30px;
      outline: none;
      display: block;
      border: none;
      border-radius: 4px;
      box-shadow: 0 0 5px #cccccc;
      margin-bottom: 10px;
      padding-left: 5px;
    }
    button{
      width: 30px;
      height: 30px;
      border-radius: 4px;
      text-align: center;
      cursor: pointer;
      margin-right: 10px;
      outline: none;
      border: none;
      box-shadow: 0 0 5px #cccccc;
      user-select: none;
    }
    .result{
      color: #999999;
      font-size: 13px;
    }
    .result .num{
      color: #333333;
      font-size: 14px;
    }
    .btn-group .active{
      background: rgb(247, 163, 67);
      color: #ffffff;
    }
  </style>
</head>
<body>
  <div class="calculator">
    <p class="result">运算结果: <span class="num">0</span></p>
    <input class="f-input" type="number" value="0" />
    <input class="s-input" type="number" value="0" />
    <div class="btn-group">
      <button data-field="plus" class="active">+</button>
      <button data-field="minus">-</button>
      <button data-field="mul">*</button>
      <button data-field="div">/</button>
    </div>
  </div>
  
  <script src="./js/calculator.js"></script>
</body>
</html>

calculator.js:

// 算数运算类
class Compute {
  plus(a, b) {
    return a + b;
  }

  minus(a, b) {
    return a - b;
  }

  mul(a, b) {
    return a * b;
  }

  div(a, b) {
    if(a % b === 0) {
      return a / b;
    }else if(a / b) {
      return (a / b).toFixed(3) || 0;
    }else {
      return 0;
    }
    
  }
}

// 计算器类
class Calculator extends Compute {
  constructor(doc) {
    super();
    const oCal = doc.querySelector('.calculator');

    this.fInput = oCal.querySelector('.f-input');
    this.sInput = oCal.querySelector('.s-input');
    this.oBtnGroup = oCal.querySelector('.btn-group');
    this.oBtnItems = this.oBtnGroup.querySelectorAll('button');
    this.oResult = oCal.querySelector('.result .num');

    this.data = this.defineData();
    this.btnIdx = 0;
  }

  // 初始化
  init() {
    this.bindEvent();
  }

  // 绑定、监听元素
  bindEvent() {
    this.oBtnGroup.addEventListener('click', this.onFieldBtnClick.bind(this), false);
    this.fInput.addEventListener('input', this.onNumberInput.bind(this), false);
    this.sInput.addEventListener('input', this.onNumberInput.bind(this), false);
  }

  // 点击计算按钮
  onFieldBtnClick(ev) {
    const e = ev || window.event,
          tar = e.target || e.srcElement,
          tagName = tar.tagName.toLowerCase();
    tagName === 'button' && this.fieldUpdate(tar);
  }

  // 计算文字变化
  onNumberInput(ev) {
    const e = ev || window.event,
          tar = e.target || e.srcElement,
          className = tar.className,
          val = Number(tar.value.replace(/\s+/g, '')) || 0;
    
    switch(className) {
      case 'f-input':
        this.data.fNumber = val;
        break;
      case 's-input':
        this.data.sNumber = val;
        break;
      default:
        break;
    }
  }

  // 监听 - 切换运算符选中
  fieldUpdate(target) {
    this.oBtnItems[this.btnIdx].className = '';
    this.btnIdx = [].indexOf.call(this.oBtnItems, target);
    target.className += ' active';
    this.data.field = target.getAttribute('data-field');
  }

  // 渲染计算结果
  computeResult(fNumber, sNumber, field) {
    this.oResult.innerText = this[field](fNumber, sNumber);
  }

  // 数据监听
  defineData() {
    let _obj = {},
        fNumber = 0,
        sNumber = 0,
        field = 'plus';
    const _self = this;
    
    Object.defineProperties(_obj, {
      fNumber: {
        get() {
          return fNumber;
        },
        set(newVal) {
          fNumber = newVal;
          _self.computeResult(fNumber, sNumber, field);
        }
      },

      sNumber: {
        get() {
          return sNumber;
        },
        set(newVal) {
          sNumber = newVal;
          _self.computeResult(fNumber, sNumber, field);
        }
      },

      field: {
        get() {
          return field;
        },
        set(newVal) {
          field = newVal;
          _self.computeResult(fNumber, sNumber, field);
        }
      }
    })
    return _obj;
  }
}

new Calculator(document).init();

演示效果:
计算器自动根据内容改变计算并渲染
感谢大家读阅,若有何想法踊跃提问,一起思索
希望能帮到你,拜拜~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值