目录
JavaScript对象的特征
JavaScript的基本数据类型,一种复合值,可看做是属性的无序集合。
- 每个属性都是一个名/值对。
- 属性名是字符串,因此可以把对象看成是从字符串到值的映射。
对象除了可以保持自有的属性,还可以从一个称为原型的对象继承属性。
- 原型式继承( prototypal inheritance )是JavaScript的核心特征。
对象是动态的,可以增加或删除属性。
除了字符串、数值、true 、 false 、null和 undefined ,其他值都是对象。
对象最常见的用法是对其属性进行创建、设置、查找、删除、检测和枚举等操作。
属性值是任意JavaScript 值,或者是一个getter 或setter函数。
每个属性还有一些与之相关的值,称为“属性特征( property abttribute ) ”。
- 可写( writable attribute ) ,表明是否可以设置属性的值。
- 可枚举( enumerable attribute ),表明是否可以通过for/in结构返回该属性。
- 可配置( configurable attribute ),表明是否可以删除或修改该属性。
每个对象还拥有三个相关的对象特性。
- 对象的原型( prototype ) ,指向另一个对象,该对象的属性会被当前对象继承。
- 对象的类( class ) ,一个标识对象类型的字符串。
- 对象的扩展标记( extensible flag ) ,指明了是否可以向该对象添加新属性。
创建对象
对象字面量
let empty={}; //无属性对象
let point={x:0,y:0}; //有属性对象
let book={
//属性名有空格,必须以字符串表示
"main title":"JavaScript",
//属性名有特殊字符,必须用字符串表示
"sub-title":"The Definitive Gruide",
//属性名是保留字,但尽量避免
for:"all audiences",
//属性值可以是另一个对象
author:{
firstname:"David",
lastname:"Flanagan",
},
};
对象字面量是一个表达式,每次运算都会创建一个新的对象,其中的属性值也会重新计算。
通过new创建对象
通过new 调用构造函数( constructor )来创建并初始化一个新对象。
JavaScript语言核心中的原始类型都包含内置构造函数,如Object() 、Array() 、Date()等。
原型
每一个JavaScript对象( null除外)都和另一个对象相关联。
- “另一个对象”就是原型对象。
- 每一个对象都从原型继承属性。
所有通过对象字面量创建的对象都具有同一个原型对象。
通过Object.prototype获得原型对象的引用。
通过new和构造函数创建的对象的原型就是构造函数的prototype属性引用的对象。
如: new Array()对象的原型就是Array.prototype。
极少对象没有原型。
如:0bject.prototype ,它不继承任何属性。
let obj=new Object();
obj.__proto__==Object.prototype; //true
Object.prototype.__proto__; //null
所有内置构造函数都具有一个继承自Object.prototype的原型
如: Array.prototype的属性继承自Object.prototype 。
通过层级的原型继承形成的链接,称为“原型链”( prototype chain ) 。
ps.另一个链是作用域链
let a={};
a.x=1;
let b=Object.create(a);
b.y=2;
let c=Object.create(b);
c.z=3;
console.log(c.toString()); //"[object Object]"
console.log(c.x+c.y+c.z); //6
console.log(c.x+c.y+c.z+c.d); //NaN
原型属性不能被继承对象属性修改。
属性相关
属性访问错误
查询一个不存在的属性并不会报错,如果在对象obj自身的属性或继承的属性中均未找到属性x ,属性访问表达式obj.x返回undefined 。
但是,如果对象不存在,那么试图查询这个不存在的对象的属性就会报错。
null和undefined值都没有属性,因此查询这些值的属性会报错。
let one={};
// let one={two:{three:3}};
console.log(one.two); //undefined
console.log(one.two.three); //报错,
let one={}
if(one){
if(one.two){
if(one.two.three){
console.log(one.two.three)}}}; //3
let one={};
console.log(one && one.two && one.two.three); //undefined
console.log(one.two && one && one.two.three); //undefined
console.log(one ?. two ?. three); //undefined 代表意义同上
// ?. Null传导运算符
eg.
true&&100 //100
false&&100 //false
undefined&&100 //undefined
100&&undefined //undefined
//表达式的值由不存在的值决定
删除属性
delete 运算符可以删除对象的属性。
let o={x:1}
delete o.x
//true
delete o.toString
//true
o
//{}
o.toString
//ƒ toString() { [native code] }
delete运算符只能删除自有属性,不能删除继承属性。
检测属性
判断某个属性是否存在于某个对象中,可以通过in运算符、hasOwnPreperty()和propertylsEnumerable()方法,甚至也可以仅通过属性查询。
枚举属性
for/in循环可以在循环体中遍历对象中所有可枚举的属性(包括自有属性和继承的属性),把属性名称赋值给循环变量。
对象继承的内置方法不可枚举的,但在代码中给对象添加的属性都是可枚举的。
let o=Object.create({m:10,n:20})
o.x=1
o.y=2
o.z=3
for(let p in o){
console.log(p,o[p])
}
x 1
y 2
z 3
m 10
n 20
Tips: for/in 遍历对象属性 for/of 遍历数组
Object.keys() ,它返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。
Object.keys(o)
//(3) ["x", "y", "z"]
Object.getOwnPropertyNames() ,它和Ojbect.keys()类似,只是它返回对象的所有自有属性的名称,而不仅仅是可枚举的属性。
Object.getOwnPropertyNames(o)
//(3) ["x", "y", "z"]
属性getter和setter
由getter和setter定义的属性称做“存取器属性”(accessor property),它不同于“数据属性”(data property),数据属性只有一个简单的值。
let circle={
r:10,
get round(){
return 2*this.r*Math.PI;
},
set round(v){
this.r=v/2/Math.PI;
},
get area(){
return Math.PI*this.r**2;
},
};
console.log(circle.round,circle.area);
//62.83185307179586 314.1592653589793
circle.round=60;
console.log(circle.r,circle.area);
//9.549296585513721 286.47889756541167
let circle1=Object.create(circle);
circle1.r=20;
console.log(circle1.round);
//125.66370614359172
circle1.round=500;
console.log(circle1.r,circle1.area);
//79.57747154594767 19894.367886486918
存取器属性实质是函数,不会重新产生,而是调用。
存取器属性和数据属性一样,同样是可以被继承的。
属性的特性
除了包含名字和值之外,属性还包含一些标识它们可写、可枚举和可配置的特性。
可以通过这些API给原型对象添加方法,并将它们设置成不可枚举的,这让它们看起来更像内置方法。
可以通过这些API给对象定义不能修改或删除的属性,借此“锁定”这个对象。
数据属性的4个特性
值(value)、可写性(writable)、可枚举性(enumerable)和可配置性(configurable) 。
存取器属性不具有值(value)特性和可写性。
它们的可写性是由setter方法存在与否决定的。
因此存取器属性的4个特性是读取(get)、写入(set)﹑可枚举性和可配置性。
通过一个名为“属性描述符”(property descriptor)的对象实现属性特性的查询和设置操作。
Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符。
console.log(Object.getOwnPropertyDescriptor(circle,"r"));
{value:9.549296585513721, writable:true, enumerable:true, configurable:true}
console.log(Object.getOwnPropertyDescriptor(circle1,"round"));
undefined
对于继承属性和不存在的属性,会返回undefined。
- 要想设置属性的特性,或者想让新建属性具有某种特性,则需要调用object.definePeoperty(
),传入要修改的对象、要创建或修改的属性的名称以及属性描述符对象。
let o={}
Object.defineProperty(o,"x",{
value:10,
writable:true,
enumerable:false,
configurable:false,
});
console.log(o.x,Object.keys(o),Object.getOwnPropertyNames(o));
//10 [] [ 'x' ]
Object.defineProperty(o,"x",{enumerable:true});
console.log(Object.keys(o))
//[ 'x' ]
- 如果要同时修改或创建多个属性,使用Object.defineProperties( ) 。
对象特性
原型属性
将对象作为参数传入Object.getPrototypeOf( )可以查询它的原型。
Tips: 也可以用 对象名.constructor.prototype 查询
要想检测一个对象是否是另一个对象的原型(或处于原型链中),使用isPrototypeOf( )方法。
let o={x:1};
let p=Object.create(o);
p.y=2;
Object.getPrototypeOf(p);
//{x: 1}
o.isPrototypeOf(p);
//true
序列化对象
对象序列化(serialization)是指将对象的状态转换为字符串,也可将字符串还原为对象,则称为反序列化。
使用内置函数 JSON.stringify( )和 JSON.parse( )用来序列化和反序列化JavaScript对象。
JSON的全称是"JavaScript 0bject Notation"——JavaScript对象表示法
JSON . stringify( )只能序列化对象可枚举的自有属性。
Object构造函数的方法