对象

原文链接

1 概述

1.1 结构

对象是一组无序键值对,是 JavaScript 最重要的数据类型。

var obj = {
  foo: 'Hello',
  bar: 'World'
};

所有键都是字符串( ES6 引入的 Symbol 值也可以作为键),非字符串键会自动向字符串转换。特别注意数值键的转换方式。键又称属性。属性之间用逗号分隔,末端逗号可加可不加。

var obj = {
  1: 'a',
  3.2: 'b',
  1e2: true,
  1e-2: true,
  .234: true,
  0xFF: true
};

obj
// Object {
//   1: "a",
//   3.2: "b",
//   100: true,
//   0.01: true,
//   0.234: true,
//   255: true
// }

obj['100'] // true

值可以是任何数据类型。函数类型的值称为方法。如果属性的值还是一个对象,就形成了链式引用。

var obj = {
  p: function (x) {
    return 2 * x;
  }
};

obj.p(1) // 2

1.2 引用

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

var o1 = {};
var o2 = o1;

o1.a = 1;
o2.a // 1

o2.b = 2;
o1.b // 2

此时如果取消某一个变量对于原对象的引用,不会影响到另一个变量。但是这种引用只局限于对象,指向原始类型的变量复制的是值。

var o1 = {};
var o2 = o1;
o1 = 1;
o2 // {}

var x = 1;
var y = x;
x = 2;
y // 1

1.3 是对象还是区块

对象也采用大括号表示,如果行首是一个大括号,它到底是对象还是区块?

{ foo: 123 }
  • 一个包含 foo 属性的对象
  • 一个包含 foo 标签的区块

JavaScript 引擎的做法是一律解释为区块。如果想要声明对象,请在大括号外加上圆括号,因为圆括号的里只能是表达式,确保了大括号只能解释为对象。在对字符串求值的 eval 语句中反映得最明显。

({ foo: 123 }) // 正确
({ console.log(123) }) // 报错

eval('{foo: 123}') // 123
eval('({foo: 123})') // {foo: 123}

2 属性

2.1 赋值

属性支持动态创建,不一定要在对象声明时就指定。

var obj = { p: 1 };
// 等价于
var obj = {};
obj.p = 1;

2.2 查看

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

var obj = {
  key1: 1,
  key2: 2
};

Object.keys(obj); // ['key1', 'key2']

in 用于检查对象是否包含某个属性。它不能识别哪些是自身的,哪些是继承的,这得使用 hasOwnProperty() 方法来判断。

var obj = {};
if ('toString' in obj) {
  console.log(obj.hasOwnProperty('toString')) // false
}

for...in 用来遍历一个对象的全部可遍历属性,不可遍历属性会被跳过。举例来说,对象都继承了 toString 属性,但是 for...in 不会遍历到它。

2.3 读取

var foo = 'bar';
var obj = {
  foo: 1,
  bar: 2
};

obj.foo  // 1
obj.['foo']  // 1
obj[foo]  // 2

若使用方括号读取,键必须有引号,否则被当作变量处理。方括号内支持表达式。数值键可以不加引号,会自动转成字符串。数值键不能使用点运算符(会被当成小数点),只能使用方括号。

var obj = {
  123: 'hello world'
};

obj.123 // 报错
obj[123] // "hello world"

2.4 删除

var obj = { p: 1 };
Object.keys(obj) // ["p"]

delete obj.p // true
obj.p // undefined
Object.keys(obj) // []

注意,删除一个不存在的属性不会报错且返回 true 。只有一种情况会返回 false ,那就是该属性存在且禁止删除。

var obj = Object.defineProperty({}, 'p', {
  value: 123,
  configurable: false
});

obj.p // 123
delete obj.p // false

3 with

with 语句的作用是方便书写。

// 例一
var obj = {
  p1: 1,
  p2: 2,
};
with (obj) {
  p1 = 4;
  p2 = 5;
}
// 等同于
obj.p1 = 4;
obj.p2 = 5;

// 例二
with (document.links[0]) {
  console.log(href);
  console.log(title);
  console.log(style);
}
// 等同于
console.log(document.links[0].href);
console.log(document.links[0].title);
console.log(document.links[0].style);

注意,若 with 区块内部有赋值操作,必须是当前对象已经存在的属性,否则会创造一个当前作用域的全局变量,因为 with 区块没有改变作用域。

var obj = {};
with (obj) {
  p1 = 4;
  p2 = 5;
}

obj.p1 // undefined
p1 // 4

建议不使用 with 语句,用一个临时变量代替。

with (obj1.obj2.obj3) {
  console.log(p1 + p2);
}
// 写成
var temp = obj1.obj2.obj3;
console.log(temp.p1 + temp.p2);