对象的属性特性:
1、可写(writable)
2、可枚举(enumerable)
3、可配置configurable
对象特性:
1、对象的原型(prototype)
2、对象的类(class)
3、对象的扩展标记
对象的种类
1、内置对象(数组、函数、日期和正则表达式)
2、宿主对象 htmlelement
3、自定义对象
属性的种类
自有属性
继承属性
原型:
每一个js对象(null和Object.prototype除外)都和另一个对象相关联,每一个对象都从原型继承属性
对象直接量({})和new Object的原型对象是Object.prototype
函数对象(function(){})的原型是Function.prototype
Date对象(new Date())的原型是Date.prototype
Array对象(new Array或者[])的原型是Array.prototype
RegExp对象(new RegExp())的原型是RegExp的原型是RegExp.prototype,
new加构造函数的对象的原型是构造函数的原型
其他原型对象都是普通对象,普通对象都具有原型。所有的内置构造函数(Function Array Date RegExp)以及自定义的构造函数都具有一个继承自Object.prototy的原型,比如Data.prototype的属性继承自Object.prototype,因此由new Date()创建的Date对象的属性同时继承自Date.prototype和Object.prototype.这一系列连接的原型对象就是所谓的原型链
Object.create()创建一个新对象,其中第一个参数是这个新对象的原型
var o={x:1,y:2}; var t=Object.create(o); console.log(t.x);//1 var t2=console.log(Object.create(Object.prototype));//{} function inherit(p){ if(p==null) throw TypeError(); var t=typeof p; if(t!=="object"&&t!=="function"){ throw TypeError(); } var f=function(){}; f.prototype=p; return new f(); } var t3=inherit(o); console.log(t3.x);//1
继承
属性赋值要么失败,要么创建一个属性,要么在原始对象中设置属性
属性访问错误
查询一个不存在的属性并不会报错,如果在对象O自身的属性或者继承的属性中均未找到属性x,属性表达式o.x则返回undefined
但是。如果对象不存在,那么试图查询这个不存在的对象的属性就会报错
简练和保险的做法
var len=book&&book.subtitle&&book.subtitle.length;
delete只是断开属性和宿主对象的关系,而不会去操作属性中的属性
var o={x:1}; var b=o.x; delete o.x; console.log(o.x);//undefined console.log(b);//1
delete运算符只能删除自有属性,不能删除继承属性
当delete表达式删除成功或者没有任何副作用(比如删除不存在的属性)时,它返回true。如果delete后不是一个属性访问表达式,delete同样返回true
var o={x:1}; console.log(delete o.x);//true console.log(delete o.x);//true console.log(delete o.toString());//true console.log(delete 1);//true
delete不能删除那些可配置属性为false的属性。某内置对象的属性是不可配置的,比如通过变量声明和函数声明创建的全局对象的属性。
检测属性
in 如果对象属性或者继承属性中包含这个属性则返回true
hasOwnProperty 检测给定的名字是否是对象的自有属性,对于继承属性它将返回false;
propertyIsEnmerable 只有检测到是自有属性且这个属性的可枚举为true时它才能返回true
var o={x:1}; console.log(o.propertyIsEnumerable("x"));//true console.log(o.propertyIsEnumerable("toString()"));//false(继承属性) console.log(Object.prototype.propertyIsEnumerable("toString()"));//false(不可枚举) console.log(o.hasOwnProperty("x"));//true console.log(o.hasOwnProperty("toString()"));//继承属性
可以用!==来判断一个属性是否属于undefined
var o={x:1}; var cs=console.log; cs(o.x!==undefined);//true cs(o.y!==undefined);false cs(o.toString()!==undefined);//true
判读属性是否为真值(不属于undefined null false "" 0或者NaN);
in(o.x) o.x*2=;
枚举属性
for/in
var o={x:1,y:2}; for(var p in o){ if(!o.hasOwnProperty(p)){ continue; }//过滤继承属性 if(typeof o[p]=="function"){ continue; }//过滤方法 console.log(p); }
function extend(o,p){//循环p的可枚举属性,复制到o中,如果o和p有同名的属性,则覆盖o中的属性 for(var prop in p){ o[prop]=p[prop]; } return o; } function merge(o,p){//把p的属性复制到o中,如果有同名的属性,则O的属性不受影响 for(var prop in p){ if(o.hasOwnProperty(prop)){ continue; } o[prop]=p[prop]; } return o; } function restrict(o,p){//如果p中不存在o的同名属性,则删掉这个属性 for(var prop in o){ if(!(prop in p)){ delete o[prop]; } } return o; } function substract(o,p){//如果p中存在o的同名属性,则删掉这个属性 for(var prop in p){ delete o[prop]; } } function union(o,p){//返回一个新对象,这个对象同时拥有o的属性和p的属性,如果有同名属性,使用p中的属性值 return extend(extend({},o),p); } function intersection(o,p){//返回一个新对象,这个对象拥有同时在o和p存在的属性
return restrict(extend({},o),p); } function keys(o){//返回一个数组,这个数组包含的是o中可枚举的自有属性的名字 if(typeof o!=="object"){ throw TypeError(); } var result=[]; for(var prop in o){ if(o.hasOwnProperty(prop)){ result.push(o[prop]); } } return result; }
object.keys 返回一个数组,这个数组有对象中可枚举的自有属性的名称组成
object.getOwnPropertyNames() 返回对象的所有自有属性的名称,而不仅仅是可枚举的属性
属性getter和setter
var p={ x:1.0, y:1.0, get r(){ return Math.sqrt(this.x*this.x+this.y*this.y); }, set r(newvlaue){ var oldvlue=Math.sqrt(this.x*this.x+this.y*this.y); var ratio=newvlaue/oldvlue; this.x*=ratio; this.y*=ratio; } }; console.log(p.r);
存取器属性定义为一个或者两个和属性同名的函数,而且是可以继承的
数据属性:value writable(bool) enumerable(bool) configurable(bool)
存取器属性:get(function) set enumerable configurable
Object.getOwnPropertyDescriptor 可以获得某个对象特定属性的属性描述
对于继承属性和不存在的属性,返回undefined
Object.defineProperty 设置属性的特性或者想让新建属性具有某种特性
不必包含4个特性,对于新建创的属性来说。默认的特性值是false或者undefined,对于修改的已有属性来说,默认的特性值没有做任何修改,不能修改继承属性
同时修改或者创建多个属性, Object.defineProperties()
对象的三个属性:prototype class(类属性) 可扩展性
对象的原型属性 对象创建之初就设置好
将对象作为参数传入Object.getPrototypeOf()可以查询到对象的原型,在em3中经常使用表达式o.constructor.prototype来检测一个对象的原型,通过new表达式创建的对象,通常继承一个constructor属性,这个属性指代创建了这个对象的构造函数。这个方法并不可靠
比如。通过对象直接量或者Object.create创建的对象包含一个名为constructor的属性,这个属性指代Object()构造函数。因此。constructor.prototype才是对象直接量的真正原型,但对于通过Object.create创建的对象则往往不是这样
var o={x:1}; console.log(o.constructor);//function Object(){} console.log(o.constructor.prototype);//{} console.log(Object.getPrototypeOf(o));//{} var p=Object.create(o); console.log(p.constructor);//function Object(){} console.log(p.constructor.prototype);//object{} console.log(Object.getPrototypeOf(p));//{x:1}
要检测一个对象是否后另一对象的原型(或者处于原型链),请使用isPrototypeOf()方法
和instranceof的区别
isPrototypeOf()左边是原型对象,参数是查询对象 判断原型对象是否在查询对象的原型链上
instranceof 左边是查询对象 右边是构造函数 判断构造函数的prototype时候在对象的原型链上
var p={x:1}; var o=Object.create(p); console.log(p.isPrototypeOf(o));//true console.log(Object.prototype.isPrototypeOf(o));//true
在火狐和谷歌浏览器中可以直接用__proto__来直接查询或者设置对象的原型,但在Ie中没有实现
var p={x:1}; var o=Object.create(p); console.log(p.__proto__);//{} console.log(o.__proto__);//{x:1}
对象的类属性是个一个字符串,用以表示对象的类型信息,只有一种间接的方法查询,默认的toString()方法(继承自Object.prototype)返回如下格式的字符串:
[object class]
因此要的对象的类,可以调用对象的toString()方法,然后提取已返回字符串的第8到倒数第二位置之间的字符
var p={x:1}; var a=[]; function getClass(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } console.log(getClass(a));//Array console.log(getClass(p));//Object console.log(getClass(1));//Number
function getClass(o){ if(o===null) return "Null"; if(o===undefined) return "Undefined"; return Object.prototype.toString.call(o).slice(8,-1); } console.log(getClass({}));//Object console.log(getClass([]));//Array console.log(getClass(/./));//RegExp console.log(getClass(new Date()));//Date console.log(getClass(window));//global var f=function(){}; console.log(getClass(new f()));//Object
JSON.stringgify(o) 对象转换为字符串
JSON.parse(s) 字符串还原为对象
支持对象、数组、字符串、无穷大数字、true、false和null。并且它们可以序列化和还原。NaN Infinity和-Infinity序列化的结果是null,日期对象序列化的结果是ISO格式的日期字符串(参照Date.toJSON()函数),但JSON.parse()依然保留它们自己的字符串形态,而不是还原。函数、RegExp、Error和undefined值不能序列化和还原。JSON.stringgify()只能序列化对象可枚举的自有属性,对于一个不能序列化的属性,在序列化的输出字符串中会将这个属性省略掉
var n=new Date();
console.log(n);//Tue Dec 15 2015 19:37:54 GMT+0800 (中国标准时间) console.log(JSON.stringify(n));//"2015-12-15T11:36:45.826Z" console.log(n.toJSON());//2015-12-15T11:36:45.826Z console.log(JSON.parse(JSON.stringify(n)));//2015-12-15T11:36:45.826Z
默认的toString()方法返回值带有的信息量很少(可以检测对象的类型),例如:
var s={x:1,y:2}.toString();//"[object object]"
由于默认的toString方法并不会输出很多有用的信息。因此很多类都带有自定义的toString。例如,当数组转换为字符串的时候,结果是一个数组元素列表,只是每个元素都转换为了字符串,当函数转换为字符串的时候,得到函数的源代码
toLocaleString() Date和Number类对toLocaleString()做了定制,可以用它对数字、日期和时间做本地化的转换。Array唯一的不同是每个数组元素都会调用toLocaleString()方法,而不是各自的toString方法