Getter and Setter

2015-04-19 Jason Liao 更多博文 » 博客 » GitHub »

原文链接 http://jasonliao.me/posts/2015-04-19-getter-and-setter.html
注:以下为加速网络访问所做的原文缓存,经过重新格式化,可能存在格式方面的问题,或偶有遗漏信息,请以原文为准。


从一个视频里接触到 JavaScript 的getset

一般来说,我们是怎么给我们类的属性定义getset方法的呢

var Person = function (age) {
  this.age = age;
};

Person.prototype = {
  getAge: function () {
    return this.age;
  },
  setAge: function (age) {
    this.age = age;
  }
};

var p1 = new Person(19);
var p2 = new Person(23);

我们定义了一定 Person 的类,他的每个实例都有age这个属性,它们都会指向相同的Person.prototype,所以有同样的getAgesetAge的方法

console.log(p1.age); // 19
console.log(p2.age); // 23
p1.age = 20;
console.log(p1.age); // 20
console.log(p2.age); // 23

为什么我们可以用p1.age这样来获得属性的值呢?为什么p1.age = 20又可以改变属性的值呢?

因为每个属性都有有一对自带的getset方法,当你想取得某属性的值的时候,就会调用这个属性的get方法;当你想修改这个属性的值的时候,就会调用这个属性的set方法

看下面这个例子

var Person = function(age) {
  this.age = age;
};

Person.prototype = {
  get age() {
    console.log('here is get');
  },
  set age(val) {
    console.log('here is set');
  }
};

var p1 = new Person(19);    // here is set 
var p2 = new Person(23);    // here is set

console.log(p1.age);
// here is get
// undefined

你们看到这时控制台打印了两次here is set, 这是因为在实例化的时候,需要为每个实例的age赋值,就是要修改属性的值,所以就会调用该属性的set方法

也正是因为我们只是在set里打印了一句话,并没有真正地给age赋值,所以当我们用p1.age去拿值的时候,就会返回 undefined,但是在取得值之前,我们是调用了get方法,所以会先打印出 here is get

getset的内部实现是怎样的呢?

Person.prototype = {
  age : {
    get age() {
      return this.age;
    },
    set : age(val) {
      this.age = val;
    }
  }
};

不知道~

自定义getset方法有什么用?

我们可以用getset方法来定义一些变量,一些要基于我们其他变量才可以确定的变量,看例子

var Person = function(age) {
  this.age = age;
};

Person.prototype = {
  get birthYear() {
    return (new Date()).getFullYear() - this.age;
  },
  set birthYear(val) {
    this.age = (new Date()).getFullYear() - val;
  }
};

var p1 = new Person(19);    
var p2 = new Person(23);

console.log(p1.birthYear);    //1996
console.log(p2.birthYear);    //1992

p1.age = 20;
p2.birthYear = 1994;
console.log(p1.birthYear);    //1995
console.log(p2.age);          //21

因为我们 birthYear 的get方法是根据this.age返回,而每个this.age都在实例里存在一份,所以 birthYear 虽然不是实例的属性,但是却互不干扰; 而在set方法里,当我们设置 birthYear 的值的时候,会修改我们的this.age,所以可以做到修改任意一个,另一个也会发生改变

这样做有什么好处吗?

  1. 我们不用在构造函数里定义那么多属性,换句话说,我们在实例化的时候,不需要传入那么多参数
  2. 只在原型里定义了getset方法的属性不会在多份实例里占内存,只存在一份在prototype里,节省内存,但却可以互不干扰

如有错误,欢迎指正 :)