接上文:Object重識(一)javascript
對象繼承,咱們不介紹名詞,不說是什麼樣的繼承,只從頭看下每一個繼承方式的不足,並介紹如何補充java
function A (name) { this.name = name } function B () {} B.prototype = new A('張三') console.log(new B("李四").name) // 張三
此方法是將 B
的原型直接指向 A
的原型,從而達到繼承的目的。Object.create
方式建立對象等同於此方式。數組
優點:函數
可達到屬性複用。this
缺陷:spa
沒法在實例化的時候傳遞參數,不可配置。上述示例中 A
和 B
的名稱都爲 張三。即便咱們在實例化 B
的時候傳入一個名稱。prototype
改進版可在實例化的時候添加參數code
function A (name) { this.name = name; } function B (name) { A.call(this, name) } console.log(new B('李四').name) // 李四
優點:對象
可實現定製化,支持傳參配置繼承
缺陷:
沒法複用,全部內容都經過構造函數定義
function A (name) { this.name = name; } A.prototype.address = '中國' function B (name) { A.call(this, name) } B.prototype = new A(); const b = new B('李四') console.log(b.name) // 李四 console.log(b.address) // 中國
總結:
此繼承方式也不是完整版,只是讓你們瞭解繼承的實現方式。像什麼 寄生繼承、寄生組合繼承。我們就多囉嗦了,容易越看越亂。有興趣的讀者能夠以後再跟你們分享或者自行查閱。
有了ES6
以後感受空氣都甜了。以前複雜的繼承寫法都變得特別簡單。看栗子↓↓↓↓↓
class A { constructor (name) { this.name = name; } } class B extends A { constructor (name) { super(name) } } const b = new B('李四') console.log(b.name)
class
方式建立對象注意點:
構造函數constructor
中的方法都屬於自身的方法。構造函數constructor
以外的方法都屬於原型方法舉慄說明:
class A { constructor () { this.log = function () { console.log('111111') } } log () { console.log('222222') } } const a = new A() a.log() // 111111 -- 原型鏈的查找問題 console.log(a.log) /* ƒ () { console.log('111111') } */ console.log(a.__proto__.log) /* ƒ log () { console.log('222222') } */
使用 JSON.stringify
方法將對象轉換爲字符串顯示
const obj = { a: 1, b: 2, c: 3 } const strObj = JSON.stringify(obj) console.log(strObj) // {"a":1,"b":2,"c":3}
注意點:
JSON.stringify(obj, replacer, space)
接收三個參數
obj
被轉換的對象replacer
能夠是 函數 或 數組。爲數組,只轉換數組中的值const obj = { a: 1, b: 2, c: 3 } // 第二個參數爲數組 console.log(JSON.stringify(obj, ['a', 'b'])) // {"a":1,"b":2} // 第二個參數爲函數 function replacer(key, value) { if (value === 1){ return undefined } return value } console.log(JSON.stringify(obj, replacer)) // {"b":2,"c":3}
space
能夠爲數字或字符串,添加輸出結果中的間距。最大間距數量爲 10
。最小爲 0
const obj = { a: 1, b: 2, c: 3 } // 爲數字 console.log(JSON.stringify(obj, null, 2)) /* { "a": 1, "b": 2, "c": 3 } */ // 爲字符串 console.log(JSON.stringify(obj, null, '-')) /* { -"a": 1, -"b": 2, -"c": 3 } */
Object.keys
返回對象的 key
值組成的數組Object.values
返回對象的value
值組成的數組Object.entries
返回對象的 key
值和value
值組成的數組const obj = { a: 1, b: 2, c: 3 } console.log(Object.keys(obj)) // [ 'a', 'b', 'c' ] console.log(Object.values(obj)) // [ 1, 2, 3 ] console.log(Object.entries(obj)) // [ [ 'a', 1 ], [ 'b', 2 ], [ 'c', 3 ] ]
上述方法會用就能夠,沒太多須要注意的點。
什麼是對象拓展?
1.1
小節中建立的對象均可以添加新的屬性和方法,這就叫對象拓展。可使用 Object.isExtensible
方法查看。
function B () {} const a = {} const b = new B() console.log(Object.isExtensible(a)) // true console.log(Object.isExtensible(b)) // true
禁止對象拓展, 可以使用 Object.preventExtensions
方法
function B () {} const a = {} const b = new B() // 禁止對象拓展 Object.preventExtensions(a) Object.preventExtensions(b) console.log(Object.isExtensible(a)) // false console.log(Object.isExtensible(b)) // false
Object.seal
對象密封能夠理解爲字面的意思。就是把一個對象密封起來。
密封的對象不可拓展(不能添加新屬性),不可刪除屬性,不能修改已有屬性的屬性描述符(writeable、value
等)
將一個對象密封,可使用Object.seal
方法
一樣,查詢一個對象是不是密封對象,可使用Object.isSealed
方法
const obj = { a: 1, b: 2, c: 3 } // 密封一個對象 Object.seal(obj) // 嘗試刪除 delete obj.a console.log(obj) // { a: 1, b: 2, c: 3 } // 嘗試添加 obj.d = 4 console.log(obj) // { a: 1, b: 2, c: 3 } // 查詢對象是不是密封狀態 console.log(Object.isSealed(obj)) // true // 嘗試修改原有屬性值 obj.a = 4 console.log(obj) // { a: 4, b: 2, c: 3 }
注意:
雖然將對象密封了,可是依舊能夠修改原有的屬性值。若是想讓一個對象不可更改,能夠用到下面這個方法。
Object.freeze
對象凍結顧名思義就是將對象的全部屬性都凍結住,不可修改,不可增刪。可使用Object.freeze
方法凍結一個對象。查看一個對象是不是凍結對象可使用Object.isFrozen()
方法。
const obj = { a: 1, b: 2, c: 3 } // 凍結一個對象 Object.freeze(obj) // 嘗試新增 obj.d = 4 console.log(obj) //{ a: 1, b: 2, c: 3 } // 嘗試刪除 delete obj.a console.log(obj) //{ a: 1, b: 2, c: 3 } // 嘗試修改 obj.a = 4 console.log(obj) //{ a: 1, b: 2, c: 3 } // 查看對象是否凍結 Object.isFrozen(obj) // true
看吧,凍結以後的對象你是不能對它作操做的。
可是………………
這種狀況下能夠修改
const obj = { a: 1, b: 2, c: { d: 4 } } Object.freeze(obj) obj.c.d = 11 console.log(obj.c) //{ d: 11 }
也就是說,凍結對象只能凍結一層,不能深層次凍結,若是須要深層次凍結,則須要遞歸的凍結每一個值爲對象的屬性。
此操做等同於數組解構,不一樣的是,對象會根據屬性值進行解構操做。話很少說,小栗子來看下
const obj = { a: 1, b: 2, c: 3 } // 普通解構 let {a, b} = obj console.log(a, b) // 1, 2 // 帶默認值的解構,解構不到時,賦值爲默認值 let {a = 0, b = 0, d = 0} = obj console.log(a,b, d) // 1,2,0 // 解構並重命名 let {a: newA, b: newB} = obj console.log(newA, newB) // 1, 2 // 默認值 and 重命名 let {d: newA = 0, b: newB = 0} = obj console.log(newA, newB) // 0, 2
注意點:
Object.assign、Object.is
Object.assign
能夠實現對象的複製,合併,深拷貝等操做,須要注意的點是:繼承的屬性和不可枚舉(enumerable爲false
)的屬性不能拷貝
// 深拷貝 const obj1 = { d: 4, e: 5 } const a = Object.assign({}, obj1) console.log(a) obj1.d = 2 console.log(a) // 修改以後不會變更a的值
const obj = { a: 1, b: 2, c: 3 } const obj1 = { a: 4, e: 5 } const a = Object.assign(obj, obj1) console.log(a) // { a: 4, b: 2, c: 3, e: 5 }
合併後,若是第二個參數中有和第一個參數相同的屬性,則第二個參數的屬性會覆蓋第一個參數的屬性。
以前的工做中,咱們會知道這樣一句話,NaN不等於任何東西,包括它自身
。那麼咱們用Object.is
來試一下。
此方法用來比較兩個對象是否相等。
Object.is(NaN, NaN) // true Object.is(+0, -0) // false
除去上面這種案例,其餘的表現與 ===
相同
?.
和 ??
(可選鏈和空值合併)?.
平常工做中,像下面這種代碼很是常見。
const obj = { result: { a: 1 } } let result = obj.result && obj.result.a;
固然,有了可選鏈以後,咱們就不須要這麼麻煩了 ,上述代碼可改寫成如下方式:
const obj = { result: { a: 1 } } let result = obj.result?.a;
若是obj.result
爲undefined
或者 null
時,會中斷操做而返回undefined
或者 null
此方法也可用於函數
const obj = { result: function (){ } } obj.result?.();
用於數組:
const arr = [] arr?.[0]
用於表達式:
const obj = { parentResult } obj?.['parent' + 'Result']
可連用:
const arr = [[[1]]] arr?.[0]?.[0]?.[0]
可選鏈具備短路功能,若是左邊的操做數爲 undefined
和 null
,則會中斷表達式計算。 (相似於 &&)
可是,此方式不能用於賦值
obj?.['parent'] = 1
若是咱們相給一個值賦默認值,一般是這麼作
let obj = {} let result = obj.a || 1
如今,咱們能夠這麼作
let obj = 0 let result = obj.a ?? 1
空值合併一樣具備短路功能,當左邊不爲null時,中斷操做。(相似於 || )
注意:
控制合併不能與 &&
或 ||
連用喲。會出現問題。
?.
與??
合用
let obj = { a: 1, b: 2 }; let result = obj?.a ?? 0; console.log(result); // 1
好了,every body. 今天要分享的內容就到這裏了。我們下次再見~~