javascript指南-对象

1.创建对象的4个方法

(1)对象直接量

var empty={};						//没有任何属性的对象
var point={x:0,y:0};				//两个属性
var point2={x:point.x,y:point.y+1};	//更复杂的属性
var book={
	"main title":"javascript",		//属性名字里有空格,必须用字符串表示
	'sub-title':"the definitive guide",//属性名字里有连字符,必须用字符串表示
	"for":"all people",				//for是保留字,必须用引号
	author:{						//这个属性的值是一个对象
		firstname:"beauty",			//注意这里的属性名都没有双引号
		surname:"myth"
	}
};

(2)通过new创建对象

关键字new后跟随一个函数调用,这里的函数称为构造函数(constructor),构造函数用以初始化一个新创建的对象。js语言核心中的原始类型都包含内置的构造函数,如

var o=new Object();		//创建一个空对象,和{}一样
var a=new Array();		//创建一个空数组,和[]一样
var d=new Date();		//创建一个表示当前时间的Date对象
var r=new RegExp("js");	//创建一个可以进行模式匹配的RegExp对象

(3)原型

每一个javascript对象(null除外)都和另一个对象相关联,“另一个”对象就是我们熟知的原型,每一个对象都是从原型继承属性。

(4)Object.create()

它创建一个对象,其中第一个参数是对象的原型,第二个参数可以对对象的属性进行进一步描述。Object.create()是一个静态函数,而不是提供给某一个对象调用的方法。

var o1=Object.create({x:1,y:2});		//o1继承了属性x和y
var o2=Object.create(null);				//没有原型的新对象,o2不继承任何属性和方法
var o3=Object.create(Object.prototype);	//创建一个普通的空对象,o3和{}和new Object()一样

//通过原型继承创建一个新对象
//inherit()返回一个继承自原型对象p的属性的新对象
//这里使用Object.create()函数(如果存在的话)
//如果不存在Object.create(),则退化使用其他方法
function inherit(p){
	if(p==null){				//p是一个对象,但不能是null
		throw TypeError();
	}
	if(Object.create){			//如果Object.create存在
		return Object.create(p);//直接使用它
	}
	var t=typeof p;				//否则进行进一步检测
	if(t!=="object" && t!=="function"){
		throw TypeError();
	}
	function f(){};				//定义一个空构造函数
	f.prototype=p;				//将其原型属性设置为p
	return new f();				//使用f()创建p的继承对象
}

2.对象属性的查询与设置
(1)继承

如果要查询对象o的属性x,如果o中不存在x,那么将会继续在o的原型对象中查询属性x。如果原型对象中也没有x,但这个原型对象也有原型,那么继续在这个原型对象的原型上查询,直到找到x或者找到一个原型为null的对象为止。可以看到,对象的原型属性构成了一个“链”,通过这个“链”可以实现属性的继承。

var o={};		//o从Object.prototype继承对象的方法
o.x=1;			//给o定义一个属性x
var p=inherit(o);//p继承o和Object.prototype
p.y=2;			//给p定义一个属性y
var q=inherit(p);//q继承o,p和Object.prototype
q.z=3;			//给q定义一个属性z
var s=q.toString();//toString继承自Object.prototype
q.x+q.y			//=>3;x和y分别继承自o和p

(2)查询属性是否存在

//一种冗余但很易懂的方法
var len=undefined;
if(book){
	if(book.subtitle){
		len=book.subtitle.length;
	}
}
//一种更简练的常用方法,获取subtitle的length属性或undefined
var len=book && book.subtitle && book.subtitle.length;
3.删除属性

delete只是断开属性和宿主对象的联系,而不会去操作属性中的属性。

delete book.author;
delete book['main title'];

//执行这段代码后b.x的值仍然为1,由于已经删除的属性的引用依然存在,
//因此在js的某些实现中,可能因为这种不严谨的代码造成内存泄露。
//所以在销毁对象的时候,要遍历属性中的属性,依次删除
a={p:{x:1}};
b=a.p;
delete a.p;
delete只能删除自有属性,不能删除继承属性(要删除继承属性必须从定义这个属性的原型对象上删除它,而且这会影响到所有继承自这个原型的对象)。

