zoukankan      html  css  js  c++  java
  • 深入理解 Getter和Setter 对对象的属性监听

    阅读目录

    一:理解普通对象在声明时添加 get、set

    在做vue的时候,我们经常会看到 data里面的属性 都有 get 和 set方法,如下所示:

    如上vue中data里面它有两个属性,一个xxx 数组 和 一个 testA对象,但是都有get和set方法。也就是说在vue中data里面的每个属性都有两个相对应的get和set方法。为什么会有这样的呢?下面我们先来看一个普通的对象,如下代码所示:

    const obj = {
      name: 'kongzhi',
      _age: 30,
      get age() {
        return this._age;
      },
      set age(x) {
        this._age = x;
      }
    };
    
    console.log(obj); 

    打印会如下所示:

    当我们继续打印如下信息:

    console.log(obj._age); // 输出:30 
    console.log(obj.age); // 输出:30
    
    // 设置值
    obj.age = 31;
    
    console.log(obj.age); // 输出:31
    
    console.log(obj.age()); // Uncaught TypeError: obj.age is not a function

    如上代码演示所示,我们在对象里面使用 get 或 set定义的 age, 它只是obj中的一个属性,它并不是方法,因此如上我们使用获取属性的值或设置属性的值操作是正常的,当我们使用 obj.age() 把它当做一个方法调用的时候,它会报错。因此在vue中所有的属性有get、set这样的,当我们自动给某个属性赋值的时候,它会自动调用 set对应的方法,当我们获取某个属性的时候,它会自动调用get方法。但是我们不能手动调用 set/get xxx() 中的xxx这样的方法。

    二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__

    上面只是在声明obj对象的时候,编写get和set 对应的属性。但是如果已经存在的对象的时候,再想继续添加 get/set呢?那只有使用

    Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 了,如下代码演示:

    const obj = {
      name: 'kongzhi',
      _age: 30
    };
    
    obj.__defineGetter__('age', function(){
      console.log('监听到正在获取属性age的值');
      return this._age;
    });
    
    obj.__defineSetter__('age', function(value) {
      console.log('监听到正在设置属性age的值为:' + value);
      this._age = value;
    });
    
    /*
     * 打印:监听到正在获取属性age的值
     * 输出:30
    */
    console.log(obj.age);
    
    // 打印:监听到正在设置属性age的值为:31
    obj.age = 31;
    
    /*
     * 打印:监听到正在获取属性age的值
     * 输出: 31
    */
    console.log(obj.age);

    但是呢?Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__ 这个方法已经不推荐使用了,并且随着以后浏览器的发展,可能会不再支持该方法,那怎么办呢?当然会有新的替代方案的,我们继续往下讲。

    三:Object.defineProperty

    该方法它是由两部分组成,分别是:数据描述符和访问器描述符,数据描述符的含义是:它是一个包含属性的值,并说明这个属性值是可读或不可读的对象。访问器描述符的含义是:包含该属性的一对 getter/setter方法的对象。

    那么具体项了解该方法的使用及详解,请看我这篇文章(https://www.cnblogs.com/tugenhua0707/p/10261170.html),下面看使用 Object.defineProperty 来监听对象属性值的变化,如下代码:

    const obj = {
      name: 'kongzhi',
      _age: 30
    };
    Object.defineProperty(obj, 'age', {
      get() {
         console.log('监听到正在获取属性age的值');
         return this._age;
      },
      set(value) {
        console.log('监听到正在设置属性age的值为:' + value);
        this._age = value;
        return this._age;
      }
    });
    
    /*
     * 打印:监听到正在获取属性age的值
     * 输出:30
    */
    console.log(obj.age);
    
    // 打印:监听到正在设置属性age的值为:31
    obj.age = 31;
    
    /*
     * 打印:监听到正在获取属性age的值
     * 输出: 31
    */
    console.log(obj.age);

    四:Object.defineProperties

    Object.defineProperties 是对 Object.defineProperty的扩展的,它可以一次性添加多个/修改多个对象属性描述符。
    如下代码演示:

    const obj = {
      _name: 'kongzhi',
      _age: 30
    };
    Object.defineProperties(obj, {
      age: {
        get() {
          console.log('监听到正在获取属性age的值');
          return this._age;
        },
        set(value) {
          console.log('监听到正在设置属性age的值为:' + value);
          this._age = value;
          return this._age;
        }
      },
      name: {
        get() {
          console.log('监听到正在获取属性name的值');
          return this._name;
        },
        set(value) {
          console.log('监听到正在设置属性name的值为:' + value);
          this._name = value;
          return this._name;
        }
      }
    });
    /*
     * 打印:监听到正在获取属性age的值
     * 输出:30
    */
    console.log(obj.age);
    
    // 打印:监听到正在设置属性age的值为:31
    obj.age = 31;
    
    /*
     * 打印:监听到正在获取属性age的值
     * 输出: 31
    */
    console.log(obj.age);
    
    console.log('-------下面是对象name属性的监听-------');
    /*
     * 打印:监听到正在获取属性name的值
     * 输出:kongzhi
    */
    console.log(obj.name);
    
    // 打印:监听到正在设置属性name的值为:longen
    obj.name = 'longen';
    
    /*
     * 打印:监听到正在获取属性name的值
     * 输出: longen
    */
    console.log(obj.name);

    五:Proxy

    那么具体了解Proxy是啥,是干啥使用的,请看我这篇文章(https://www.cnblogs.com/tugenhua0707/p/10306793.html);

    那么它也可以监听对象属性值的变化,如下代码演示:

    const target = {
      name: 'kongzhi'
    };
    
    const handler = {
      get: function(target, key) {
        console.log(`${key} 被读取`);
        return target[key];
      },
      set: function(target, key, value) {
        console.log(`${key} 被设置为 ${value}`);
        target[key] = value;
      }
    };
    
    const testObj = new Proxy(target, handler);
    
    /*
      获取testObj中name属性值
      会自动执行 get函数后 打印信息:name 被读取 及输出名字 kongzhi
    */
    console.log(testObj.name);
    
    /*
     改变target中的name属性值
     打印信息如下: name 被设置为 111 
    */
    testObj.name = 111;
    
    console.log(target.name); // 输出 111
  • 相关阅读:
    发一弹
    压缩图片
    页面返回并刷新页面
    贤心的WEB弹窗挺不错的
    SMS短信发送API 以后可以弄个短信验证了
    <many-to-one>的fetch属性
    AJAX技术
    中国土地所有权的属性
    Today 's check:mappingResource属性和mappingDirectoryLocations属性的使用
    Pattern类的中文版 菜鸟翻译 有错请纠
  • 原文地址:https://www.cnblogs.com/tugenhua0707/p/10324983.html
Copyright © 2011-2022 走看看