对象与继承(一) 单一对象

Posted by Damon on 2016-06-03

Objects and Inheritance

概括的讲所有的js对象都是从字符串到值的映射,一个对象中的某一项(键,值对)称作对象的属性。属性的key始终是一个字符串而值可以是任何js值,包括函数。方法是指值为函数的属性。

属性的种类

三种属性:

  1. 属性(Properties,或称为数据属性) 普通属性,在一个对象里面的一个键值对包括方法,最常用属性。
  2. 访问器(Accessors,或者叫访问属性) 类似于读写属性的特殊方法。属性值存在普通属性中,而访问属性可以计算他们的值。你可以把他们看作是虚拟的属性,比如(getter 和 setter).
  3. 内置属性(Internal property) 只存在于ECMAscript规范当中,他们不能被js直接访问,但可以间接的方式访问到。规范里规定将这种属性放在[[]]当中,比如[[Property]]吃有一个对象的原型,它可以通过 Object.getPrototypeOf() 访问到。

对象字面量

JavaScript对象字面量允许你直接的创建简单的对象(Object直接实例)。
例如:

1
2
3
4
5
6
var jane = {
name: 'Jane',
describe: function () {
return 'Person named '+this.name; // (1)
}, // (2)
};
  1. 使用this来指代当前对象.
  2. ECMAScript 5 允许最后一个属性跟一个逗号,但不是所有的旧版本浏览器都支持这个做法.这个逗号还是挺管用的, 你可以重排属性而不用担心谁在最后.

你可能有这样的印象,对象仅仅是字符串到值的映射。事实上远不止这些,有一些真正意义上的通用对象。
比如你可以做对象的继承,还可以保护对象不被修改。直接创建对象的功能是标准的js特性之一:你可以在没有类的前提下创建一个正确的对象,然后再对他进行抽象。
例如:构造函数(constructors)大体和其他语言的类相似,我们在后面会降到。

点运算符 (.): 通过固定值来访问属性

点运算符提供了一种简洁的语法来访问属性,属性的名称必须是合法标识符. 你可以用中括号来读写任意名称的属性.

1
2
3
4
5
6
7
var jane = {
name: 'Jane',

describe: function () {
return 'Person named '+this.name;
}
};

获取属性

点操作符获取属性 (读值).例如:

1
2
3
4
> jane.name  // get property `name`
'Jane'
> jane.describe // get property `describe`
[Function]

如果属性不存在则返回 undefined:

1
2
> jane.unknownProperty
undefined

调用方法

也可以调用方法:

1
2
> jane.describe()  // call method `describe`
'Person named Jane'

设置属性

可以用赋值符=来给.指向的属性赋值:

1
2
3
> jane.name = 'John';  // set property `name`
> jane.describe()
'Person named John'

如果设置的属性不存在在赋值的时候就自动创建一个属性.如果存在就修改该属性。

删除属性

delete操作符可以完全的从对象里面删除一个属性(键值对):

1
2
3
4
5
> var obj = { hello: 'world' };
> delete obj.hello
true
> obj.hello
undefined

如果你仅仅给一个属性设置为undefined,这个属性会仍然存在,而且这个对象包含这个键:

1
2
3
4
5
> var obj = { foo: 'a', bar: 'b' };

> obj.foo = undefined;
> Object.keys(obj)
[ 'foo', 'bar' ]

但是如果你将属性删除那么他的键就不存在了

1
2
3
4
> delete obj.foo
true
> Object.keys(obj)
[ 'bar' ]

delete只影响一个对象的直接属性(非继承的,自有属性)。并不会删除对象的原型。

Tip
慎用delete操作符,大多数现代化js引擎都会针对构造函数的创建实例进行优化,前提是这些实例不会发生形态改变(就是说没有删除或者添加属性的),但是删除属性会破坏这种优化。

delete的返回值

如果属性是一个自有属性且不能删除,那么delete会反回false,其他情况返回true。
例子:
作为准备,我们用Object.defineProperty创建一个不被删除自有属性

1
2
3
4
5
6
7
8
9
var obj = {};
Object.defineProperty(obj, 'canBeDeleted', {
value: 123,
configurable: true
});
Object.defineProperty(obj, 'cannotBeDeleted', {
value: 456,
configurable: false
});

delete cannotBeDeleted 时候返回 false :

1
2
> delete obj.cannotBeDeleted
false

其他情况下delete 返回 true:

1
2
3
4
> delete obj.doesNotExist
true
> delete obj.canBeDeleted
true

即使delete没有起作用也会返回true (继承的属性是不会被移除的):

1
2
3
4
> delete obj.toString
true
> obj.toString // still there
[Function: toString]

特殊属性键

虽然你不能使用保留字作为变量名,但是你可以把他们作为属性键。

1
2
3
4
5
> var obj = { var: 'a', function: 'b' };
> obj.var
'a'
> obj.function
'b'

数字也可以作为属性键,但会被解析成字符串。点操作符不能访问他们(只能访问键为标识符的属性)所以要用[]来访问:

1
2
3
4
5
> var obj = { 0.7: 'abc' };
> Object.keys(obj)
[ '0.7' ]
> obj['0.7']
'abc'

对象字面量,同样允许你使用其他任意字符串来做为键,但是你必须用上单引号,且需要用[]来访问。

1
2
3
4
5
> var obj = { 'not an identifier': 123 };
> Object.keys(obj)
[ 'not an identifier' ]
> obj['not an identifier']
123

中括号 ([]): 通过计算出来的键访问属性

中括号可以通过表达式引用一个属性。

用中括号获取属性:

1
2
3
4
5
6
7
8
> var obj = { someProperty: 'abc' };

> obj['some' + 'Property']
'abc'

> var propKey = 'someProperty';
> obj[propKey]
'abc'

非标识符:

1
2
3
> var obj = { 'not an identifier': 123 };
> obj['not an identifier']
123

表达式,转换成字符串:

1
2
3
> var obj = { '6': 'bar' };
> obj[3+3] // key: the string '6'
'bar'

用中括号调用方法

1
2
3
> var obj = { myMethod: function () { return true } };
> obj['myMethod']()
true

用中括号设置属性

1
2
3
4
> var obj = {};
> obj['anotherProperty'] = 'def';
> obj.anotherProperty
'def'

用中括号删除属性

1
2
3
4
5
6
7
> var obj = { 'not an identifier': 1, prop: 2 };
> Object.keys(obj)
[ 'not an identifier', 'prop' ]
> delete obj['not an identifier']
true
> Object.keys(obj)
[ 'prop' ]