深刻理解 Getter和Setter 对对象的属性监听

阅读目录html

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

在作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); 

打印会以下所示:函数

当咱们继续打印以下信息:this

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这样的方法。spa

二:Object.prototype.__defineGetter__ 和 Object.prototype.__defineSetter__prototype

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

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

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方法的对象。

那么具体项了解该方法的使用及详解,请看我这篇文章(http://www.javashuo.com/article/p-qpgkyhbt-hh.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是啥,是干啥使用的,请看我这篇文章(http://www.javashuo.com/article/p-gfvzjduv-be.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
相关文章
相关标签/搜索