跳至正文

JavaScript入门教程笔记(6)-对象

1 概述

1.1 定义

对象(object)是JavaScript语言的核心概念,也是最重要的数据类型。简单说,对象就是一组“键值对”的集合,是一种无序的复合数据集合。

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

上面代码中,大括号就定义了一个对象,它被赋值给变量obj,所以变量obj指向这个对象。该对象包含两个键值对(又称为两个“成员”),第一个键值对是 foo:'Hello',其中foo是'键名'(成员的名称),字符串Hello是'键值'(成员的值)。

键名和键值之间用冒号分隔,两个键值对之间用逗号分隔。

1.2 键名

对象的所有键名都是字符串,加不加引号都被当作是字符串。上面的obj对象相当于这样:

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

如果键名不符合条件(例如:第一个字符是数字,或者含有空格或运算符),则必须加上引号,否则报错。

// 报错
// var obj = {
    1p: 'Hello',
};

// 不报错
// var obj = {
    '1p': 'Hello'
    'h w': 'World'
};

1.3 属性

对象的每个键名又被称为“属性”,属性之间用逗号分隔,最后一个属性结尾可以加逗号,也可以不加。

属性可以动态创建,不必在对象声明时就指定。

var obj = {};
obj.foo = 123; // 123

上面代码就是在运行时创建了 foo 属性。

1.4 对象的引用

如果不同的变量指向同一对象,那么它们都是这个对象的引用,也就是指向同一个内存地址。

var obj1 = {};
var obj2 = obj1;

obj1.a = 1;
obj2.a // 1

obj2.b = 2;
obj1.b // 2

上面代码中,obj1和obj2都指向同一个对象,因此为其中任何一个变量增加或修改属性,都会影响到其它所有变量。

1.5 表达式还是语句?

对象采用大括号表示,这产生了一个问题:如果行首是个大括号,它是表达式还是语句?

{ foo: 123 }

JavaScript引擎解释这行代码时,会发现可能有两种含义。1)这是一个表达式,表示一个包含foo属性的对象;2)这是一个语句,表示一个代码区块,里面有个标签foo,指向表达式123。
为避免这种歧义,V8引擎规定,如果行首是大括号,一律解释为对象。不过为了避免歧义,最好在大括号前加上圆括号。

({ foo: 123})

这种差异在 eval 语句(作用是对字符串求值)中反映得最明显。

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

上面代码中,如果没有圆括号,eval将其理解为一个代码块;加上圆括号后,就理解成一个对象了。

2 属性的操作

2.1 属性的读取

读取对象的属性,有两种方法。一种是使用点运算符,一种是使用方括号运算符。例如:

var obj = {
    name: 'Mark'
};
obj.name // "Mark"
obj['name'] // "Mark"

注意,如果使用方括号运算符,键名必须放在引号里面,否则会被当作变量处理。

2.2 数字键名

数字键名可以不加引号,因为会自动转成字符串。但数字键名不能使用点运算符(因为会被当作小数点),只能使用方括号运算符。例如:

var obj = {
    123: 'Hello'
};
obj.123 // 报错
obj[123] // "Hello"
obj['123'] // "Hello"

上面代码中对数字键名123使用点运算符,结果报错。

2.3 属性的赋值

点运算符和方括号运算符,不仅可以取值,也可以赋值。

var obj = {};
obj.a = 'Hello';
obj['b'] = 'World';

上面代码中,分别使用了点运算符和方括号运算符,对属性赋值。

JavaScript允许属性的“后绑定”,即可以在任意时刻新增属性,而没必要在定义对象的时候,就定义好属性。

2.4 属性的查看

查看一个对象本身的所有属性,可以使用 Object.keys 方法,它将会把对象的所有属性都放在一个数组里返回。

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

2.5 属性的删除

删除属性可以用 delete 方法,删除成功返回true。

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

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

上面代码中,delete 方法删除obj对象的a属性。删除后,再读取a属性就会返回undefined,而且Object.keys方法的返回值也不再包括该属性。

注意,删除一个不存在的属性,delete不会报错,仍然返回true。因此,不能根据delete的结果来判定某个属性是否存在。

另外,delete只能删除对象自身属性,无法删除继承的属性。

var obj = {};
delete obj.toString // true
obj.toString // ok

上面代码中,toString是obj继承得来的属性,虽然delete返回true,但toString属性并未被删除。

2.6 属性是否存在:in运算符

in 运算符用来检查对象是否包含某个属性,如果包含返回true,否则返回false。

var obj = { a: 1 };
'a' in obj; // true
'toString' in obj; // true

注意,它不能识别哪些属性是自身的,哪些是继承的。就像上面代码,toString并不是obj本身的,但 in 运算符仍然返回true。
不过,使用 hasOwnProperty 方法可以判断出属性是否为对象自身的。

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

2.7 属性的遍历:for...in 循环

for...in循环用来遍历一个对象的全部属性。

var obj = {a:1, b:2, c:3};
for (var i in obj) {
    console.log(i); 
}
// a 
// b 
// c

有两点需要注意。

  • 它遍历的是对象所有可遍历的属性,会跳过不可遍历的属性。
  • 它不仅遍历对象自身属性,还遍历继承的属性。

例如,对象都继承了 toString 属性,但是 for...in 不会遍历到这个属性。因为它默认是“不可遍历”的。关于可遍历性,请参见《标准库》章节中Object的介绍。
使用 for...in 时,如果只想遍历对象自身属性,应该结合 hasOwnProperty 方法,在循环内部判断。

var obj = {name: 'node'};
for (var key in obj) {
    if (obj.hasOwnProperty(key)) {
        console.log(key);
    }
}

注:本文适用于ES5规范,原始内容来自 JavaScript 教程,有修改。

标签:

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注