var person={ name:'小王', age:18, _pri:233 }
es5普通模式下後定義的會覆蓋前面定義的,嚴格模式則會報錯javascript
es6則無論什麼模式都採用後面的覆蓋前面的java
es5只能在對象字面量表達式申明之後再添加jquery
var dynamicVar="dyna"; var person={ } person[dynamicVar]='123'; console.log(person[dynamicVar])
es6則更符合使用場景,可在表達式內建立動態的成員名es6
var dynamicVar="dyna"; var person={ [dynamicVar]:'test' } console.log(person[dynamicVar])
es6中若是想使用表達式外面的變量名做爲成員名,變量的值做爲成員值,可進一步簡寫爲設計模式
var dynamicVar="dyna"; var person={ dynamicVar, //這是一個語法糖,js引擎會解釋爲dynamicVar:'dyna' age:15 } console.log(person.dynamicVar)
注意:此時不能採用person[dynamicVar]方式訪問,由於這句話js引擎會解釋爲person['dyna'],對象中沒有dyna屬性,確定就是undefined了數組
確定是不能夠,new關鍵字後面必須是一個構造函數才行,對象字面量哪來的構造函數瀏覽器
對象屬性描述符有兩種主要形式:函數
數據描述符和存取描述符。數據描述符是一個具備值的屬性,該值多是可寫的,也可能不是可寫的。this
存取描述符是由getter-setter函數對描述的屬性。es5
Object.getOwnPropertyDescriptor()或getOwnPropertyDescriptor()-讀取屬性的描述
Object.definePropertype或Object.defineProperties----設置屬性的描述
當屬性是採用Object.definePropertype建立時,省略的描述符會擁有默認值,布爾值的字段的默認值都是false
。value
,get
和set
字段的默認值爲undefined
。
var parent={} Object.defineProperty(parent,'name',{}) console.log(Object.getOwnPropertyDescriptor(parent,'name')) //{value: undefined, writable: false, enumerable: false, configurable: false}
當屬性是直接是直接在對象中建立時,布爾值的字段默認都是true
var parent={ name:'parent' } console.log(Object.getOwnPropertyDescriptor(parent,'name')) //{value: "parent", writable: true, enumerable: true, configurable: true}
數據描述符:
configurable-是否能夠刪除某個屬性或修改屬性的描述,爲true時可進行操做,若是該屬性先定義爲false,後續又定義爲true的話會報錯
Object.defineProperty(person,'name',{ configurable:false }) Object.defineProperty(person,'name',{ configurable:true })
Object.defineProperty(person,'name',{ writable:false }) person.name='小李'; //屬性不可寫,嚴格模式下會報錯 console.log(person.name); //輸出小王,說明上面一句無效
enumerable-屬性是否可被枚舉,默認爲false,該屬性主要是用來防範Object.keys()和for in的,也就是說該屬性設置對於Object.getOwnPropertyNames()方法是無效的。
使用相應的枚舉方法,輸出的結果是一個數組,那麼數組中元素的順序是按什麼規則組織的呢?
在es5中並無明確這一點,各個瀏覽器有本身的實現,es6中採用Object.keys()和for in方法時仍是沒有明確,但採用Object.getOwnPropertyNames()方法枚舉時,有了相應的標準:
最早放入數組中的是數值型的成員名,按升序排列;
其次是其它類型的,按添加的前後順序排列
var obj={ 3:'我是1', 1:'我是1', b:'我是b', a:'我是a' } var names=Object.getOwnPropertyNames(obj); console.log(names) //["1","3","b","a"]
value
-
該屬性對應的值。能夠是任何有效的 JavaScript 值(數值,對象,函數等)。默認爲 undefined
。
存取描述符:
get與set-讀寫成員時調用的函數,默認爲undefined,若是隻有get則表示屬性值是隻讀的,只有set表示只能寫。屬性讀寫器最經常使用的場景就是在讀取或寫入屬性前能夠附帶的作一些操做,達到更好的封裝性。
Object.defineProperty(person,'pri',{ get:function(){ //作一些其它操做 console.log('準備獲取_pri的值') return _pri; }, set:function(newValue){ _pri =newValue } }) person.pri='456'; console.log(person.pri);
Object.preventExtensions(),該方法用於阻止向對象添加成員,使用Object.isExtensible()判斷對象是否可添加成員
Object.preventExtensions(person); //添加成員無效,非嚴格模式下什麼都不會發生,嚴格模式下會報錯 person.bankAccount='中國農業銀行' //依然能夠刪除成員,證實了preventExtensions方法只能阻止添加方法 delete person.age; console.log(person.age) //undefined,代表刪除成功了
Object.seal()用來阻止添加或刪除成員,判斷對象是不是密封的可採用Object.isSealed()
使用Object.freeze()方法後,除了不能添加刪除成員,連成員的賦值都會失效,可是寫入屬性(上面set定義的)依然是有效
方法 | 禁止增長屬性 | 禁止刪除屬性 | 禁止修改屬性 |
---|---|---|---|
Object.preventExtensions() | 是 | 否 | 否 |
Object.seal() | 是 | 是 | 否 |
Object.freeze() | 是 | 是 | 是 |
Object.create(person)可產生一個具備繼承特性的新對象,可是須要注意的是,父對象的引用類型成員是和子對象共享的,當子對象修改引用類型的成員時,父對象的該成員也會同步發生變化
var person={ name:'小王', age:18, _pri:233, gf:['豆得兒','張G','TFb'] } var child=Object.create(person); child.gf.splice(0,1); //跟豆得兒分手了 console.log(person.gf.length) //父類的gf也變成2了,父子共享女朋友,尼瑪,太亂了
es6中的Object.setPrototypeOf(obj, prototype)方法可將已有的對象變成繼承關係,其內部原理也跟Object.create同樣,都是將子對象的prototype指向父對象,該方法實現的繼承依然有父子對象共享了引用類型成員的問題
var person={ age:15 } var man={ } Object.setPrototypeOf(man,person) console.log(Object.getPrototypeOf(man)===person) //true console.log(man.age); //15
向一個子對象的屬性賦值時,假如這個屬性是從父對象繼承下而且父對象中把該屬性設置爲不可寫時,在嚴格模式下會報錯,非嚴格模式下賦值不生效
var parent={ name:'parent' } Object.defineProperty(parent,'name',{ writable:false }) var child=Object.create(parent) child.name='child' //嚴格模式下報錯,非嚴格模式下默認失敗
向一個子對象的屬性賦值時,假如這個屬性是從父對象繼承下來的而且父對象中設置了set描述符,則賦值時會觸發set,若是未定義get,則沒法獲取屬性值
'use strict' var parent={ name:'parent' } Object.defineProperty(parent,'name',{ set(val){ console.log('父元素的set被調用了') this._name = val } }) var child=Object.create(parent) child.name='child' //會觸發父對象中的set console.log(child.name) //undefined,只有父對象的name屬性描述符設置了get才能獲取到值
直接在子對象中定義一個同名的成員便可
super關鍵字是es6新增的,它是一個指針,指向當前對象的原型,也就是父對象
var person={ age:15, testMethod(){ console.log('我是父類方法') } } var man={ //重寫父類方法 testMethod(){ console.log('我是子類方法') super.testMethod(); } } Object.setPrototypeOf(man,person) man.testMethod();
須要注意的是,若是兩個對象不是繼承關係,使用super關鍵字會報錯
jquery.extend是一個典行的對象混入,所謂對象混入,就是將n個對象(爲了便於表述,直接叫作輸入對象)組合成一個新對象,新對象具備各個輸入對象的特徵,這在軟件設計模式中叫作裝飾器模式,在es6之前須要本身實現,核心代碼以下:
function mixins(target,sourceArr){ sourceArr.forEach(function(source){ Object.keys(source).forEach(function(item){ target[item] = source[item] }) }) return target } var obj1={ name:'123' } var obj2={ id:100 } var obj3={ meth(){ console.log('haha') } } var target=mixins(obj1,[obj2,obj3]) target.meth()
上面的代碼實現了一個簡易版的jquery.extend的淺拷貝模式(也就是deep參數爲false時的功能),若是多個對象成員同名,則後面的會覆蓋前面的,該代碼若是要在正式環境使用,還須要加很多的判斷代碼,可是在es6中一句話就能夠實現mixins()函數的功能。
var target=Object.assign(obj1,obj2,obj3)
須要注意的一點就是輸入對象中使用了get修飾符,這時後會有一個轉換,方法名變成了新對象的屬性名,其值爲get修飾符方法中的返回值
var obj1={ name:'123' } var obj2={ id:100 } var obj3={ get getMethod(){ return '123' }, meth(){ console.log('haha') } } var target=Object.assign(obj1,obj2,obj3) console.log(target.getMethod) //target.getMethod()會報錯,緣由是發生了轉換