章节索引 :

JavaScript 对象

对象 指包含数据和用于处理数据的指令的数据结构. 对象有时也指现实世界中的一些事, 例如在赛车游戏当中一辆车或者一幅地图都可以是一个对象。—— MDN

JavaScript 中的对象由属性方法组成。

属性可以是任意 JavaScript 中的数据类型,方法则是一个函数。

1. 创建对象

对象的格式如下:

{
  prop1: 'value1',
  prop2: 666,
  prop3: {},
  method1: function() {
  },
}

其中 prop1prop2prop3 都是属性,method1 是方法,属性是任意的数据类型,方法则是一个函数。

可以看到一个属性或者方法,在其名字与值中间采用冒号 : 分隔,属性和方法之间采用逗号 , 分隔。

通常属性和方法的名字会被称为属性名方法名,属性的值称为属性值,方法的值则直接叫做 方法

对象符合 key/value 的结构,一个 key 对应一个 value,这种结构也被称为键值对,属性名和方法名都是 key,他们的值都是 value

注意:在 JavaScript 的对象中,方法和属性的表示其实是一样的。

一个属性的值如果是一个函数,则就把这个属性称之为方法,只是称呼上的不同。

对象最简单的创建方式就是使用对象字面量

var person = {};

以上创建了一个最简单的空对象。

对象在 JavaScript 中的应用范围非常广。

可以试想一下,如果需要用变量描述一个人的信息,包括名字、性别、年龄、双亲信息,同时就要表示这个人的一些行为,如说话。

显然数值、字符串、布尔类型这些数据类型是不太适合描述这样一个人的。

这个时候就可以考虑使用对象,也就是说当需要描述的事物变得复合(无法使用单一的数据类型描述的时候),就可以考虑使用对象存储数据。

var person = {
  'name': '小明',
  'age': 17,
  isAdult: false,
  sex: 'man',
  hobby: ['eat', 'sleep', 'play doudou'],
  parents: {
    mather: {
      name: '大红',
    },
    father: {
      name: '大明',
    },
  },
  say: function() {
    console.log('我叫' + this.name + ',我今年' + this.age + '岁了。');
  },
};

console.log(person); // 在控制台可以观察 person 对象

上面这个 person 变量就是一个对象,用于描述一个人,这个人具有 nameage 等属性与方法。

在控制台输出对象后,可以对其展开,观察他的内容。

其中部分属性在声明的时候,属性名上加上了引号,这在 JavaScript 中是被允许的,但一般情况下不会加上引号,原因之一是没有必要加,不应该与字符串混淆,另外一点就是可以消除初学者对 JSON 和 JavaScript 对象在理解上的歧义。

2. 操作对象

创建对象主要是为了设置、访问对象的属性值,调用对象的方法等。

2.1 访问对象的属性值

访问属性有 2 种方式:

  1. 对象.属性名
  2. 对象['属性名']
var obj = {
  key: 'value',
  say: function() {
    console.log('never 996');
  },
};

console.log(obj.key); // 输出:"value"
console.log(obj['key']); // 输出:"value"

obj.say(); // 输出:"never 996"
obj['say'](); // 输出:"never 996"

这两种方式都很常用。第二种通常会应用在需要用变量确定属性名的时候去使用。

var person = {
  age: 27,
  name: '鸽手',
};

Object.keys(person).forEach(function(key) {
  console.log(person[key]);
});

以上就是使用第二种方式的场景之一,使用 Object.keys() 获取到 person 的所有属性名组成的数组,对数组做遍历拿到每一个属性名并放在一个变量中,再通过变量访问到对应的属性值。

当试图访问一个不存在的属性的时候,则会返回 undefined

var obj = {};

console.log(obj.value); // 输出:undefined

2.2 设置对象的属性值

设置属性值也有 2 种方式:

  1. 对象.属性名 = 属性值
  2. 对象['属性名'] = 属性值

设置属性值的方式与访问值很相似,只是多了一个赋值操作。

设置属性值按照如下规则进行:

  • 如果对象中不存在这个属性,则创建这个属性并赋值
  • 如果对象中存在这个属性,则直接赋值