当delete表达式删除成功或没有任何作用(比如删除不存在的属性时),它返回true。如果delete一个不是属性访问表达式,也返回true。

o={x:1};	//o有一个属性x,并继承属性toString
delete o.x;	//删除x,返回true
delete o.x;	//什么也没做(x已经不存在了),返回true
delete o.toString();//什么也没做(toString是继承来的,非自有的),返回true
delete 1;	//无意义返回true
delete不能删除可配置性为false的属性。某些内置对象的属性时不可配置的,比如通过变量声明和函数声明创建的全局对象的属性。在严格模式中,删除一个

不可配置对象会报一个类型错误,在非严格模式中,下面这些情况下的delete会返回false

delete Object.prototype;	//不能删除,属性是不可配置的
var x=1;					//声明一个全局变量
delete this.x;				//不能删除变量
function f(){};				//声明一个全局函数
delete this.f;				//不能删除全局函数
在非严格模式中删除全局对象的可配置属性时,可以省略对全局对象的引用,直接在delete操作符后跟随要删除的属性名既可。

this.x=1;	//创建一个可配置的全局属性(没有用var)
delete x;	//将它删除

然而在严格模式中,delete后面跟随一个非法的操作数 (比如x),则会报一个语法错误,因此必须显式指定对象及属性。

delete x;	//在严格模式下报语法错误
delete this.x;//正常工作

4.检测属性
(1)“in”运算符
如果对象的自有属性或继承属性中包含这个属性则返回true。
var o={x:1};
"x" in o;	//true,x是o的属性
"y" in o;	//false,y不是o的属性
"toString" in o;//true,o继承toString属性
(2)hasOwnProperty()
用来检测给定的属性是否是对象的自有属性,对于继承属性将返回false
var o={x:1};
o.hasOwnProperty("x");	//true,o有一个自有属性x
o.hasOwnProperty("y");	//false,o中不存在属性y
o.hasOwnProperty("toString");//false,toString是继承属性
(3)propertyIsEnumerable()
此方法是hasOwnProperty()的增强版,只有检测到属性是自由属性且这个属性是可枚举的才返回true。某些内置属性是不可枚举的。通常由js代码
创建的属性都是可枚举的,除非在ECMA Script 5中使用一个特殊的方法来改变属性的可枚举性。
var o=inherit({y:2});
o.x=1;
o.propertyIsEnumerable("x");	//true,o有一个可枚举的属性x
o.propertyIsEnumerable("y");	//false,y是继承来的
Object.prototype.propertyIsEnumerable("toString");//false,不可枚举
(4)同“in”的作用,使用“!==”判断一个属性是否是undefined
var o={x:1};
o.x !== undefined;		//true,o中有x属性
o.y !== undefined;		//false,o中没有y属性
o.toString !== undefined;//true,o继承toString属性
(5)有一种场景只能使用in而不能使用上面的方式。in可以区分不存在的属性和存在的属性但是值为undefined的属性
var o={x:undefined};	//属性被显式赋值为undefined
o.x !== undefined;		//false,属性存在,但值为undefined(不希望要的结果)
o.y !== undefined;		//false,属性不存在
"x" in o;				//true,属性存在
"y" in o;				//false,属性不存在
delete o.x;				//删除了属性x
"x" in o;				//false,属性不再存在
(6)!==可以区分undefined与n ull,有时不必做这种区分 
//如果o中含有属性x,且x的值不是null或undefined
if(o.x != null){
	o.x=o.x*2;
}
//如果o中含有属性x,且x的值不能转换为false,则乘以2
//如果x是undefined,null,false," ",0,NaN,则不处理
if(o.x){
	o.x=o.x*2;
}
5.枚举属性
(1)for/in循环
可以遍历对象中所有可枚举的属性(包含自有属性与继承的属性)。对象继承的内置方法不可枚举,但在对象中给对象添加的方法类属性是
可枚举的。
for(p in o){
	if(!o.hasOwnProperty(p)){	//跳过继承的属性
		continue;
	}
}

