JavaScript的对象是一堆部属(property)的集合,每个部属是一个从名字到值的映射。从形式上,这构成了一种关联数组的形态。对象的部属可以是是另一个对象,这就构成了对象的嵌套,从而能让JavaScript表示复杂的数据结构。此外,对象还有类型之分。最基本的对象类型是"object"。

通过objectName.propertyName可以引用对象objectName的propertyName部属。

通过var myCar = new Object();的形式可以创建一个新的对象。这样创建出来的对象存在一些默认的部属,比如__proto__(用来实现对象类型的延展)。虽然Javascript的类型系统中只有固定的几种类型,比如数值、字符串、对象、undefine、null等待。当时Javascript对象可以通过__proto__标签给对象做标记,让对象具有不同的行为。这和C++等静态语言有一定的区别,C++的对象在创建时,其类型必须是已经确定的。Javascript则不然,可以在对象创建后通过修改__proto__来达到修改自身行为的效果。这里的隐喻是:对象的行为是由其类型决定的。

JavaScript的对象部属有两个访问方式:myObject.hello 或者 myObject['hello']。部属的名字可以事任意的可以转化为(调用Object.toString())字符串的值(空字符串也是一个合法的部属名)或者是Symbol类型。如果访问的部属在对象中没有定义,那么会返回undefined类型。比如打开一个浏览器,在其console中输入window.non_existing_prop会返回undefined。

下面的代码会访问对象自身的部属:

for (var i in obj) {
  if (obj.hasOwnProperty(i)) {
    console.log (`${i}, ${obj[i]}`)
  }
}

上面的hasOwnProperty会忽略那些从原型继承而来的属性。除了for...in,还有下面两种办法:

  • Object.keys(o),返回一个自有的,可列举的部属名字列表
  • Object.getOwnPropertyNames(o),除了可列举的部属以外,还会附加不可列举的部属

可以通过Object.getPrototypeOf来回溯原型链,获取一个对象自身以及继承的所有部属。

删除一个部属,可以使用delete myobj.a这种语法

创建对象

可以从字面创建对象:

var obj = { a: 1, "b": 2}
var c="hello"
var obj2 = {c: 3, ...obj}

也可以通过构造函数创建:

function Elephant(trunk) {
  this.trunk = trunk
  this.whatType = function () { return this.type; }
}
// new 关键字用来给函数产生this变量
let elephant = new Elephant(20);

也可以使用Object.create来创建对象,而不用通过构造函数。这个方法的特殊之处是,它可以通过:

Object.create(null)
a.__proto__ === undefined
a.hasOwnProperty === undefined

来创建没有原型的对象。参考Object.create(null)

访问控制

可以使用getter和setter来控制对某个部属的访问:

let o = { get hi() { return "hello" } }
o.hi // hello

也可以用Object.defineProperty来创建,比如:

var d = Date.prototype;
Object.defineProperty(d, 'year', {
  get: function() { return this.getFullYear(); },
  set: function(y) { this.setFullYear(y); }
})

或者是Object.defineProperties:

var o = { a: 0 };

Object.defineProperties(o, {
    'b': { get: function() { return this.a + 1; } },
    'c': { set: function(x) { this.a = x / 2; } }
});

其他