var person = {
  age: 22,
};

person.name = '阿花';
person['hobby'] = ['eat', 'play doudou'];

console.log(person);

person.age = 33;

console.log(person);

3. 使用特殊的属性名

对象的属性名是可以用任意字符串表示的。

上面有提到,声明属性的时候可以带上引号。

如果不带引号,那属性名必须要符合变量命名的规则,使用引号包裹属性名,则可以使用任意字符串作为属性名。

var obj = {
  --^$@@@age: 16,
};

上面这样写是会报错的,如果非要使用这样的属性名,就可以加上一对引号,可以双引号,也可以是单引号,使用引号的规则和字符串一致。

var obj = {
  '--^$@@@age': 16,
};

这种特殊的属性名无法通过 对象.属性名 的形式访问。

var obj = {
  '--^$@@@age': 16,
};

var val = obj.--^$@@@age;

JavaScript 无法解析这种特殊的语法,所以要使用 对象['属性名'] 的形式访问。

var obj = {
  '--^$@@@age': 16,
};

var val = obj['--^$@@@age'];

console.log(val); // 输出:16

特殊的属性名场景比较少,如统计字符串的场景。

var counter = {};

var strs = [
  '#@T%TGFDSgfdsgsf',
  '#@T%TGFDSgfdsgsf',
  '123fdafeafewa',
  '123fdafeafewa',
  '#@T%TGFDSgfdsgsf',
];

strs.forEach(function(item) {
  if (item in counter) {
    counter[item]++;
  } else {
    counter[item] = 0;
  }
});

console.log(counter);

strs 是由字符串组成的数组,即需要统计的一组数据。

利用对象的特性来对字符串分类计数。

4. 其他创建对象的方法

除了字面量的方式,还有许多创建对象的方式。

4.1 使用 Object 对象

使用 new Object() 或者 Object() 的方式也可以创建一个对象

var obj1 = new Object();
var obj2 = new Object; // 如果没有参数 可以不带括号

var obj3 = Object();

上面的方式都可以创建一个空对象。

比较有趣的是可以给 Object 传递一个对象字面量作为参数,返回的对象的属性与传入的对象字面量的属性一致。

var obj1 = new Object({
  age: 11,
  name: '长睫毛',
});

var obj2 = Object({
  age: 12,
  name: '小酒窝',
});

console.log(obj1, obj2);

4.2 构造函数

使用构造函数,也可以创建对象。

function Car(color, maxSpeed) {
  this.color = color;
  this.maxSpeed = maxSpeed;
}

Car.prototype.bibi = function() {
  console.log('哔哔!');
};

var car = new Car('red', 9999999);

console.log(car);

以上例子使用构造函数创建了一个速度超级快的车对象。

4.3 Object.create

使用 Object.create 也可以创建一个新对象,但是必须传递一个对象作为参数。

var parent = {
  walk: function() {
    console.log('走路');
  },
};

var son = Object.create(parent);

console.log(parent === son);

son.walk();

Object.create 会根据传递过去的对象生成一个新的对象,作为参数传递的对象会作为新对象的原型。

5. 遍历对象

5.1 for … in

var me = {height: 180, weight: 70};

var i;
for (i in me) {
  console.log(i);
  console.log(me[i]);
}

使用 for ... in 可以遍历对象的所有 key 值,也就是属性名,取到所有的属性就可以访问到所有的属性值。

需要注意的是 for ... in 循环只遍历可枚举属性,同时对象原型上的也会被访问到。

var me = {height: 180, weight: 70};

var you = Object.create(me);

you.age = 11;

var i;
for (i in you) {
  console.log(i);
}

上面这个例子就把 meyou 中的所有属性都遍历出来了。

可以使用 Object.prototype.hasOwnProperty 来判断一个属性是否只处于其本身而不在原型上。

var me = {height: 180, weight: 70};

var you = Object.create(me);

you.age = 11;

var i;
for (i in you) {
  if (you.hasOwnProperty(i)) {
    console.log(i);
  }
}

这样就只会输出 age 了。

