对象就是一组“键值对”(key-value)的集合,是一种无序的复合数据集合。

  1. var obj = {
  2. foo: 'Hello',
  3. bar: 'World'
  4. };

对象的所有键名都是字符串(ES6 又引入了 Symbol 值也可以作为键名),所以加不加引号都可以。如果键名是数值,会被自动转为字符串。如果键名不符合标识名的条件(比如第一个字符为数字,或者含有空格或运算符),且也不是数字,则必须加上引号,否则会报错。

对象的每一个键名又称为“属性”(property),它的“键值”可以是任何数据类型:

  • 如果一个属性的值为函数,通常把这个属性称为“方法”,它可以像函数那样调用。
  • 如果属性的值还是一个对象,就形成了链式引用。

对象的属性之间用逗号分隔,最后一个属性后面可以加逗号(trailing comma),也可以不加。属性可以动态创建,不必在对象声明时就指定。

如果不同的变量名指向同一个对象,那么它们都是这个对象的引用,也就是说指向同一个内存地址。修改其中一个变量,会影响到其他所有变量。如果两个变量指向同一个原始类型的值。那么,变量这时都是值的拷贝。

对于首行{}开头的,JavaScript 引擎的做法是,如果遇到这种情况,无法确定是对象还是代码块,一律解释为代码块。如果要解释为对象,最好在大括号前加上圆括号。因为圆括号的里面,只能是表达式,所以确保大括号只能解释为对象。

读取对象的属性,有两种方法,一种是使用点运算符,还有一种是使用方括号运算符。请注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。方括号运算符内部还可以使用表达式。数字键可以不加引号,因为会自动转成字符串。注意,数值键名不能使用点运算符(因为会被当成小数点),只能使用方括号运算符。

点运算符和方括号运算符,不仅可以用来读取值,还可以用来赋值。JavaScript 允许属性的“后绑定”,也就是说,你可以在任意时刻新增属性,没必要在定义对象的时候,就定义好属性。

查看一个对象本身的所有属性,可以使用Object.keys方法。

  1. var obj = {
  2. key1: 1,
  3. key2: 2
  4. };
  5. Object.keys(obj);
  6. // ['key1', 'key2']

delete命令用于删除对象的属性,删除成功后返回true。

in运算符用于检查对象是否包含某个属性(注意,检查的是键名,不是键值),如果包含就返回true,否则返回false。它的左边是一个字符串,表示属性名,右边是一个对象。

in运算符的一个问题是,它不能识别哪些属性是对象自身的,哪些属性是继承的。就像上面代码中,对象obj本身并没有toString属性,但是in运算符会返回true,因为这个属性是继承的。

这时,可以使用对象的hasOwnProperty方法判断一下,是否为对象自身的属性。

Object对象

Object对象的原生方法分成两类:Object本身的方法与Object的实例方法。

(1) 静态方法(是指部署在Object对象自身的方法)/Object本身的方法

  1. Object.print = function (o) { console.log(o) };

(2) Object的实例方法

  1. Object.prototype.print = function () {
  2. console.log(this);
  3. };
  4. var obj = new Object();
  5. obj.print() // Object

Object 构造函数

通过var obj = new Object()的写法生成新对象,与字面量的写法var obj = {}是等价的。或者说,后者只是前者的一种简便写法。

虽然用法相似,但是Object(value)与new Object(value)两者的语义是不同的,Object(value)表示将value转成一个对象,new Object(value)则表示新生成一个对象,它的值是value。

Object 的静态方法

Object.keys方法的参数是一个对象,返回一个数组。该数组的成员都是该对象自身的(而不是继承的)所有属性名。

Object.getOwnPropertyNames方法与Object.keys类似,也是接受一个对象作为参数,返回一个数组,包含了该对象自身的所有属性名。(包括了不可枚举的属性名)

Object 的实例方法

除了静态方法,还有不少方法定义在Object.prototype对象。它们称为实例方法,所有Object的实例对象都继承了这些方法。

Object.prototype.valueOf() 返回一个对象的“值”,默认情况下返回对象本身。主要用途是,JavaScript 自动类型转换时会默认调用这个方法:将对象obj与数字1相加,这时 JavaScript 就会默认调用valueOf()方法,求出obj的值再与1相加。

Object.prototype.toString() 返回一个对象的字符串形式,默认情况下返回类型字符串。new Object() -> 字符串[object Object]本身没有太大的用处,但是通过自定义toString方法,可以让对象在自动类型转换时,得到想要的字符串形式。数组、字符串、函数、Date 对象都分别部署了自定义的toString方法,覆盖了Object.prototype.toString方法。

Object.prototype.hasOwnProperty 方法接受一个字符串作为参数,返回一个布尔值,表示该实例对象自身是否具有该属性。

对象构造函数

Vehicle就是构造函数。为了与普通函数区别,构造函数名字的第一个字母通常大写。

  1. var Vehicle = function () {
  2. this.price = 1000;
  3. };

使用new命令时,根据需要,构造函数也可以接受参数。

new命令本身就可以执行构造函数,所以后面的构造函数可以带括号,也可以不带括号。下面两行代码是等价的,但是为了表示这里是函数调用,推荐使用括号。

如果忘了使用new命令,构造函数就变成了普通函数,并不会生成实例对象。而且由于后面会说到的原因,this这时代表全局对象,将造成一些意想不到的结果。

为了保证构造函数必须与new命令一起使用,一个解决办法是,构造函数内部使用严格模式,即第一行加上use strict。这样的话,一旦忘了使用new命令,直接调用构造函数就会报错。

由于严格模式中,函数内部的this不能指向全局对象,默认等于undefined,导致不加new调用会报错(JavaScript 不允许对undefined添加属性)。

另一个解决办法,构造函数内部判断是否使用new命令,如果发现没有使用,则直接返回一个实例对象。

使用new命令时,它后面的函数依次执行下面的步骤:

  1. 创建一个空对象,作为将要返回的对象实例。
  2. 将这个空对象的原型,指向构造函数的prototype属性。
  3. 将这个空对象赋值给函数内部的this关键字。
  4. 开始执行构造函数内部的代码。

Object.create() 创建实例对象,就是复制一个对象。