- 时间:2021-03-17 13:58 编辑: 来源: 阅读:
- 扫一扫,手机访问
摘要:JavaScript高级程序设计(第3版)学习笔记10 再访js对象
[b]1、对象再认识[/b]
(1)对象属性和特性
什么是属性(Property),什么是特性(Attribute),这有什么区别?我不想也不会从语义学上去区分,对于这系列文章来说,属性就是组成对象的一个部分,广义上也包括对象的方法,而特性则是指被描述主体所具有的特征,换句话说,属性是我们可以通过编码来访问的具体存在,而特性则主要是为了便于理解概念的抽象存在,当然,特性也可以通过相应的属性来具体外化。这一小节所讲的对象属性的特性就是对对象属性特征的一个描述,主要来自于ECMA-262规范的第5版,该规范使用两个中括号的形式来描述不能直接访问的内部特性。
A、属性类型(先给属性分下类):
[list]
[*]数据属性:直接访问属性值的属性
[/*][*]访问器属性:通过getter/setter方法来访问属性值的属性
[/*][*]内部属性:不能通过代码直接访问的属性,只是为了规范说明目的而存在,在规范中也使用两个中括号的形式来描述[/*][/list]
B、对象内部属性
内部属性不能通过代码直接访问,它主要是为了描述规范,也是给ECMAScript实现者参考的,而对于开发者来说,了解这些可以便于理解一些内部机制。比如在给一个属性赋值时,在实现中会调用[[Put]]内部方法,而读取一个属性值时,则调用[[Get]]方法。
| 所有对象公共的内部属性 |
个别对象特有的内部属性 |
| 名称 |
规范 |
名称 |
规范 |
对象 |
| [[Prototype]] |
Object/Null |
[[PrimitiveValue]] |
primitive |
Boolean|Date|Number|String |
| [[Class]] |
String |
[[Construct]] |
SpecOp(a List of any) → Object |
new |
| [[Extensible]] |
Boolean |
[[Call]] |
SpecOp(any, a List of any) → any|Reference |
call |
| [[Get]] |
SpecOp (propName) →any |
[[HasInstance]] |
SpecOp(any) → Boolean |
Function |
| [[GetOwnProperty]] |
SpecOp (propName) →Undefined|Property Descriptor |
[[Scope]] |
Lexical Environment |
Function |
| [[GetProperty]] |
SpecOp (propName) →Undefined|Property Descriptor |
[[FormalParameters]] |
List of Strings |
Function |
| [[Put]] |
SpecOp (propName, any, Boolean) |
[ [url=javascript:void(0);][/url]
// 创建一个包含一个默认属性job的对象(job属性可以修改、删除、在for-in中枚举)
var person = {job:'it'};
// 添加一个不能被修改、删除的name属性
Object.defineProperty(person, 'name', {
value:'linjisong',//这里的配置属性和上面特性列表中的配置属性一致
enumerable:true
});
// 定义多个属性(数据属性year和访问器属性age)
Object.defineProperties(person, {
year:{
value : 2012,
configurable:true,
writable:true
},
age:{
get : function(){
return this.year-1983;
}
}
});
var job = Object.getOwnPropertyDescriptor(person, 'job');
console.info(job.configurable);//true,直接添加属性时默认为true
var name = Object.getOwnPropertyDescriptor(person, 'name');
console.info(name.configurable);//false,使用属性定义方法添加属性时默认为false
console.info(person.name);//linjisong
person.name = 'oulinhai';//由于不能修改,所以值不会改变,在严格模式下会抛出异常
console.info(person.name);//linjisong
person.year = 2015;
console.info(person.year);//2015
console.info(person.age);//32,在修改year的同时,也修改了age属性[url=javascript:void(0);][/url] |
| defineProperties() |
定义一组属性 |
(1)目标对象
(2)多个属性描述符组成的一个对象
|
| getOwnPropertyDescriptor() |
获取属性的特性 |
(1)目标对象
(2)属性的名字
(3)返回一个包括了属性特性的对象
|
|
注:这些方法设置或获取的属性特殊和属性的类型有关,比如数据属性只能设置[[Confirurable]]、[[Enumerable]]、[[Writable]]、[[Value]]。
(2)防篡改对象
所谓防篡改对象,就是给对象一定级别的保护以防止在这个级别上对对象的变更,在ES5规范中,定义了依次升高的三种保护级别:
| 保护级别 |
描述 |
操作方法 |
判断方法 |
说明 |
| 不可扩展 |
不能给对象添加新属性和方法,但可以修改已有属性和方法 |
preventExtensions() |
isExtensible():不能扩展时返回false |
|
| 密封 |
不可扩展,并且已有成员的[[Configurable]]设置为false,不能删除属性,但可以修改属性值 |
seal() |
isSeal():被密封时返回true |
isSeal()为true时一定有isExtensible()为false |
| 冻结 |
密封,其[[Writable]]设置为false,但如果定义了[[Set]],访问器属性仍然可写 |
freeze() |
isFrozen():被冻结时返回true |
isFrozen()为true时一定有isSeal()为true,isExtensible()为false |
注:一旦定义成了防篡改对象,就不能撤销。
(3)对象的其它方法
| 名称 |
描述 |
| create(prototype[,descriptors]) |
创建一个具有指定原型且可选择性地包含指定属性的对象 |
| getOwnPropertyNames(object) |
返回对象的属性(方法)的名称 |
| getPrototypeOf(object) |
返回对象的原型 |
| keys(object) |
返回对象的可枚举属性(方法)的名称 |
这里的create(prototype[,descriptors])是一个非常有意思的方法,规范中这样描述它的行为:
[code]
①如果prototype不是Null或Object,抛出TypeError异常
②var obj = new Object()
③设置obj的内部属性[[Prototype]]为prototype
④如果descriptors存在且不为undefined,使用Object.defineProperties(obj,descriptors)来添加属性
⑤返回obj