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.检测属性
var o={x:1};
"x" in o; //true,x是o的属性
"y" in o; //false,y不是o的属性
"toString" in o;//true,o继承toString属性
var o={x:1};
o.hasOwnProperty("x"); //true,o有一个自有属性x
o.hasOwnProperty("y"); //false,o中不存在属性y
o.hasOwnProperty("toString");//false,toString是继承属性
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()
6.属性getter和setter
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)//返回{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)检测一个对象是否是另一个对象的原型(或出于原型链中),使用 Object.prototype. is PrototypeOf()
//获取一个对象的类型
function classof(o){
if(o===null){
return "Null";
}
if(o===undefined){
return "undefined";
}
return Object.prototype.toString.call(o).slice(8,-1);
}