5.2 Object.keys

Object.keys 会返回对象上的所有可枚举属性组成的数组。

var gugugu = {
  name: '?王',
  hobby: '放鸽子',
};

var keys = Object.keys(gugugu);

console.log(keys);

keys.forEach(function(key) {
  console.log(gugugu[key])
});

通过遍历属性组成的数组来遍历对象。

5.3 Object.getOwnPropertyNames

使用 Object.getOwnPropertyNames 也可以获取到由属性组成的数组,但数组会包括不可枚举的属性。

var gugugu = {
  name: '?王',
  hobby: '放鸽子',
};

var desc = Object.create(null);
desc.enumerable = false; // 是否可枚举 默认就是false
desc.value = '最强鸽手';

Object.defineProperty(gugugu, 'nickname', desc);

console.log(Object.keys(gugugu));
console.log(Object.getOwnPropertyNames(gugugu));

使用 getOwnPropertyNames 比使用 keys 多出一个不可枚举的 nickname 属性。

注意:ES6 还提供了Object.valuesObject.entriesfor ... ofReflect.ownKeys等特性,结合这些特性也能遍历一个对象。

6. 创建绝对纯净的对象

纯净对象仅为本篇中的称呼方式,这种特殊的对象没有特定的称呼。

纯净对象即原型为 null 的对象。

使用 Object.create(null) 来创建纯净对象。

var obj1 = Object.create(null);

console.log(obj1);

var obj2 = {};

console.log(obj2);

可以尝试在控制台中对比这两个对象,纯净对象是没有原型的,无法调用 toStringhasOwnPropertyvalueOf 这些原型上的方法。

大部分使用纯净对象的场景是使用 Object.defineProperty 为对象创建属性的时候,属性的描述需要一个绝对干净的对象,防止特殊的属性对描述造成影响。

另外的使用场景就是当作一个字典使用,防止原型上的内容对字典产生干扰。

7. 小结

对象最常用的两种创建方式,就是使用字面量和构造函数。

创建对象的时候应合理规划属性名和方法名,根据业务来确定如何使用对象。

前置知识
什么是JavaScript 开发与学习环境准备 调试方案
基础
JavaScript 变量 JavaScript 数据类型 JavaScript if 语句 JavaScript for 语句 JavaScript 算数运算符 JavaScript 比较运算符 JavaScript 逻辑运算符 JavaScript 表达式 JavaScript 函数 JavaScript 对象 JavaScript 字符串 JavaScript 数字 JavaScript 数组 JavaScript switch 语句 JavaScript while 语句 JavaScript break与continue JavaScript with document.cookie
内置对象
JavaScript Function JavaScript Math JavaScript Date JavaScript RegExp JavaScript JSON
JavaScript 与 DOM
什么是DOM DOM和JavaScript的关系 获取和操作 DOM 节点 JavaScript DOM与事件 JavaScript DOM 事件绑定 JavaScript DOM 事件对象 JavaScript DOM 事件流 JavaScript DOM 事件优化 JavaScript DOM 自定义事件
表单处理
使用 JavaScript 校验表单
BOM
BOM window 对象 常用的 BOM 相关对象 BOM 常用属性和方法
AJAX
JavaScript AJAX
进阶知识
JavaScript 异常处理 JavaScript 三元运算符 JavaScript 逗号操作符 JavaScript void JavaScript typeof JavaScript delete JavaScript debugger JavaScript getter &setter JavaScript 原型 JavaScript new操作符和构造函数 JavaScript instanceof JavaScript this JavaScript 严格模式 JavaScript 作用域 JavaScript 闭包 JavaScript 变量提升 JavaScript 对象包装器
常用库
jQuery Lodash moment.js swiper
进阶指南
ECMAScript6 Node.js Babel CSS 预处理器 代码规范 TypeScript Web Components 小程序 Vue / React / Angular JavaScript 关键字
常见疑点与误区
分号问题 对象属性访问问题 this 使用问题 浮点数精度问题 独一无二的 NaN 避免全局污染 控制台观察对象问题 根据环境选择语言特性
扩展
相关资源