6.0 对象
__proto__和prototype的关系:https://www.zhihu.com/question/34183746/answer/58068402
对象是一种复合值:它将很多值聚合在一起,可通过名字访问这些值。
对象的常见用法:创建、设置、查找、删除、检测和枚举它的属性。
属性特性:可写(是否可以设置该属性的值),可枚举(是否可通过for/in返回该属性),可配置(是否可以删除或修改该属性)。
三类js对象和两类属性的区分:
内置对象(是由ECMAScript规范定义的对象或类。例如数组、函数、日期、正则)
宿主对象(宿主环境定义的对象,比如HTMLElement)
自定义对象(运行js代码创建的对象)
自有属性(直接在对象中定义的属性)
继承属性(在对象的原型对象中定义的属性)
6.1 创建对象
创建对象的三种方式:
对象直接量:var obj={ x:1,y:2 };访问方式:obj.x或obj["x"]
new运算符创建并初始化一个新对象:var a=new Date();
object.create函数创建的对象:var c=object.create( {} )或var c=object.create(null);
6.1.3 原型
对象通过原型的继承方式形成了一种"原型链"形式,可继承原型链上的原型对象的属性和方法,也可以动态创建原型对象(prototype)的属性和方法
每个js对象(null除外)都有和另一个对象相关联。“另一个”对象就是我们熟知的原型,每个对象都从原型继承属性
Object.prototype没有原型对象
属性prototype就是原型对象,不过由于是隐型的,所有大多浏览器都给出了__proto__ 作为构造该对象的原型对象
比如:对象直接量 var a1={ x:1,y:2 }; a1.__proto__指向原型对象object.prototype
通过new构造函数 function f(){}; var a2=new f(); a2.__proto__==f.prototype;
函数f的原型对象 f.prototype,函数f的原型对象的原型对象 f.prototype.__proto__指向 Object.prototype
6.1.4 Object.create()
ECS5定义了Object.create()方法,它创建一个新对象,其中第一个参数是这个对象的原型。
比如:var o1=Object.create( { x:1,y:2 } );
6.2 属性的查询和设置
6.2.1 作为关联数组的对象
object.property
object["property"]
6.2.2 继承
javascript对象使用某个属性时会查找原型链上的所有可能存在的属性
原型继承方式 object.prototype=其他原型对象
6.2.3 属性访问错误
只读属性会报错;继承的只读属性,同名自有属性会报错;可扩展性是false会报错
6.3 删除属性
delete运算符可以删除对象的属性,只能删除自有属性,不能删除继承属性,可删除可配置属性(可修改)
6.4 检测属性
检测一个对象是否有指定属性的方式:
in运算符 : var o={ x:1 }; "x" in o ;=>true;也可以检测继承属性
只能检测自有属性:obj.hasOwnProperty(属性)
只能检测自有属性且可枚举的属性:obj.propertyIsEnumerable(属性)
获取指定对象的原型对象: Object.getPrototypeOf(普通对象);
6.5 枚举属性
for/in;Object.getOwnPropertyNames();Object.keys()
6.6 属性getter和setter
区别于数据属性,getter和setter定义了存取器属性。
var p={
x:1.0,y:1.0,
get r(){
return this.x*5+this.y*5;
},
set r(newvalue){
this.x=newvalue;
this.y=newvalue;
},
};
除了包含名字和值之外,属性还包含一些标志它们 可写、可枚举和可配置的特性。
开发库的作用:可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,折让它们看起来更像内置对象。
可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象。
数据属性:包含 值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable)
存取器属性: 包含 读取(get属性代替)、写入(set属性代替)、可枚举性(enumerable)和可配置性(configurable)
ECS5定义了 “属性描述符”的对象,这个对象代表上述4个特性
Object.getOwnpropertyDescriptor() 可以获得某个对象特定自有属性的属性描述符,比如:
object.getOwnpropertyDescriptor( {x:1},"x" ); => { value:1, writable:true, enumerable:true, configurable: true }
Object.defineProperty(要修改的对象,要创建或修改的属性的名称,属性描述符对象),Object.defineProperties(多属性的属性描述符修改),比如:
var o={};
Object.defineProperty( o,"x",{ value:1,writable:true, enumerable: false, configurable: true } );
属性是存在的,但不可枚举o.x =>1;Object.keys(o) => []
var p=Object.defineProperty({},
{ x:{ value: 1,writable:true,enumerable: true,configurable: true,y:{ value:2,writable:true,enumerable:true,configurable:true } } }
);
常见错误类型:
a.如果对象是不可扩展的,则可以编辑已有的自有属性,但不能给它添加新属性;
b.如果属性是不可配置的,则不能修改它的可配置性和可枚举性;
c.如果存取器属性是不可配置的,则不能修改其getter和setter方法,也不能将它转换为数据属性;
d.如果数据属性是不可配置的,则不能将它转换为存取器属性;
e.如果数据属性是不可配置的,则不能将它的可写性从false修改为true,但可以从true修改为false;
f.如果数据属性是不可配置且不可写的,则不能修改它的值。然而可配置但不可写属性的值是可以修改的(实际是先标记为可写,再修改值,最后转换为不可写)
6.8 对象的三个属性
每个对象都有与之相关的原型(prototype)、类(class)和可扩展性(extensible attribute)。
6.8.1 原型属性
var p={ x:1 };
var o=Object.create(p);
p.isPrototypeOf(o); =>true:o继承自p
Object.prototype.isPrototypeOf(o); =>true:p继承自Object.prototype
6.8.2 类属性
可通过 toString获得类属性
function classof(){
if( o==null ){ return "Null"; }
if( o==undefined ){ return "Undefined" };
return Object.prototype.toString.call(o).slice(8,-1);
}
classof(1) => "Number"
6.8.3 可扩展性
Object.esExtensible():判断该对象是否是可扩展的
Object.preventExtensions:将待转换的对象作为参数传进去,转换为不可扩展的(自有属性)
Object.seal() :可将对象设置为不可扩展,还可以将对象的所有自有属性都设置为不可配置的
Object.freeze():“冻结”,可设置对象为不可扩展和其自有属性设置为不可配置之外,还可以将它自有的所有数据属性设置为只读
Object.isFrozen():检测对象是否冻结
6.8.9 序列化对象
对象序列化是指将对象的状态转换为字符串,也可将字符串还原为对象。
ECS5提供了内置函数JSON.stringify()和JSON.parse()用来序列化和还原JavaScript对象。这些方法都使用JSON作为数据交换格式。