查询和设置
. []
ECMAScript 3中, 点运算符后的标识符不能是保留字。ECMAScript5(包括ECMAScript3的某些实现)中可以
[]中必须返回可以转换为字符串的值
[]的写法用了字符串索引,叫做关系数组(associative array), 散列或字典
属性不存在时自动创建
描述对象
value
writable # 可修改
enumerable # 可枚举性
for…in, Object.keys(), JSON.stringify(), Object.assign(), Reflect.enumerate()会忽略不可枚举属性
for…in等价Reflect.enumerate(), 会返回继承的属性
configurable # 可配置
遍历属性 # 先遍历属性名是数值的属性,再遍历字符串,再遍历Symbol
for … in # 自身和继承的可枚举属性
Object.keys # 自身的可枚举属性(不含Symbol)
Object.getOwnPropertyNames # 自身所有属性(不含Symbol)
Object.getOwnPropertySymbols # 自身所有Symbol属性
Reflect.ownKeys # 自身所有属性
Reflect.enumerate # 同for … in
访问错误
查询不存在的属性不报错, 返回undefined
对象不存在,会查询null和undefined的属性,会报错
建议写法: var len = book && book.subtitle && book.subtitle.length
只读的设置不报错,如 # ECMAScript 5的严格模式中会报错
设置属性失败的情况
o中属性p是只读的 # defineProperty()可以
o中属性p是继承属性,且它是只读的
o没有属性p, o没有使用p的setter方法, o可扩展性为false
删除属性
delete
删除成功,属性不存在,不是属性访问表达式时,返回true
属性可配置性为false,非严格模式下返回false, 严格模式下抛出异常
全局对象可以不用属性访问表达式, 如 delete x;
严格模式下, delete x; 会报语法错误, 必须delete this.x
只是断开联系
只删除自有属性,不能删除继承属性
继承属性可以从原型对象上删除它
a = {p:{x:1}}; b= a.p; delete a.p; 执行后p.x还是1。因为属性的引用依然存在
会内存泄漏,所以在销毁对象时,要遍历属性中的属性,依次删除
检测属性
in # 检测自有属性和继承属性
o.x !== undefined
同in,但没法区分属性的值为undefined时的属性,in可以
!可以区分null和undefined, 所以用!
hasOwnProperty() # 只检测自有属性
propertyIsEnumerable() # 自有属性且可枚举
o.propertyIsEnumerable(“x”)
枚举属性 # ECMAScript 3 的不可枚举属性不能得到
for/in
ECMAScript 5之前, 工具库给Object.prototype添加的属性必须可枚举
所以for/in会枚举出来,要用hasOwnProperty(p)来过滤
Object.keys() # ECMAScript 5中定义,返回可枚举的自有属性名数组
Object.getOwnPropertyNames() # ECMAScript 5中定义,返回自有属性名数组
getter和setter
通常用来表示同一组数据的两种方法(如笛卡尔坐标系表示法和极坐标系表示法)
ECMAScript 5中属性值可以用方法替代,就是getter和setter, 叫做存取器属性(accessor property)
是访问描述符,相对数据描述符(如writable)
普通的属性叫做数据属性(data property), 只有一个简单的值
存取器属性不具有可写性(writable attribute)
作为替代, 只有getter, 则只读。只有setter, 则只写。同时拥有, 则可读写
存取器属性是可以继承的
定义
var o = {
data_prop: 1 ,
get accessor_prop (){}, # 函数中的this表示当前对象o
set accessor_prop ( value ){}
};
var descriptor = Object. getOwnPropertyDescriptor (o, 'accessor_prop' );
'get' in descriptor // true
'set' in descriptor // true
例子
var p = {
$x: 1.0 ,
$y: 1.0 ,
get r () { return Math. sqrt ( this .x * this .x + this .y * this .y);},
set r ( newvalue ) {
var oldvalue = Math. sqrt ( this .x * this .x + this .y * this .y);
var ratio = newvalue / oldvalue;
this .x *= ratio;
this .y *= ratio;
},
get theta () { return Math. atan2 ( this .y, this .x); }
}
例子
var serialnum = { # 序列
$n: 0 , # $暗示私有属性
get next (){ return this .$n ++ ;},
set next ( n ){
if (n >= this .$n) this .$n = n;
else throw "序列号的值不能比当前值小" ;
}
}
例子2
var random = { # 返回不同数量范围的随机数
get octet (){ return Math. floor (Math. random () * 256 )},
get uint16 (){ return Math. floor (Math. random () * 65536 )},
get int16 (){ return Math. floor (Math. random () * 65536 ) - 32768 }
};
属性的特性 # ECMAScrit 3这些特性不可以配置, ECMAScript 5中提供查询和设置的api
作用
给原型对象添加方法,设置该方法为不可枚举,看起来像内置方法
给普通对象定义不能修改或删除的属性,实现”锁定”
组成
值(value), 可写性(writable)、可枚举性(enumerable)、可配置性(configurable)
存取器特性是读取(get)、写入(set)、可枚举性、可配置性
原理
ECMAScript 5定义了 属性描述符(property descriptor)对象, 代表4个特性
该对象的属性有value, writable, enumerable, configurable, 代表4个特性
存取器属性描述符用get和set代替value和writable
writable, enumerable, configurable是布尔值
get和set是函数值, value什么都可以
调用 # 新建属性的默认特性对象为false或undefined
Object.getOwnPropertyDescriptor(o, p)
获得对象o的p自有属性的 属性描述符对象
要得到继承属性的特性, 要遍历原型链
Object. defineProperty (o, "x" , {
# 新建或修改自有属性的特性, 传入对象和属性名与属性描述符对象
value: 1 ,
writable: true ,
enumerable: false ,
configurable: true
});
Object.defineProperty(o, “x”, {get: function(){ return 0; }});
修改x为存取器属性
不允许创建或修改的属性,抛出类型错误异常
规则(违反则抛异常)
对象不可扩展,可以编辑已有属性, 不能添加
属性不可配置, 不能修改可配置性和可枚举性
存取器属性不可配置, 不能修改getter, setter方法, 不能转换为数据属性
数据属性不可配置,不能转换在存取器属性
数据属性不可配置,不能可写性从false修改为true
数据属性不可配置且不可写, 不能修改值。可配置但不可写时可以修改值
Object. defineProperties ({}, {
x: {value: 1 , writable: true , enumerable: true , configurable: true },
y: {value: 1 , writable: true , enumerable: true , configurable: true },
r: {
get : function (){ return Math. sqrt ( this .x * this .x + this .y * this .y)},
enumerable: true ,
configurable: true
}
})
新建或修改多个属性及特性。第一个参数是修改对象,第二个参数是映射表
不允许创建或修改的属性,抛出类型错误异常
老式api(ECMAScript 5之前,非IE浏览器)
__lookupGetter__()
__lookupSetter__() # 返回一个属性的getter和setter
__defineGetter__()
__defineSetter__() # 定义getter和setter, 第一个参数是属性名, 第二个参数是getter或setter方法
对象三个属性
包括
原型(prototype)
类(class)
可扩展性(extensible attribute)
原型
api
Object.getPrototypeOf() # ECMAScript 5出现, 传入对象返回原型
o.constructor.prototype # 得到对的原型,对于Object.create()创建的对象常不是这样
p.isPrototypeof(o) # 检测p是否是o的原型(或牌原型链中),与instanceof运算符类似
proto # Mozilla实现的js有的属性, safari和chrome也支持
类属性
表示对象类型信息的字符串, 用toString()方法可以得到
ECMAScript 3和5 都不能设置这个属性,只能间接查询
js内置构造函数创建的对象类属性与函数名称相匹配
对象直接量、Object.create、自定义构造函数 创建的对象类属性是”Object”
对于自定义类来说,没办法通过类属性来区分对象的类
api
toString()
返回如 [object class], 提取class, 很多对象的toString方法重写了, 要间接调用Function.call()方法
function classof ( o ){
if (o === null ) return "Null" ;
if (o === undefined ) return "Undefined" ; # ECMAScript 5中不需要对null和undefined作处理
return Object . prototype .toString. call (o). slice ( 8 , - 1 );
}
可扩展性
表示是否可以给对象添加新属性。ECMAScript 5中 内置对象和自定义对象都显式可扩展
宿主对象可扩展性由js引擎定义
api
preventExtensions, seal, freeze 都返回传入的对象
Object.esExtensible() # 判断对象是否可扩展
Object.preventExtensions() # 转换对象为不可扩展, 参数为待转换对象, 对象转换不可扩展后,无法再转换回来, 给不可扩展对象原型添加属性, 对象同样会继承新属性
Object.seal() # 对象设置不可扩展, 同时对象自有属性不可配置, 已有属性标记为可写的依然可配置, seal后的对象不能解封
Object.isSealed() # 检测对象是否封闭
Object.freeze() # 除了seal外,将自有数据属性设置为只读, setter方法不受影响
Object.isFrozen() # 检测是否冻结
继承
介绍
js对象有自有属性(own property),有从原型继承来的属性
原型链(prototype chain) # 原型,原型的原型 …
属性的查询先找自有属性,再找原型链
属性修改时, 先检查属性是否允许赋值。
总在自有属性修改或创建,不修改原型链上的对象。这就是属性的覆盖(override)
继承的对象有setter方法且是accessor属性时,修改属性时会由当前对象(非原型对象)调用setter方法。
由当前对象调用,所以还是不会修改原型链
setter方法如setTitle()
inherit(p)函数
function inherit ( p ){
if (p == null ) throw TypeError ();
if (Object.create) return Object. create (p);
var t = typeof p;
if (t !== "object" && t !== "function" ) throw TypeError ();
function f (){};
f . prototype = p;
return new f ();
}
var o = {x: "don't change this value" };
library_function ( inherit (o)); # 可以防止对o的意外修改