JavaScript中幾乎全部東西都是一個對象,除了六種基本類型數據 - null,undefined,strings,numbers,boolean和symbols。javascript
任何不是原始值的東西都是Object。這包括數組,函數,構造函數和對象自己。前端
從概念上講,對象在全部編程語言中都是相同的。它們使用具備屬性和方法的代碼來表示真實世界。java
例如,若是您的對象是學生,則它將具備名稱,年齡,地址,ID等屬性以及updateAddress,updateName等方法。編程
在JavaScript中,將對象視爲包含元素項的列表,而且列表中的每一個項(屬性或方法)都由內存中的鍵值對存儲。數組
讓咱們看一個對象的例子。編程語言
firstObj 是一個對象,有2個屬性:1,age;value 爲 foo 和 28。函數
JavaScript對象在建立方式上有所不一樣。不須要非得用class建立,而且可使用字面量表示法聲明。優化
咱們能夠在JavaScript中以多種方式建立對象,讓咱們來看看都有哪些。spa
1. 對象字面量(最直接的方式)。對象字面量是用大括號括起來的以逗號分隔的鍵值對列表。對象字面量屬性值能夠是任何數據類型,包括數組文字,函數,嵌套對象字面量或基本數據類型。3d
`
注意:上面的學生對象鍵能夠經過點表示法訪問,即student.id,student.name或經過方括號表示法,即學生['id'],學生['姓名']等
`
2. Object.create()。該方法使用指定的原型和舊對象的屬性建立一個新對象。
`
注意:默認狀況下,每一個JavaScript函數都有一個原型對象屬性(默認狀況下它是空的)。方法或屬性能夠附加到此屬性。
`
下面是對象__proto__的輸出:
咱們如今可使用Object.create()方法向newStudent對象添加新屬性和數據。
`
注意:newStudent可以訪問student對象的鍵和值,由於它已被添加到newStudent的原型鏈中,這是咱們在javascript中繼承的一種方式。也就是說,newStudent將存儲一個指向student對象的連接。讀取屬性時也會查詢此父對象。
`
父母能夠有父母,依此類推。重複這一過程,直到咱們到達一個沒有任何父項的對象,即父項爲空。
3. 對象實例。將Object constructor與「new」關鍵字結合使用可讓咱們初始化新對象。
咱們來看一個例子吧。
可是,new Object() 不適合須要建立同一類型的多個對象的狀況,由於它須要爲每一個這樣的對象重複編寫上面的代碼。
爲了解決這個問題,咱們可使用下一個方法。
4. 對象構造器。當咱們須要一種能夠屢次建立對象「類型」的方法時,構造函數很是有用,而無需每次都從新定義對象,這可使用Object Constructor函數來實現。
咱們來看一個例子吧。
咱們建立了兩個具備相同屬性但具備不一樣值的對象。
5. Object.assign()。這是從其餘對象建立新對象的另外一種方法。
它將全部可枚舉的自有屬性的值從一個或多個源對象複製到目標對象。它將返回目標對象。讓咱們經過一個例子來理解:
Object.assign() 有不少用例,好比對象克隆,合併對象等。
6. Object.fromEntries()。方法將鍵值對列表轉換爲對象。咱們來看一個例子吧
`
注意:建立對象的最佳方法是經過字面量表示法,由於它在源代碼中佔用的空間更少。它能夠清楚地識別出發生了什麼,因此使用new Object(),你實際上只是輸入更多(理論上,若是沒有被JavaScript引擎優化)和進行沒必要要的函數調用。此外,字面量表示法建立對象,並在同一行代碼中分配屬性,而其餘代碼則否則。
`
如前所述,能夠經過點 或 括號表示法添加對象的屬性。讓咱們看一個例子
這裏,name 和 city 是對象屬性。
對象只能包含一個且具備一個值的鍵,也就是說同一個鍵只能有一個值。
屬性名稱能夠是字符串,數字或特殊字符,也能夠是動態屬性,但若是屬性名稱不是字符串,則必須使用括號表示法訪問它。所以,若是咱們須要訪問上面示例中的屬性1,咱們能夠執行a[1],可是a.1將返回語法錯誤。而a.name或[「name」]則均可以。
要更新屬性,咱們能夠再次使用上述兩種表示法。若是咱們爲已建立的屬性添加值,則會更新這個屬性的值。
咱們還能夠經過Object函數方法( 如Object.defineProperties() 或 Object.defineProperty() )建立和更新對象的屬性。
要刪除對象的屬性,咱們可使用delete關鍵字,來執行此操做。
若是成功刪除屬性,則返回值delete爲true。不然,它將是錯誤的。
如何迭代對象屬性?
若是咱們想要訪問全部對象鍵值對的狀況下,會出現這種需求。
使用循環 - for in 和 for of
在 for in 的狀況下,它迭代一個對象並逐個返回屬性。
Key將逐個對應對象的屬性,[key]返回該值。對於for in循環也迭代原型鏈並返回父鍵,因此若是你看到更多的鍵,不要感到驚訝。爲了不看到更多的鍵,咱們能夠執行hasOwnProperty 檢查以僅獲取當前對象鍵。
在 for of 狀況下,它迭代遍歷可迭代對象,僅獲取當前對象的key。這點也是和 for in 的區別。更多詳細解釋,能夠參考MDN for...of。
Object函數中有各類方法,它們只會訪問當前對象的屬性和值,而不是其原型鏈。
1. Object.keys() 或 Object.getOwnPropertyNames()。 返回字符串鍵數組。
2. Object.values(). 返回一個值數組。
3. Object.entries(). 返回 [key, value] 爲元素的二維數組
從輸出結果看,上面的屬性順序是不固定的。
有三種方法能夠檢查對象中是否存在屬性。
1. 使用hasOwnProperty。此方法返回一個布爾值,表示對象自己是否具備指定的屬性,而不是父/繼承屬性。
注意:即便屬性的值爲 null 或 undefined,hasOwnProperty 也會返回true。
若是咱們將hasOwnProperty做爲對象中的屬性名稱怎麼辦?這個值得思考。
2. 使用in運算符 - 若是指定的屬性位於指定的對象 或 其原型鏈中(即在其父級內),則 in 運算符返回true。
注意:hasOwnProperty僅檢查當前對象屬性,而 in 運算符中檢查當前+父屬性
3. 使用自定義功能
有多種方式能夠經過自定義方法檢查屬性是否存在。其中一個是經過 Object.keys。
什麼是按引用/共享複製和按值複製,它如何應用於對象?
不一樣之處在於,經過值,咱們的意思是每次建立內容時都會執行新的內存分配,而在引用的狀況下,咱們指向已經建立的內存空間。
在javascript的上下文中,全部原始數據類型都是經過值方法分配的內存,對於一個對象,能夠進行值或引用傳遞,根據具體操做狀況。
淺層和深層副本之間的核心區別在於如何將屬性複製到新對象。
在淺拷貝中,新對象與舊對象共享數據,即在上述示例的狀況下使用 = 建立對象的淺拷貝b。所以,在大多數狀況下,經過引用傳遞是淺層複製。
此外,淺拷貝將複製頂級屬性,但嵌套對象在原始(源)和副本(目標)之間共享。
淺拷貝的另外一種方法是使用Object.assign()。咱們來看看這個例子
正如咱們在上面看到的 obj.b.c = 30,這是 Object.assign() 的一個陷阱。 Object.assign 只生成淺拷貝。 newObj.b 和 obj.b共享對象的相同引用,沒有製做單獨的副本,而是複製了對象的引用。
在Deep copy中,新對象將擁有本身的一組鍵值對(與原始對象具備相同的值)而不是共享。
讓咱們看看作一些深層複製的方法
1. JSON.parse(JSON.stringify(object))
咱們沒法複製自定義的對象函數,以及鍵對應的值是undefined 或 Symbol的狀況,以下:
此外,此方法不適用於循環對象。
`
注意:循環對象是具備引用自身屬性的對象。
`
上面將拋出一個錯誤,converting circular structure to JSON.
2. 使用ES6展開運算符
可是,nested對象仍然是淺層複製的。
對象的等式 == 和 嚴格相等 === 運算符徹底相同,即只有兩個對象的內存引用相同時才相等。
例如,若是兩個變量引用同一個對象,它們是相等的:
未完待續
相關文章:
還能夠關注頭條號:「前端知否」