Object(对象)是在全部的编程语言中都十分重要的一个概念,对于事物咱们能够把他们看做是一个对象,而每个事物都有本身的表示的属性和对于某一信息做出的相应的操做。而这些东西就变成了事物的属性和方法。chrome
在JS中咱们能够见到的对象常量有以下的形式:编程
1 var obj= { 2 3 name:"Arvin", 4 5 lastName:"Huang" , 6 7 whatsName:function(){ 8 9 alert(this.name+" "+this.lastName); 10 11 }, 12 13 }
由上面的代码咱们能够看出实际上在JS中的对象就是一个以键值对形式存储属性的一个集合,每个属性有一个特定的名称,并与名称相对应的值。其实这种关系是有一个专有名称的,咱们能够称之为映射,固然对于对象来讲,除了能够经过这种方式来保持自有属性,还能够经过继承的方式来获取继承属性。这种方式咱们称做“原型式继承”。json
接下来咱们将从js对象的属性,属性特性,方法和对象特性等多个方面来学习对象的概念。数组
2.js对象属性操做。编程语言
一:js对象建立与对对象属性。ui
咱们先看以下的代码。
1 var built = function(){ 2 3 var me = this; 4 me.name = "Arvin"; 5 6 } 7 8 built.prototype = { 9 toStr:function(value){ 10 alert("there have a " + value); 11 } 12 13 }; 14 15 var obj = new built();
上面的代码就描述了一种咱们经常使用到的一种建立对象的方法,使用new关键字来建立一个拥有独立内存区域和指向原型的指针的对象。当咱们使用的new的时候,js解析器会分配一块内存空间,用以存放当前的对象的自有属性。以后解析器会给这一对象一个_proto_属性指向的原型对象内容。
还有一种方式咱们称之为对象直接量申明的方式,代码以下:
1 var obj = { 2 3 name:"Arvin", 4 5 toStr:function(value){ 6 alert("there has a "+value); 7 } 8 };
对象直接量就是直接经过花括号包裹的键值对的形式来定义当前对象的。每两个值之间的经过逗号来进行分割。键和值之间经过冒号来分割。放解析器读取到当前的内容的时候会自动的生成一个对象的内容并把当前的对象存储在当前上下文中。
还有一种对象建立的方式是使用Object.create()方法,这一方法是ECMAScript5中定义的一个内容,它是一个静态方法,其使用方法以下。
1 var obj = Object.create({x:1,y:2});//obj继承了属性x和y
这一方法传入的参数是一个对象,而且这一做用的对象将会做为新的对象的原型存在。
接下来咱们来看一看属性。
当咱们在chrome的命令台中运行第一段示例代码的时候咱们能够看到以下的内容。
可见,当咱们在构造函数中直接使用this指针(指代当前的对象)添加属性,这时,其实咱们的设置的属性是当前的对象特有的属性,独属于当前的对象的,这样的属性称之为自有属性。而在咱们定义构造函数的时候,咱们为构造函数的prototype属性(指向原型对象),这时咱们定义了prototype的内容和方法。当使用new关键字来进行对象的构造的时候,咱们所构造的对象其实是继承了这一原型对象的内容的,因此咱们能够再对象的_proto_属性中能够看见继承与原型对象的内容,但这也是属于当前的对象的,(原型链内容请阅读原型链学习汇总。)这样的属性咱们称之为继承属性。
咱们对象属性的类型能够是字符串,数字,true,false,null和undefined,或者是对象的内容。固然虽然字符串,数字,和布尔值虽然不是对象,可是性质和不可变对象相似的。
咱们以前说过属性的值是名字和值,其中名字是能够是包括空字符串在内的任意字符串,可是属性的值是除这些以外的,还能够是定义好的存取器方法。以下代码:
1 var o = { 2 x:1,3 y:1,4 5 get r(){return x+y;}, 6 set r(value){this.x = value;} 7 }
如上代码可见,在对象O中r就是一个存取器属性内容,存取器属性实际上是不可设置的属性的一种,只有当他拥有了getter方法的时候才能够取值的,而又setter方法的时候表示这一属性是可写的,存取其属性实在ECMAScript5中才有定义的,其实是把属性经过函数的方式进行与外界的数据交互的。从而使得属性值自己不能够直接进行配置或是获取。
存取器属性的写法就如上面代码书写的同样,get关键字空格以后跟属性名称做为函数的名称,set方法和get方法是同样编写的,只是会传入参数,而且参数的个数严格是一个,不然会报语法错误。在使用的时候咱们是经过o.r来调用getter方法,而setter方法的调用时以下,o.r = 2;
当咱们没有定义setter方法的时候,使用对象调用setter方法的时候虽然不会报出错误,可是对象中没有任何变化。而当咱们在定义对象的时候没有定义getter方法的时候,在咱们调用这一属性的时候,将会获得undefined。
二:js对象属性操做
1.访问属性。
对象属性的访问通常是经过obj.attr的方式来访问的,或者是obj[attr]的方式来进行操做,通常状况之下这样都是能够行的通的,可是但咱们的是属性名称是一些特殊字段的额时候就要注意了,例如关键字或是保留字段,这是后咱们要经过中括号的形式来访问才能够成功,固然这点在ECMAScript5中的已经更改了,可是在咱们日常编写的时候仍是要注意变量的命名。对于保留字段尽可能不要使用。
属性访问的时候,当对象存在而对象中没有这一属性的时候,若是程序中访问了当前的属性的话咱们,js的解析器将会返回undefined的数值,可是若是当前须要访问的对象是不存在的,这个时候js就会返回一个类型错误。
2.属性赋值。
咱们能够经过赋值运算来为属性中可写的属性赋值,当访问的对象存在,可是表达式中的属性不存在时候,则会返回一个类型错误。以下
1 var obj = { 2 3 this.name = "Arvin"; 4 5 }; 6 7 obj.lastName = "Huang"; //此时对象将会被赋予一个新的属性为lastName而且其值为Huang
可是虽说null和undefined在js中是特有的对象,可是咱们也不能够为其设置属性,由于他们都是只读的。而上一段代码中的原理其实就是这个。obj.lastName不存在,因此js返回的额是undefined对象,以后再计算赋值,浏览器会为其添加新的属性来存储当前赋予的值。
固然有一些对象属性虽然不能赋值可是咱们对其进行赋值的时候仍是不会报错,例如以下代码:
1 Object.prototype = 0;//复制失败可是并不会报错。object原名没有被修改。
在ECMAScript中的严格模式下面已经获得了修复。
咱们对于对象中的属性赋值出错的状况会有以下的总结。
3.属性删除:
delete运算符能够删除对象中的属性。这里先讲一下delete运算符的内容。
delete:一元运算符,用于删除对象和数组中的属性的,单它也仅仅是删除一个值,并不会返回删除的内容。
1 var o = {x:1, y:2};//定义了一个对象 2 delete o.x; 3 "x" in o; //这里将会获得false值。 4 5 var a = [1,2,3]; 6 delete a[1]; 7 2 in a; //元素2已经再也不数组中了。 8 9 a.length == 3 //这里将会显示为true,虽然删除了属性可是,留下了一个占位,因此数组长度没有变化。
这是在chrome中运行的结果,咱们能够看见,删除属性以后其实只是元素自己与对象的关系被断开了,可是实际上数组中的内容数量仍是没有改变的,可是并无数值,因此经过undefined来进行填充。
delete操做数须要时一个左值(对象的属性,变量),若是不是的话将会不作任何操做返回true。以下图:
图片中可见,返回的值是true,可是7并非一个左值。
固然也有一些delete没有办法删除的左值。
因而可知,delete是没有办法删除用var关键字定义的变量是不能够删除的。在delete删除元素失败的时候会返回一个false值。固然咱们使用群居变量定义的属性也是能够经过delete对象来删除的,由于全局对象也是对象吗。
好接下来回归正题。对象经过delete实际上就是断开当前的对象和属性之间的联系。当咱们删除了属性以后还要查找这一属性的时候,咱们会获得的值是undefined这个值。固然delete只能删除自有属性,对于继承属性delete是没有做用的。若是想删除继承属性的话,直接在对原型对象属性进行删除不就行了。。还有一点,当对象的属性是不可配置的时候也是不删除的(可是当对象是不可配置的,可是其属性是能够配置的时候,仍是能够删除的。对象的特性内容请看后文。)
固然在用delete的时候仍是要注意的应为有些状况下将会出现一些问题。以下代码。
1 var o= {x:1, y:2}; 2 var b = o.x; 3 delete o.x; 4 //这个时候b实际上仍是只想以前的x的内容的,这种状况很容易致使内存泄漏的额问题。
4.检测属性:
咱们常常要判断某一个属性是否存在于某一个对象中。这个时候咱们能够经过in运算符,hasOwnProperty()方法或是propertylsEnumerable()方法来进行判断。
首先咱们来说一下IN运算符的内容:in操做符是一个二元操做符,其左边的额数值是字符串或者是能够转化为字符串的,右边的内容是对象。判断的当前的属性是否是存在于对象中。
1 var point = {x:1}; 2 3 "x" in point; //这一个表达式最后返回的将会是true。 4 "toString" in point; //因为toString是继承方法,因此也是返回true. 5 "z" in point; //这一表达式最后返回false,由于point对象中没有z属性. 6 7 //数组能够经过索引来判断当前的数组中是否有相应的数据。
因此咱们能够经过使用in操做符来判断当前的属性是否是存在与某一对象中的。而且即便是继承属性,也是能够测试的。
第二种检测的方法是hasOwnProperty()方法。代码以下:
1 var o ={x:1}; 2 3 o.hasOwnProperty("x"); //true:o有这一属性, 4 o.hasOwnProperty("y"); //false; 5 o.hasOwnProperty("toString"); //false
因此咱们能够知道,hasOwnProperty方法只能测试当前属性是否是对象的自有属性。
第三种检测方式是用propertylsEnumerable()方法。只有当当前的属性是自有属性,而且是可枚举的的时候,这一方法才会返回true。
5.枚举属性:
遍历属性将会是进场要用到的内容。
三:js属性特性:
属性的特性其实就是值当前的属性是否能够写能够读等等。即外部对象对于属性操做的权限。
当前的js通常的属性都是有4中属性。分别是:数值属性value,可读属性writable,可枚举属性enumerable,和可配置属性configurable。可是因为对象中存在一类特别的属性存取器属性,因此对于存取器属性的值其实是有点不一样的,他有本身的特别的属性特性包括,读取(get),写入(set),可枚举和可配置。为了实现这一对象属性的描述,js中定义了一个属性描述符对象。而且能够经过Object.getOwnPropertyDescriptor()方法来获取某个对象中的特定属性的描述符。固然当前函数只能获取对象自有属性的描述,若是要获取继承属性的描述符的话,须要使用Object.getPrototypeOf();
固然咱们可使用Object.defineProperty方法进行对象内容的进行相关的编辑,以下
1 Object.defineProperty({},"x", {value:1, writable:true, enumerable:true, configurable:true}); 2 //这是将返回一个对象,而且其中设定了一个可读写,枚举和配置的属性x 3 4 //固然若是要修改的对象自己其中就有一个这一属性,而后想经过这一方法配置的话。也是能够的。 5 6 //特性对象中的内容能够不用写全,当添加属性的时候未写明的内容将会直接设置成为false或是undefined。而在修改属性的时候未写明的内容将不会有任何改变。
固然咱们也能够用Object.defineProperties()来进行对个属性的修改和添加,这是咱们须要一个对应列表。以下代码
1 Object.defineProperties({}, { 2 x:{value:1, writable:true}, 3 y:{value:2, writable:true}, 4 ...... 5 });
当咱们在定义一个对元素的属性的时候,咱们要注意上面两个方法在某些状况之下是会报错误的,状况以下
var obj = { x:1, get y(){return x;}, set y(value){x = value;} }; console.log(""+obj.hasOwnProperty("y")); console.log(Object.getOwnPropertyNames(obj).toString()); Object.defineProperty(obj,"x",{value:1, writable:true, enumerable:false, configurable:true});//修改当前属性为不可枚举的 console.log(Object.getOwnPropertyNames(obj).toString()); console.log(""+obj.hasOwnProperty("x")); console.log(""+obj.propertyIsEnumerable("x")); obj.x = 2; console.log(obj.x); Object.defineProperty(obj,"x",{value:1, writable:false, enumerable:true, configurable:true});//修改当前属性为不可写的 console.log(Object.getOwnPropertyNames(obj).toString()); console.log(""+obj.hasOwnProperty("x")); obj.x = 2; console.log(obj.x); Object.defineProperty(obj,"x",{value:1, writable:true, enumerable:true, configurable:false});//修改当前属性为不可配置的 console.log(Object.getOwnPropertyNames(obj).toString()); console.log(""+obj.hasOwnProperty("x")); obj.x = 3; console.log(obj.x); Object.defineProperty(obj,"x",{value:1, writable:false, enumerable:false, configurable:true});//测试不可配置属性是否能够改变属性特性 console.log(Object.getOwnPropertyNames(obj).toString()); console.log(""+obj.hasOwnProperty("x")); obj.x = 3; console.log(obj.x);
运行结果以下:
四:js对象方法。
咱们这里主要说明的将会是js的Object.prototype里面的原生的方法。
一、toString()方法,是咱们经常使用到的一个方法,当咱们要将对象转换为值的时候,都会调用这么一个方法,可是其实现,实际上只是返回了一些对象的信息。例如:
1 var s = {x:1, y:1}.toString() 2 //这里返回的内容是[Object, Object]
固然在许多的内置对象中toString方法其实是被重写了的,例如,array(数组)对象中,咱们是童toString方法的话,是吧当前的额数组中的内容以逗号隔开的形式来返回字符串的。函数调用toString方法的时候,是返回函数的源代码。还有Data对象是toString方法返回的是当前时间星系字符串,等等。
二、toLocaleString方法和toString方法是相似的,只是返回的是本地的字符串,实际上就是根据一些当地的用户使用习惯来定义的返回内容。
三、toJSON()方法,实际上在Object.prototype中是没有这一方法的。咱们经常使用的多的是在Date对象中使用,当须要获取当前对象的序列化的时候调用他它怎会得到当前对象的序列化。
4.valueOf()方法,相似于toString()方法,实际上在js只有在要吧当前的对象转换为费字符串的状况之下才会调用这一方法。通常的对象调用这一方法的时候,返回的数值,实际上就是当前对象的内容,固然内置对象也有改变了这一方法的实现的。例如Date.valueOf(),返回的就是从1970年1月1日到如今的毫秒数。
五:js对象的特性。
一、原型属性:原型属性实际上就是当前的对象继承自哪个对象,当前对象继承了原型对象中的方法和属性,因此咱们称之为对象的原型属性,固然也能够称之为对象的原型。固然咱们也有一个方法测试某一对象是不是继承与另外一对象,使用isPrototypeOf()方法来进行判断。
二、类的属性:其实其自己是一个字符串来着,用以表示对象的类型,上文中的提到的toString方法能够获取类的属性。固然因为toString在许多的内置对象中有重写,因此党咱们调用toString的方法的时候最好使用的以下封装方法。
1 function classof(o){ 2 if(o === null){ 3 return "Null"; 4 } 5 if( o === undefined){ 6 return "Undefined"; 7 } 8 return Object.prototype.toString.call(o).slice(8, -1); 9 }
三、可扩展性:对象的可扩展性表示的是但钱的对象是不是能够扩展的,宿主对象的可扩展性是有但钱的额js的引擎来进行定义的,全部的额内置对象都是能够扩展的,除非咱们把其转化成为不可扩展的对象,Object.esExtensible()能够用来进行判断的当前的对象是不是能够扩展到的。Object.preventExtensions()方法设置当前的兑现格式不能够扩展的内容。当咱们把对象设置成为不可扩展以后,咱们就不能够在准换当前的内容。实际上上述的方法只是对于当前对象的自由空间来定义的,因此党咱们改变源性对象的时候当前的对象中实际上仍是会有必定的变化的。固然还有一些其余的方法是能够来避免对象的受到外来的干扰的。Object.seal()其实和以前的preventExtensible()方法仍是挺像的,除了将但前的对象设置成为不可设置的,同事吧其全部的额属性也同时设置成为不可设置的。还有一个函数更绝,Object.freeze()方法不只仅把对象的属性和自己设置成为不可配置的,同事也设置为不可写的状态,因此所设置完成以后整个就一只读对象。
4.序列化对象:实际上就是指当前的对象转化为字符串,固然也是能够还原的。序列化当前的对象实际上就是经过JSON来进行操做的。其中将Object转化成为json字符串的方法是,JSON.stringify(),其中的参数是须要序列化的对象。而JSON.parse()则是反序列化,但实际上这样得出的对象是序列化的深拷贝。固然JSON只是js的一个子集,支持对象,数组,字符串,无穷大数字,true,false,null。NaN,infinity等等这一类数据在序列化的时候都会统一转化成为null,而Date的数据在序列化的时候是会直接转换成为ISO格式的日期字符串,就相似于Date.toJSON()方法同样的。
知识不完,更新不止。