JavaScript监听对象属性的改变

目前监听JS中的变量变化的方法很多,流行的MVVM的JS库/框架的共同特点就是数据绑定, 在数据变更后响应式的自动进行相关计算并变更DOM展现

常见的监听方法

1. 基于ES5的getter和setter

在ES5中新增了一个Object.defineProperty, 直接在一个对象上定义一个新属性, 或者修改一个已存在的属性,并返回这个对象。

Object.defineProperty(obj, prop, descriptor)

参数
obj
要在其上定义属性的对象。
prop
要定义或修改的属性的名称。
descriptor
将被定义或修改的属性描述符。

var obj={};
Object.defineProperty(obj,'data',{
    get:function(){
        return data;
    },
    set:function(newValue){
        data=newValue;
        console.log('set :',newValue);
        //需要触发的渲染函数写在这...
    }
})

当我们给obj的data赋值的时候,就会触发set 的方法

    obj.data=5;//set: 5

如果要一下子定义多个变量的getter和setter,你可以使用Object.defineProperties(obj,props)

参数
obj
要在其上定义属性的对象。
props
要定义其可枚举属性或修改的属性描述符的对象。

 var obj = {};
Object.defineProperties(obj, {
    a: {
        configurable: true, //表示该属性描述符可以被改变(默认为false)
        get: function() {
            console.log('get: ',a)
            return a
        },
        set: function(newValue) {
            a = newValue;
            console.log('set: ',a)
        }
    },
    b: {
        configurable: true,
        get: function() {
            console.log('get: ',b)
            return b;
        },
        set: function(newValue) {
            b = newValue;
            console.log('set: ',b)
        }
    }
})
2. 脏值检测

脏值检测原理就是比较新值和旧值, 当值真的发生改变时再去更改DOM,目前Angular使用脏值检测

缺点是如果不注意,每次脏值检测会检测大量的数据, 而很多数据是没有检测的必要的,容易影响性能。

3. ES6的Proxy

类似HTTP中的代理:

let p = new Proxy(target, handler);

target
用Proxy包装的目标对象(可以是任何类型的对象,包括原生数组,函数,甚至另一个代理)。
handler
一个对象,其属性是当执行一个操作时定义代理的行为的函数。

示例:当对象中不存在属性名时,缺省返回数为37

let handler = {
    get: function(target, name){
        return name in target ? target[name] : 37;
    }
};

let p = new Proxy({}, handler);

p.a = 1;
p.b = undefined;

console.log(p.a, p.b);    // 1, undefined

console.log('c' in p, p.c);    // false, 37

示例:通过代理,验证向一个对象的传值

let validator = {
  set: function(obj, prop, value) {
    if (prop === 'age') {
      if (!Number.isInteger(value)) {
        throw new TypeError('The age is not an integer');
      }
      if (value > 200) {
        throw new RangeError('The age seems invalid');
      }
    }

    // The default behavior to store the value
    obj[prop] = value;
  }
};

let person = new Proxy({}, validator);

person.age = 100;

console.log(person.age); 
// 100

person.age = 'young'; 
// 抛出异常: Uncaught TypeError: The age is not an integer

person.age = 300; 
// 抛出异常: Uncaught RangeError: The age seems invalid

(来源于:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/Proxy

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 国家电网公司企业标准(Q/GDW)- 面向对象的用电信息数据交换协议 - 报批稿:20170802 前言: 排版 ...
    庭说阅读 11,167评论 6 13
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,142评论 1 32
  • 函数和对象 1、函数 1.1 函数概述 函数对于任何一门语言来说都是核心的概念。通过函数可以封装任意多条语句,而且...
    道无虚阅读 4,663评论 0 5
  • 第3章 基本概念 3.1 语法 3.2 关键字和保留字 3.3 变量 3.4 数据类型 5种简单数据类型:Unde...
    RickCole阅读 5,162评论 0 21
  • 既然还是青年,就去做青年人该做的事情。 在闭着眼睛狂欢的人群中,不想随波逐流,你就必须学会沉默,学会拒绝,在沉默中...
    孟非黎阅读 150评论 0 2