javascript对象
动态:可新增、删除属性;
但常来模拟静态对象以及静态类型语言中的结构体(struct),有时也做字符串的集合。
除了字符串、数字、true、false、null、undefined之外,其他的javascript都是对象。尽管字符串、数字、布尔值不是对象,行为和不可变对象相似。
方法:
create、set、query、delete、test、enumerate
属性特征:
1.可写:表明是否可设置改属性的值
2.可枚举:表明是否可以通过for/in循环返回该属性
3.可配置:表明是否可以删除或修改该属性
注:ECMAScript5之前,代码给对象创建的所有属性都是可枚举的。之后有改变
对象特性:
1.对象的原型(protype)指向另一个对象,本对象的属性继承与它的原型对象
2.对象的类(class)是一个表示对象类型的字符串
3.对象的扩展标记(exensible flag)指明了是否可以向该对象添加新属性
三类对象和两类属性:
1.内置对象(native object):ECMAScript规范定义的对象或类。例如:数组、函数、日期、正则表达式
2.宿主对象(host object):javascript解释器锁嵌入的宿主环境,例如:web浏览器定义的。网页结果中的htmlelement都是宿主对象。宿主环境定义的方法都可以看做普通javascript的函数对象,那么宿主对象也可以当做内置对象
3.自定义对象(user-defind object):由运行的javascript代码创建的对象
4.自有属性(own property):直接在对象中定义的属性
5.继承属性(inherited property):在对象的原型对象中定义的属性
原型:
所有通过对象直接量创建的对象都具有同一个原型对象,并可以通过JavaScript代码Object.prototype获得对原型对象的引用。
new Object() ---> Object.prototype
new Array() ---> Array.prototype
Object.create()
静态函数,不提供给某个对象调用,只需传入所需原型对象即可
var test = Object.create(Object.prototype); //和{}、new Object()一样
//通过运行继承创建一个新对象
function inherit(p) {
if(p == null) throw TypeError(); //p是一个对象不能为Null
if(Object.create) return Object.create(p); //如果Object.create存在,则直接使用
var t = typeof p;
if(t != 'object' && t != 'function') throw TypeError(); //进一步检测
function f(){} //空构造函数
f.prototype = p; //将其原型属性设置为p
return new f(); //使用f()创建p的继承对象
}
属性访问错误
如果对象不存在,则试图查询对象的属性就会报错。 null和undefined值都没有属性
//一种冗余但很易懂的方法
var len = undefined;
if(book) {
if(book.subtitle) len=book.subtitle.length;
}
//简练语法
var len = book && book.subtitle && book.subtitle.length;
删除属性
delete运算符可以删除对象的属性。它的操作数应当是一个属性访问表达式。 但是,delete只是断开属性和宿主对象的联系,而不会操作属性中的属性
delete运算符只能删除自有属性,不能删除继承属性(要删除继承属性,必须从定义这个属性的原型对象删除它,而且会影响到所有继承自这个原型的对象)
检测属性
判断某个属性是否存在于某个对象中,可以通过in运算符、hasOwnPreperty()和propertyIsEnumerable()方法等。
对象的hasOwnProperty()方法:检测给定的名字是否是对象的自有属性,对于继承属性返回false
propertyIsEnumerable():只有检测到是自有属性且这个属性的可枚举性为true是才返回true
in运算符
!==:判断一个属性是否是undefined
var o = {x:0}
o.x !== undefined; //true
o.y !== undefined; //false
o.toString !== undefined; //true
有一种场景只能使用in运算符,而不能使用上述属性访问的方式。 in可以区分不存在的属性和存在但值为undefined的属性
var o = {x:undefined};
o.x !== undefined; //false:属性存在,值为undefined 此时会有问题
o.y !== undefined;
'x' in o; //true:属性存在
'y' in o; //false
delete o.x; //删除x
‘x’ in o; //false
//把p中可枚举的属性赋值到o中,并返回o。 如果有同名属性,则覆盖
function extend(o,p) {
for(prop in p) {
o[prop] = p[prop];
}
return o;
}
//将p中可枚举的属性复制到o中,并返回o。 如果o和p中有同名属性,o中不受影响
function merge(o,p) {
for(prop in p) {
in(o.hasOwnProperty[prop]) continue;
o[prop] = p[prop];
}
return o;
}
//如果o中的属性再p中没有同名属性,则从o中删除这个属性
function restrict(o,p) {
for(prop in o) {
if(! (prop in p)) delete o[prop];
}
return o;
}
//如果o中的属性在p中存在同名属性,则从o中删除这个属性
function subtract(o, p) {
for(prop in p) {
delete o[prop];
}
return o;
}
//返回一个新对象,这个对象同时拥有o的属性和p的属性; 如果有重名,则使用p中属性
funciton union(o, p) {
return extend(extend({}, o), p);
}
//返回一个新对象,同时拥有o和p的属性,像求交集。p中属性的值被忽略
function intersection(o,p) {
return restrict(extend({}, o), p);
}
属性的特性
- 值(value)
- 可写性(writable)
- 可枚举性(enumerable)
- 可配置性(configurable)
通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符
//得到自有属性的描述符
Object.getOwnPropertyDescriptor({x:1}, 'x');
//获得继承属性的特性,需要遍历原型链
Object。getPrototypeOf();
//要想设置属性的特性,或者让新建属性具有某种特性。
Object.definePeoperty(); //传入要修改的对象,要创建或修改的属性的名称以及属性描述符对象
var o = {};
//创建一个不可枚举的数据属性x,赋值为1
Object.defineProperty(o, 'x', {
value : 1,
writable:true,
enumerable:false,
configurable:true
});
//属性存在不可枚举
o.x; // 1
Object.keys(o) //[]
//对属性x进行修改,变为只读
Object.defineProperty(o, 'x', {writable:false});
//试图更改这个属性的值
o.x = 2//操作失败但报错,在严格模式里面会抛出类型错误异常
o.x == 1 //true
//配置属性
Object.defineProperty(o, 'x',{value:2});
//强x从数据属性修改为存取器属性
Object.defineProperty(o, 'x', {get:function(){return 0;}});
Object.defineProperty()的属性描述符对象不必包含所有4个特性。
对于新建属性:默认特性值是false或undefined。
对于修改已有属性:默认的特性值没有做任何修改
如果同时修改多个属性,则使用Object.defineProperties();
参数:
1. 要修改的对象
2. 映射表,包含要新建或修改的属性的名称,以及他们的属性描述符
var p = 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
}
});
原型属性、类属性、可扩展性、序列化对象
原型属性
//ECMAScript5:传递对象,可获取对象的原型
Object.getPrototypeOf()
//ECMAScript3
o.constructor.prototype检测一个对象的原型
类属性
function classof(o) {
if(o === null) return 'Null';
if(o === undefined) return 'Undefined';
return Object.prototype.toString.call(o).slice(8, -1);
}
解析:
1. object.prototype:object的原型对象,代表继承关系
2. toString:方法名
3. call(o):返回数据的类型
4. 获取里面的值,两个参数截取:包前不包后,负数依然是包前不包后,但是是代表从结尾计数的。
//demo
var p = {x:1};
var o = Object.create(p);
p.isPrototypeOf(o) //true:o继承与p
Object.prototype.isPrototype(o) //true,p继承与Object.prototype
可扩展性
Object.esExtensible(); //判断该对象是否可扩展
Object.preventExtensions(); //对象会变成不可扩展的。 改方法只会影响对象本身的可扩展性。如果给一个不可扩展的对象的原型添加属性,这个不可扩展的对象同样会继承这些新属性
Object.seal()
序列化对象
指:将对象的状态转换为字符串,也可以将字符串还原为对象
JSON.stringify() //序列化
JSON.parse() //还原对象
注意:
1. 支持对象、数组、字符串、无穷大数字、true、false和null
2. NaN、Infinity和-Infinity序列化结果依然是null
3. 日期对象序列化的结果是:ISO格式的日期字符串,但JSON.parse()依然保留他们的字符串形态,而不会还原成日期对象
4. 函数、RegExp、Error对象不支持
5. JSON.stringify() 只能序列化对象可枚举的自有属性,对于一个不能序列化的属性来说,在序列化后的输出字符串会忽略该属性