for(p in o){
	if(typeof o[p] ==="function"){//跳过方法
		continue;
	}
}
(2)Object.keys()
返回一个数组,这个数组由对象中可枚举的自有属性的名称组成。
var o={x:1};
var p=Object.create(o);	//p继承自o
p.y=2;
Object.keys(p);	//["y"],继承的属性x不会出来
(3)Object.getOwnPropertyNames()
同Object.keys(),返回对象的所有自有属性,而不仅仅是可枚举的属性。
6.属性getter和setter
在ECMAScript5中,属性值可以用getter和setter来替代,由它们定义的属性为“存取器”属性。好比c#中类里面的get,set。
定义存取器属性最简单的方法是使用对象直接量语法的一种扩展写法:
var o={
	//x和y为普通的可读写的数据属性
	x:1,
	y:1,
	//r是可读写的存取器属性
	get r(){return this.x+this.y},
	set r(num){this.x=num},
	//s是只读属性
	get s(){return this.x},
	//t是只写属性,读取只写属性返回为undefined
	set t(num){this.y=num}
};
7.属性的特性
数据属性的4个特性:值(value),可写性(writable),可枚举性(enumerable),可配置性(configurable)
存取器属性的4个特性:取(get),写(set),可枚举性(enumerable),可配置性(configurable)
通过调用Object.getOwnPropertyDescriptor()可以获得某个对象特定属性的属性描述符,它只能获取自有属性的描述符。
//返回{value: 1, writable: true, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({x:1},"x");
//返回{get: function, set: undefined, enumerable: true, configurable: true}
Object.getOwnPropertyDescriptor({get x(){}},"x");
//对于继承属性和不存在的属性,返回undefined
Object.getOwnPropertyDescriptor({},"x");	//没有这个属性
Object.getOwnPropertyDescriptor({},"toString");//继承属性
要想设置属性的特性,或者想让新建属性具有某种特性,需要使用 Object. defineProperty(),参数为(要修改的对象)(要创建或修改的属性)(属性描述符对象)
var 0={};//创建一个空对象
//添加一个不可枚举的属性x,并赋值为1
Object.defineProperty(o,"x",{value:1,writable:true,enumerable:false,configurable:true});
//属性是存在的,但是不可枚举
o.x;	//=>1
Object.keys(o);//=>[]
//现在对属性进行修改,让它变为只读
Object.defineProperty(o,"x",{writable:false});
//试图更改这个属性的值
o.x=2;//操作失败但不会报错,而在严格模式中会抛出类型错误异常
o.x;//=>1
//属性依然是可配置的,因此可以通过这种方式对它进行修改
Object.defineProperty(o,"x",{value:2});
o.x;
//现在将x从数据属性修改为存取器属性
Object.defineProperty(o,"x",{get:function(){return 0;}});

/*
*给Object.prototype添加一个不可枚举的extend()方法
*这个方法继承自调用它的对象,将作为参数传入的对象的属性一一复制
*除了值之外,也复制属性所有特性,除非在目标对象中存在同名的属性
*参数对象的所有自有对象(包括不可枚举的属性)也会一一复制
*/
Object.defineProperty(Object.prototype,"extend",{
	writable:true,
	enumerable:false,	//将其定义为不可枚举的
	configurable:true,
	value:function(o){	//值就是一个函数
		//得到所有自有属性,包括不可枚举的属性
		var names=Object.getOwnPropertyNames(o);
		//遍历它们
		for(var i=0;i<names.length;i++){
			//如果属性已经存在,则跳过
			if(names[i] in this){
				continue;
			}
			//获得o中属性的描述符
			var desc=Object.getOwnPropertyDescriptor(o,names[i]);
			//用它给this创建一个属性
			Object.defineProperty(this,names[i],desc);
		}
	}
});
8.对象的3个属性
每一个对象都有与之相关的原型(prototype),类(class)和可扩展性(extensible attribute)
(1)原型属性
对象的原型属性是用来继承属性的。
将对象作为参数传入 Object.getPrototypeOf()可以查询它的原型
检测一个对象是否是另一个对象的原型(或出于原型链中),使用 Object.prototype. is PrototypeOf()
(2)类属性
对象的类属性时一个字符串,表示对象的类型信息。
//获取一个对象的类型
function classof(o){
	if(o===null){
		return "Null";
	}
	if(o===undefined){
		return "undefined";
	}
	return Object.prototype.toString.call(o).slice(8,-1);
}


































  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值