JavaScript对象
1、创建对象
可以通过对象直接量,关键字new,object.create()三种方法来创建对象
对象直接量
var empty = {}; //没有任何属性的对象
var point = {x:0,y:0}; //两个属性
var point2 = {x:point.x,y:point.y} //更复杂的值
var book = {
'main title':'javascript', //属性名字里面有空格,必须用字符串表示
sub-title':'The Definitive Guide', //属性名字里面有连字符,必须用字符串表示
'for':'all audiences', //'for'是保留字,必须用引号
author:{ //这个属性的值是一个对象
firstname:'David', //注意,这里的属性名都没有引号
surname:'Flanagan'
}
}
通过new创建对象
new运算符创建并初始化一个对象,关键字后面跟一个函数调用,这个函数称作构造函数,构造函数用于初始化一个新创建的对象
var o = new Object(); //创建一个空对象,和{}一样
var a = new Array(); //创建一个空数组,和[]一样
var d = new Date(); //创建一个表示当前时间的Date对象
var r = new RegExp('js'); //创建一个可以进行模式匹配的RegExp对象
原型
每个对象都会从原型对象继承属性
通过对象直接量创建的对象,会继承自原型Object.prototype
通过new Object(),继承自原型Object.prototype
通过new Date(),继承原型Date.prototype.
通过new Array(),继承原型Array.prototype.
通过new RegExp,继承原型RegExp.prototype
Date.prototype,Array.prototype,RegExp.prototype继承自原型Object.prototype
Object.prototype是唯一一个没有原型的对象
object.create()
object.create()创建了一个新对象,第一个参数是这个对象的原型,提供第二个可选参数,可以对对象的属性进行进一步的描述
object.create() 是一个静态函数,而不是提供给某个对象调用的方法。使用方法简单,只需传入所需的原型对象即可
var o1 = Object.create({x:1,y:1}); //o1继承了属性x和y
var o2 = Object.create(null); //不继承任何属性和方法
var o3 = Object.create(Object.prototype); //o3和{}和new Object()一样,属于一个普通的空对象
2、属性的查询和设置
通过 . 和 []用来获取和设置属性,点运算符是静态的,写死的,不能改变。[]是动态的,在运行是可进行修改。
var book = {
'main title':'javascript',
'sub-title':'The Definitive Guide',
'for':'all audiences',
author:{
firstname:'David',
surname:'Flanagan'
}
}
var author = book.author; //得到book的'author'属性
var name = author.surname; //Flanagan
var title = book['main title']; //javascript
book.edition = 6; //给book创建了一个名为'edition'的属性
book['main title'] = 'ECMAScript'; //给'main title'属性赋值
继承
对象具体有自有属性,也有一些属性是从原型对象继承而来。
假设要查询对象o的属性x,如果o中不存在x,那么将会在o的原型对象中继续查找属性x。如果原型对象中也没有x,但这个原型对象也原型,那么继续这个原型对象的原型上继续查找,直到找到x或者查到到一个原型是null的对象为止。
只有在查找时才会体会到继续的存在,设置和赋值和继承无关
var o = {}; //o从Objec.prototype 继承对象的方法
o.x = 1; //给o定义一个属性x
var p = inherit(o); //p继承o和Objec.prototype
var p.y = 2; //给p定义一个属性y
var q = inherit(p); //q继承p、o、Object.prototype
q.z = 3; //给q定义一个属性z
var s = q.toString(); //toString继承自Object.prototype
q.x+q.y //3:x和y分别继承自o和p
var unitcircle = {r:1}; //一个用来继承的对象
var c = inherit(unitcircle); //c继承属性r
c.x = 1;c.y = 1; //c定义两个属性
c.r = 2; //c覆盖继承来的属性
unitcircle.r; //1:原型对象没有修改
3、删除属性
delete运算符可以删除对象属性,只能删除自有属性,不能删除继承属性
var book = {
'main title':'javascript',
'sub-title':'The Definitive Guide',
'for':'all audiences',
author:{
firstname:'David',
surname:'Flanagan'
}
}
delete book.author; //book不再有属性author
delete book['main title'] //book不再有属性'main title'
当delete表达式删除成功或者没有任何副作用的时候,返回true
var o = {x:1}; //o有一个属性x,并继承属性toString
delete o.x; //删除x,返回true
delete o.x; //什么都没做(x已经不存在),返回true
delete o.toString(); //什么都没做(toString是继承来的),返回true
delete 1; //无意义,返回true
4、属性检测
四种方法:in运算符,hasOwnPreperty(),propertyIsEnumberable(),属性查询
in运算符
var o = {x:1};
'x' in o; //true:x是o的属性
'y' in o; //false:y不是o的属性
'toString' in o; //true:o继承toString属性
hasOwnProperty()方法用来检测给定的名字是否是对象的自由属性。对于继承属性将返回false
var o = {x:1};
o.hasOwnProperty('x'); //true:o有一个自有属性x
o.hasOwnProperty('y'); //false:o不存在属性y
o.hasOwnProperty('toString'); //false:toSting 是继承属性
propertyIsEnumerable()是hasOwnProperty()的增强版,只有检测到是自有属性且这个属性的可枚举性为true时才返回true
var o = inherit({y:2});
o.x = 1;
o.propertyIsEnumerable('x'); //true:o有一个可枚举的只有属性x
o.propertyIsEnumerable('y'); //false:y是继承来的
o.propertyIsEnumerable('toString'); //false:不可枚举
通过'!=='进行判断
var o = {x:1};
o.x !== undefined; //true:o中有属性x
o.y !== undefined; //false:o中没有属性y
o.toString() !== undefined; //true:o继承了toString属性
5、枚举属性
for/in循环可以在循环体内遍历对象中所有可枚举的属性(包括自有和继承的属性);对象继承的内置方法不可枚举,在代码中给对象添加的属性都是可枚举的
var o = {x:1,y:2,z:3};
o.propertyIsEnumerable('toString'); //false:不可枚举
for(var p in o){
console.log(p); //输出x、y、z
}
for(var p in o){
if(!o.hasOwnProperty(p)) continue; //跳过继承的属性
}
6、对象属性 -- getter和setter
如果属性同时具有getter和setter方法,那么它是一个读/写属性;如果只有getter方法,那么它是一个只读属性;如果只有setter方法,那么它是一个只写属性。存取器属性可以继承
var o = {
data_prop:value, //普通的数据属性
get accessor_prop(){...}, //存取器属性
set accessor_prop(value){...}
}
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);}
}
console.log(p.r);
console.log(p.theta);
7、对象属性的特性
除了包含名字和值之外,属性还包含一些标识他们可写、可枚举和可配置的的特性
一个属性包含一个名字和4个特性。
数据属性特性:值(value)、可写性(writable)、可枚举行(enumerable)、可配置性(configurable)
存取器属性:取(get)、写入(set)、可枚举行(enumerable)、可配置性(configurable)
Object.getOwnPropertyDescriptor() 可以获得某个对象特定属性的“属性描述符”(4个特性),只能得到自有属性的描述符
var o = {x:1,y:2};
console.log(Object.getOwnPropertyDescriptor(o,'x')); //Object {value: 1, writable: true, enumerable: true, configurable: 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);}
}
console.log(Object.getOwnPropertyDescriptor(p,'r')); //configurable:true enumerable:true get:r() set:r(newvalue)
对于继承属性和不存在的属性,返回undefined
console.log(Object.getOwnPropertyDescriptor({},'x')) //undefined
console.log(Object.getOwnPropertyDescriptor({},'toString')) //undefined
Object.defineProperty()--设置属性的特性,或者想让新建属性具体有某种特性,只能设置自有属性,不能修改继承属性
var o = {};
Object.defineProperty(o,'x',{
value:1,
writable:true,
enumerable:false,
configurable:true
})
console.log(o.x); //1
console.log(Object.getOwnPropertyDescriptor(o, 'x')); //Object {value: 1, writable: true, enumerable: false, configurable: true}
Object.defineProperties -- 同时修改或者创建多个属性
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
}
})
8、对象的三个属性 -- 原型(prototype)、类(class)、可扩展性(extensible attribute)
isPrototypeOf() -- 检测一个对象是否是另一个对象的原型
var p = {x:1};
var o = Object.create(p);
console.log(p.isPrototypeOf(o)); //true:o继承自p
console.log(Object.prototype.isPrototypeOf(o)); //true:p继承自Object.prototype
可扩展性
对象的可扩展性用以表示是否可以给对象添加新属性。默认所有内置对象和自定义对象都是可扩展的。
Object.isExtensible() -- 判断对象是否可扩展
Object.preventExtensions() -- 将对象转换为不可扩展的,一旦将对象转换为不可扩展的,就无法将其转换回可扩展的了,只影响对象本身的可扩展性,如果给一个不可扩展的对象的原型添加属性,这个不可扩展的对象同样会继承这些新属性
Object.seal() -- 将对象设置为不可扩展,并将对象的所有自有属性都设置为不可配置的。已经封闭的对象不能解封
Object.isSealed() -- 检测对象是否已封闭(sealed)
Object.freeze() -- 将对象设置为不可扩展,并将对象的所有自有属性都设置为不可配置的和只读
Object.isFrozen() -- 检测对象是否冻结(frozen)
var o = {x:1};
console.log(Object.isExtensible(o)); //true
Object.preventExtensions(o);
console.log(Object.isExtensible(o)); //false
Object.seal(o);
console.log(Object.getOwnPropertyDescriptor(o,'x')); //{value: 1, writable: true, enumerable: true, configurable: false}
console.log(Object.isSealed(o)); //true
Object.freeze(o);
console.log(Object.getOwnPropertyDescriptor(o,'x')); //{value: 1, writable: false, enumerable: true, configurable: false}
console.log(Object.isFrozen(o)); //true
9、序列化对象
对象序列化(serialization)是指将对象的状态转换为字符串,也可将字符串还原为对象
JSON.stringify() -- 将对象的状态转换为字符串
JSON.parse() -- 将字符串还原为对象
var o = {x:1,y:{z:[false,null,'']}};
s = JSON.stringify(o);
console.log(s); //{"x":1,"y":{"z":[false,null,""]}}
console.log(typeof s) //string
p = JSON.parse(s);
console.log(p); //object {x:1,y:{z:[false,null,'']}};
console.log(typeof p) //object