什麼是面向對象的javaScript(一)

什麼是面向對象的javaScript(一)

面向對象(OO)的語言有一個標志,那就是他們都有的概念,而通過類可以創建任意多個具有相同屬性和方法的對象。然而,ECMAScript中沒有類的概念,因此它的對象也與基於類的語言中的對象有所不同。 ECMAScript把對象定義為:

無序屬性的集合,其屬性可以包含基本值、對象、函數。

每個對象都是基於一個引用類型創建的,這個引用類型可以是原生類型,也可以是開發人員自定義的類型。

一、理解對象

創建自定義對象的最簡單方式就是創建一個Object的實例,然後再為它添加屬性和方法,如下所示。

var person  = new Object();
person.name = "sheldon";
person.age = 15;

person.sayHello = function(){
    console.log(this.name)
}

值得關註的是:早期JS開發人員經常使用這種模式創建對象。幾年後,對象字面量成為創建對象的首選模式

var person = {
    name: "sheldon",
    age:15,
    sayHello:function(){
        console.log(this.name);
    }
}

這個例子的person對象與前面例子的person對象是一樣的,有相同的屬性和方法。

1、屬性類型

ECMAScript中有兩種屬性:數據屬性訪問器屬性

1.1、數據屬性

數據屬性包含一個數據值的位置:這個位置可以讀取和寫入值。數據屬性還有4個描述其行為的特性。

[[Configurable]]:表示能否通過delete刪除屬性,能否修改屬性的特性。默認值是true。

[[Enumerable]]:表示能否通過for-in循環返回屬性。默認值是true。

[[Writable]]:表示能否修改屬性的值。默認值是true。

[[Value]]:這個屬性的數據值。默認值是undefined

對於像前面例子中那樣直接在對象上定義的屬性,他們的[[Configurable]]、[[Enumerable]]、[[Writable]]特性都默認是true,而[[Value]]特性被設置為指定的值“sheldon”

要修改屬性默認的特性,必須使用ECMAScript5的Object.defineProperty()方法,使用方式如下。

var person = {};
Object.defineProperty(person,"name",{
    writable:false,
    value:"sheldon"
});

alert(person.name); // sheldon
person.name = "dog";
alert(person.name); // sheldon

上例屬性的值“sheldon”是隻讀的瞭,嚴格模式下賦值會報異常,普通模式將忽視賦值操作。

另外,可以多次調用Object.defineProperty()方法修改同一屬性,但是configurable的特性一旦設置為false之後,就不行瞭。而且一旦調用瞭Object.defineProperty()方法,[[Configurable]]、[[Enumerable]]、[[Writable]]特性就都默認是false瞭。Object.defineProperty()方法多數情況下用不上,但是理解這些概念對理解JavaScript對象非常有用。

IE8是第一個實現Object.defineProperty()方法的瀏覽器版本,然而實現存在諸多限制。建議不要在IE8中使用該方法

1.2、訪問器屬性

訪問器屬性不包含數據值,而是包含一對兒getter和setter函數。它還有4個特性

– [[Configurable]]:表示能否通過delete刪除屬性,能否修改屬性的特性,能否把屬性修改為數據屬性。默認值是true。

– [[Enumerable]]:表示能否通過for-in循環返回屬性。默認值是true。

– [[Get]]:在讀取屬性時調用的函數。默認值是undefined。

– [[Set]]:在寫入屬性時調用的函數。默認值是undefined。

訪問器屬性不能直接定義,必須使用Object.defineProperty()來定義。請看下面的例子

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

以上代碼創建一個book對象,並給它定義兩個默認的屬性:_ year和edition。_ year前面的下劃線是一種常用的記號,用於表示隻能通過對象方法訪問的屬性。而訪問器屬性year則包含一個getter函數和一個setter函數。getter函數返回_ year的值,setter函數通過計算來確定正確的版本。因此,把year屬性修改為2005會導致_year變成2005,而edition變為2。這是使用訪問器屬性的常見方式,即設置一個屬性的值會導致其他屬性發生變化。

不一定非要同時指定getter和setter。隻指定getter意味著屬性不能寫,嚴格模式報錯,非嚴格模式忽略。

支持ECMAScrpit5的這個方法的瀏覽器有IE9+(IE8隻是部分實現)和其他正常瀏覽器。

2、定義多個屬性

由於為對象定義多個屬性的可能性很大,E5又定義瞭一個Object.defineProperties()方法,例如:

var book = {};
Object.defineProperties(book,{
    _year:2004,
    edition:1,
    year:{
        get: function(){
            return this._year;
        },
        set: function(newValue){
            if(newValue > 2004){
                this._year = newValue;
                this.edition += newValue -2004;
            }
        }
    }
});

支持該方法的的瀏覽器 IE9+和其他。

3、讀取屬性的特性

E5的Object.getOwnPropertyDescriptor()方法,可以取得給定屬性的描述符。該方法有兩個參數:屬性所屬對象,要讀取描述符的屬性名稱。返回一個對象,如果是訪問器屬性,該對象有屬性configurable、enumerable、get、set;如果是數據屬性,該對象有屬性configurable、enumerable、writable、value。 舉例就略瞭,讀者自己嘗試。Js中針對任何對象都可以使用此方法,包括BOM、DOM對象。支持瀏覽器IE9+和其他。

發佈留言