# JavaScript-2:面向对象 vs JavaScript中的面向对象


(题图:梵高-开花的杏树)


对象的特征如下:


  • 对象具有唯一标识性:即使完全相同的两个对象,也并非同一个对象。
  • 对象有状态:对象具有状态,同一对象可能处于不同状态之下。
  • 对象具有行为:即对象的状态,可能因为它的行为产生变迁。


JavaScript 中对象独有的特色是:对象具有高度的动态性,这是因为 JavaScript 赋予了使用者在运行时为对象添改状态和行为的能力。 如果你用过 Java 或者其它别的语言,肯定会产生跟我一样的感受。


# JavaScript 对象的两类属性


对 JavaScript 来说,属性并非只是简单的名称和值,JavaScript 用一组特征(attribute)来描述属性(property)。


属性又分为:数据属性和访问器(getter/setter)属性


# 数据属性


数据属性具有4个特征:


  • value:就是属性的值。
  • writable:决定属性能否被赋值。
  • enumerable:决定 for in 能否枚举该属性。
  • configurable:决定该属性能否被删除或者改变特征值。


在大多数情况下,我们只关心数据属性的值即可。


# 访问器(getter/setter)属性


访问器(getter/setter)属性也具有4个特征:


  • getter:函数或 undefined,在取属性值时被调用。
  • setter:函数或 undefined,在设置属性值时被调用。
  • enumerable:决定 for in 能否枚举该属性。
  • configurable:决定该属性能否被删除或者改变特征值。


访问器属性使得属性在读和写时执行代码,它允许使用者在写和读属性时,得到完全不同的值,它可以视为一种函数的语法糖。


我们通常用于定义属性的代码会产生数据属性,其中的 writable、enumerable、configurable 都默认为 true。


我们可以使用内置函数 Object.getOwnPropertyDescripter 来查看,如以下代码所示:


var o = { a: 1 };
o.b = 2;
//a 和 b 皆为数据属性
Object.getOwnPropertyDescriptor(o,"a") // {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,"b") // {value: 2, writable: true, enumerable: true, configurable: true} 


如果我们要想改变属性的特征,或者定义访问器属性,我们可以使用 Object.defineProperty,示例如下:


var o = { a: 1 };
Object.defineProperty(o, "b", {value: 2, writable: false, enumerable: false, configurable: true});
//a和b都是数据属性,但特征值变化了
Object.getOwnPropertyDescriptor(o,"a"); // {value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor(o,"b"); // {value: 2, writable: false, enumerable: false, configurable: true}
o.b = 3;
console.log(o.b); // 2 


在创建对象时,也可以使用 getset 关键字来创建访问器属性,代码如下所示:


var o = { 
   get a() {
       console.log('getter');
       return a;
   },
   set a(val) {
       console.log('setter');
       a = val;
   }
};

o.a = 123;
console.log(o.a); // setter getter 123 


实际上 JavaScript 对象的运行时是一个“属性的集合”,属性以字符串或者 Symbol 为 key,以数据属性特征值或者访问器属性特征值为 value。


比如上面 a 为对象o的key,访问器属性或者{writable:true,value:1,configurable:true,enumerable:true} 为value。


到这里,可以理解有人得出 “JavaScript 不是面向对象”  的说法, 但是 JavaScript 提供了完全运行时的对象系统,这使得它可以模仿多数面向对象编程范式,所以它也是正统的面向对象语言。


JavaScript 语言标准也已经明确说明,JavaScript 是一门面向对象的语言,我想标准中能这样说,正是因为 JavaScript 的高度动态性的对象系统。