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()方法同樣的。
知識不完,更新不止。