一、對象屬性類型
????1瞭郑、數(shù)據(jù)屬性:數(shù)據(jù)屬性包含一個數(shù)據(jù)值的位置可很。在這個位置可以讀取和寫入值。數(shù)據(jù)屬性有 4 個描述其行為的特性凰浮。
????????[[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性,能否修改屬性的特性苇本,或者能否把屬性修改為訪問器屬性袜茧。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認(rèn)值為 true瓣窄。
????????[[Enumerable]]:表示能否通過 for-in 循環(huán)返回屬性笛厦。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認(rèn)值為 true俺夕。
????????[[Writable]]:表示能否修改屬性的值裳凸。像前面例子中那樣直接在對象上定義的屬性,它們的這個特性默認(rèn)值為 true劝贸。
????????[[Value]]:包含這個屬性的數(shù)據(jù)值姨谷。讀取屬性值的時候,從這個位置讀;寫入屬性值的時候映九,把新值保存在這個位置梦湘。這個特性的默認(rèn)值為 undefined。
? ? ?????要修改屬性默認(rèn)的特性件甥,必須使用 ECMAScript 5 的 Object.defineProperty()方法捌议。這個方法 接收三個參數(shù):屬性所在的對象、屬性的名字和一個描述符對象引有。其中瓣颅,描述符(descriptor)對象的屬 性必須是:configurable、enumerable譬正、writable 和 value宫补。設(shè)置其中的一或多個值檬姥,可以修改 對應(yīng)的特性值。
????????一旦把屬性定義為不可配置的(configurable:false)守谓, 就不能再把它變回可配置了穿铆。此時,再調(diào)用 Object.defineProperty()方法修改除 writable 之外 的特性斋荞,
????????var a = 0,? window.a的configurable默認(rèn)為false荞雏;
????????window.a = 0, window.a的configurable默認(rèn)為true;
????2. 訪問器屬性
????????[[Configurable]]:表示能否通過 delete 刪除屬性從而重新定義屬性平酿,能否修改屬性的特 性凤优,或者能否把屬性修改為數(shù)據(jù)屬性。對于直接在對象上定義的屬性蜈彼,這個特性的默認(rèn)值為 true筑辨。
????????[[Enumerable]]:表示能否通過 for-in 循環(huán)返回屬性。對于直接在對象上定義的屬性幸逆,這 5 個特性的默認(rèn)值為 true棍辕。
?????????[[Get]]:在讀取屬性時調(diào)用的函數(shù)。默認(rèn)值為 undefined还绘。
?????????[[Set]]:在寫入屬性時調(diào)用的函數(shù)楚昭。默認(rèn)值為 undefined。
????????var book = {
????????????? _year: 2004,
????????????edition: 1
????????};
????????Object.defineProperty(book, "year", {
? ? ????????????get: function(){
? ? ? ?????????????return this._year;
? ????? ????????},
? ? ????????????set: function(newValue){????
? ? ? ? ????????????if (newValue > 2004) {
? ? ? ? ? ????? ????this._year = newValue;
? ? ? ? ? ????? ????this.edition += newValue - 2004;
? ????????????? } }
????????});
????????book.year = 2005; alert(book.edition); //2
????????支持 ECMAScript 5 的這個方法的瀏覽器有 IE9+(IE8 只是部分實現(xiàn))拍顷、Firefox 4+抚太、Safari 5+、Opera 12+和 Chrome昔案。在這個方法之前尿贫,要創(chuàng)建訪問器屬性,一般都使用兩個非標(biāo)準(zhǔn)的方法: __defineGetter__()和__defineSetter__()踏揣。這兩個方法最初是由 Firefox 引入的庆亡,后來 Safari 3、 Chrome 1 和 Opera 9.5 也給出了相同的實現(xiàn)呼伸。使用這兩個遺留的方法身冀,可以像下面這樣重寫前面的例子。
????????var book = {
? ????????? _year: 2004,
????????????edition: 1
? ? ? ? };????????
????????//定義訪問器的舊有方法?
????????book.__defineGetter__("year", function(){
? ? ????????return this._year;
????????});
????????book.__defineSetter__("year", function(newValue){
? ????????? if (newValue > 2004) {
? ? ? ????????? this._year = newValue;
? ? ? ????????? this.edition += newValue - 2004;
? ????????? }
????????});
????????book.year = 2005; alert(book.edition); //2
????????在 不 支 持 Object.defineProperty() 方 法 的 瀏 覽 器 中 不 能 修 改 [[Configurable]] 和 [[Enumerable]]括享。
????3搂根、讀取屬性的特性
????????ECMAScript 5 的 Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述 符铃辖。這個方法接收兩個參數(shù):屬性所在的對象和要讀取其描述符的屬性名稱剩愧。返回值是一個對象,如果 是訪問器屬性娇斩,這個對象的屬性有 configurable仁卷、enumerable穴翩、get 和 set;如果是數(shù)據(jù)屬性,這 個對象的屬性有 configurable锦积、enumerable芒帕、writable 和 value。
二丰介、創(chuàng)建對象
????關(guān)于創(chuàng)建對象的幾種模式我就不多贅述了背蟆,總體的思想是將公共方法和屬性放在構(gòu)造函數(shù)的原型中,在這我主要列出ES6及ES6之前的寫法哮幢。
????ES6之前:
????????function Person (name) {
????????????this.name = name
????????}
????????Person.prototype.sayHi = function(){
????????????return? 'sayHi';
????????}
????????var person = new Person('Tom')
????????console.log(person.name)? // Tom
????????console.log(person.sayHi()) // sayHi
????ES6:? class Person {
????????????????????constructor(name){
????????????????????????this.name = name;
????????????????????}
????????????????????sayHi(){
????????????????????????return? 'sayHi';
????????????????????}
? ? ? ? ? ? ? ?}
????????????? let person = new Person('Tom')
????????????? console.log(person.name)? // Tom
????????????? console.log(person.sayHi()) // sayHi
三带膀、繼承
????實現(xiàn)繼承最好的就是寄生組合繼承方法了,ES6的extends也是基于此來實現(xiàn)繼承的橙垢;以下是2種寫法:
????ES6之前:
????????function SuperType (name) {
????????????this.name = name
????????}
????????SuperType.prototype.sayHi = function(){
????????????return? this.name +? 'sayHi';
????????}
????????function SubType (name,age) {
????????????SuperType.call(this,name);
????????????this.age = age
????????}
????????function inheritPrototype(subType, superType){
? ? ????????var prototype = Object.create(superType.prototype);? // ES5 支持 Object.create()
? ???????? prototype.constructor = subType;
? ???????? subType.prototype = prototype;
????????}
????????inheritPrototype(SubType,SuperType);
????????var subType = new SubType('Tom')
????????console.log(subType.name)? // Tom
????????console.log(subType.sayHi()) // TomsayHi
????ES6:? class SuperType {
????????????????constructor(name){
????????????????????this.name = name;
????????????????}
????????????????sayHi(){
????????????????????return? `${this.name}sayHi`;
????????????????}
? ????????? }
? ???????? class SubType? extends SuperType {
????????????????constructor(name,age){
????????????????????super(name)?
????????????????????this.age = age;
????????????????}
? ????????? }
????????? let subType = new SubType('Tom')
? ???????? console.log(subType.name)? // Tom
? ???????? console.log(subType.sayHi()) // TomsayHi
? ? ? ?子類必須在constructor方法中調(diào)用super方法垛叨,否則新建實例時會報錯。如果子類在constructor方法中使用了this初始化實例屬性,調(diào)用super方法必須放到this初始化實例屬性的前面柜某。這是因為子類沒有自己的this對象嗽元,而是繼承父類的this對象,然后對其進(jìn)行加工喂击。如果不調(diào)用super方法还棱,子類就得不到this對象。