对象

对象 属于 JavaScript

18 个练习

关于 对象

说明

除了像number和string这样的原始数据类型之外,JavaScript 中还有一种重要的数据类型,叫做object。 对象是键值对的集合。 因此,它们可以充当其他语言中常说的映射或字典。

在其他语言里,映射中的所有值通常必须是同一种数据类型。 而在 JavaScript 中,只有键的类型受到限制:它必须是字符串。 同一个对象里的值可以有不同的类型。 它们可以是数字这样的原始类型,也可以是数组、其他对象,甚至函数。 这让对象非常灵活,因此它也是 JavaScript 中面向对象编程(OOP)的核心概念。

接下来,我们会把重点放在作为集合或映射的对象上。对象的其他用法会在其他概念中介绍,比如类。

创建对象

使用大括号可以创建对象字面量。 你也可以直接在里面写一些条目(键值对)。 写法是先写键,然后是一个冒号和值。

const emptyObject = {};

const obj = {
  favoriteNumber: 42,
  greeting: 'Hello World',
  useGreeting: true,
  address: {
    street: 'Trincomalee Highway',
    city: 'Batticaloa',
  },
  fruits: ['melon', 'papaya'],
  addNumbers: function (a, b) {
    return a + b;
  },
};

在 JavaScript 中,最后一项后面的尾随逗号是可选的。 你可以在这里了解使用它的好处。

你可能会奇怪,既然键应该是字符串,为什么没有用引号括起来。 这是一种简写形式。 如果键符合 JavaScript 标识符的命名规则,就可以省略引号。 如果键名里含有特殊字符,就需要使用常规的字符串写法。

const obj = {
  '1keyStartsWithNumber': '...',
  'key/with/slashes': '...',
  'key-with-dashes': '...',
  'key with spaces': '...',
  '#&()[]{}èä樹keyWithSpecialChars': '...',
};

声明对象时,你常常想把已有的变量加进去。 这通常会写成name: name这样的键值对。 JavaScript 有一种简写形式,允许只写name。 在对象里定义函数也有简写形式。 这时可以省略冒号和function关键字。

const x = 1;
const y = 2;

const obj = {
  x: x,
  y: y,
  calcSum: function (a, b) {
    return a + b;
  },
};

// Can be shortened to ...
const obj = {
  x,
  y,
  calcSum(a, b) {
    return a + b;
  },
};

如果想创建对象字面量,而键名保存在变量里或由表达式得出,就需要把这个变量或表达式用方括号括起来。

const key = 'greeting';

const obj = {
  [key]: 'hello world',
};
console.log(obj);
// => { greeting: 'hello world' }

读取值

为给定的键读取值有两种方式:点表示法和方括号表示法。

const obj = { greeting: 'hello world' };

obj.greeting;
// => hello world

obj['greeting'];
// => hello world

// Bracket notation also works with variables.
const key = 'greeting';
obj[key];
// => hello world

把点表示法当作简写,限制和省略引号一样。 只有当键符合标识符的命名规则时才能这样写。

如果尝试读取对象里不存在的键,JavaScript 会返回undefined。 更多细节请见 Null 与 Undefined。

如果想从嵌套对象里读取值,可以逐级串联键。

const obj = {
  address: {
    street: 'Trincomalee Highway',
    city: 'Batticaloa',
  },
};

obj.address.city;
// => 'Batticaloa'

obj['address']['city'];
// => 'Batticaloa'

// Notations can also be mixed.
obj.address['city'];
// => 'Batticaloa'

添加或修改值

可以使用赋值运算符=来添加或修改值。 同样,点表示法和方括号表示法都可以用。

const obj = { greeting: 'hello world' };

obj.greeting = 'Hi there!';
obj['greeting'] = 'Welcome.';

obj.newKey1 = 'new value 1';
obj['new key 2'] = 'new value 2';

const key = 'new key 3';
obj[key] = 'new value 3';

删除条目

可以使用delete关键字从对象里删除一个键值对。

const obj = {
  key1: 'value1',
  key2: 'value2',
};

delete obj.key1;
delete obj['key2'];

注意,虽然读取不存在的键会返回undefined,但把某个键设为undefined并不会删除这个条目。 这时应该始终使用delete。

检查键是否存在

可以用hasOwnProperty方法检查对象里是否存在某个键。

const obj = { greeting: 'hello world' };

obj.hasOwnProperty('greeting');
// => true

obj.hasOwnProperty('age');
// => false

对于继承来的键,hasOwnProperty会返回false。这通常正是你想要的行为。 如果想让存在性检查也包括继承来的键,可以改用 in运算符。

遍历对象

有一种特殊的for...in循环,可以迭代对象的所有键。

const obj = {
  name: 'Ali',
  age: 65,
};

for (let key in obj) {
  console.log(key, obj[key]);
}
// name Ali
// age 65

看起来for...in似乎总是按键出现或被添加到对象里的顺序(插入顺序)访问它们。 不过,你不应该依赖这一点,因为在某些特殊情况下,顺序会和插入顺序不同。 写代码时始终假设顺序是任意的。 如果需要可靠的顺序,请使用Map或嵌套的[数组][concept-arrays],而不是对象。

如果对象有继承来的键,for…in循环就会有一个坑。 for…in循环也会访问这些键。 通常你希望避免这种情况,所以需要像下面这样跳过它们。

for (let key in obj) {
  if (!obj.hasOwnProperty(key)) {
    continue;
  }
  // ...
}

JavaScript 还有一种for...of循环,例如用来迭代数组。 需要注意的是,for...in和for...of不能互换使用,详情请见 MDN 文档。

键、值和条目

内置对象Object提供了辅助方法,能把给定对象的所有键、值或条目以数组的形式取出。

const obj = {
  name: 'Ali',
  age: 65,
};

Object.keys(obj);
// => [ 'name', 'age' ]

Object.values(obj);
// => [ 'Ali', 65 ]

Object.entries(obj);
// => [ [ 'name', 'Ali' ], [ 'age', 65 ] ]

真正空的对象

你可能已经注意到,JavaScript 里的空对象并不是完全空的。 比如,它包含hasOwnProperty方法,以及toString等其他方法。 通常这不会带来任何问题,但如果你确实需要创建一个真正空的对象,可以使用通过Object.create(null)创建的空对象。

通过 GitHub 编辑 该链接会在新窗口或标签页中打开

学习 对象