JS語言精粹--對象

這篇文章算是我職業生涯中的第一篇技術博文吧,有些地方可能表達得不是很好,還望你們多多包涵哈^_^!javascript

正文

JavaScript的簡單類型有數字、字符串、布爾值(true、false)、null值和underfind值,其餘全部的值都是對象。java

數字、字符串和布爾值「貌似」是對象,由於它們都擁有方法,可是它們是不可變的。而JavaScript中的對象是可控的鍵控集合正則表達式

在JavaScript中,數組是對象,函數是對象,正則表達式是對象,固然,對象天然也是對象。數組

對象是屬性的容器,其中每一個屬性都擁有名字和值(name-value)。屬性名能夠是包括字符串在內的任意字符串,屬性值能夠是除undefined值以外的任意值。閉包

JavaScript中的對象是無類別(class-free)的,它對新屬性的名字和值沒有約束。對象適合用於收集和管理數據。對象能夠包含其餘對象,因此它們能夠容易的表示成樹形或圖形結構。函數

JavaScript包括一個原型鏈特性(這是JS對象中很重要的一個特性,具體用法之後我會發一篇針對原型鏈及其用法的文章進行專門說明),容許對象繼承另外一個對象的屬性,正確地使用它能減小對象初始化的時間和內存耗損。ui

1. 對象字面量

對象字面量,提供了一種很是方便的建立新對象值得表示法,即包圍在一對花括號中的零個或多個「名/值」對(也稱爲鍵值對),它能夠出如今任何容許表達式出現的地方。prototype

javascriptvar empty_object = {};
var batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

屬性名能夠是包括空字符串在內的任何字符串,不過,一個合法的變量標識符,不能是保留字,雖然不強調用引號括住,可是,像「first-name」、「first name」這類含有「-」或是空格的屬性名,是必須加上引號括住的。逗號用來分隔多個「名/值」對。code

屬性值能夠從包括另外一個對象字面量在內的任意表達式中得到,而對象是可嵌套的。對象

javascriptvar flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

2. 檢索

要檢索對象中包含的值(或屬性值或方法或其它),能夠採用在 [] 後綴中括住一個字符串表達式的方式,若是字符串表達式是一個合法js標識符且不爲保留字的常數,那麼優先考慮用 . 表示法,由於它更緊湊且可讀性更好。

javascriptbatman['first-name']    // "Bruce"
flight.departure.city   // "shenzhen"

若是你嘗試檢索一個並不存在的成員元素的值(這裏的屬性表達式是嚴格區分大小寫的),將返回一個undefined值。

javascriptbatman['middle-name']   // undefined
flight.status           // undefined
batman['FIRST-NAME']    // undefined

|| 運算符能夠用來填充默認值:

javascriptvar middle = batman['middle-name'] || '(none)';
var status = flight.status || 'unknown';

嘗試檢索一個undefined值將會致使TypeError異常,這能夠經過 && 運算符來避免錯誤。

javascriptflight.equipment                             // undefined
flight.equipment.model                       // throw "TypeError"
flight.equipment && flight.equipment.model   // undefined

3. 更新

對象中的值能夠經過賦值語句來更新。

若是屬性名已經存在於對象中,那麼這個屬性值將被替換。

javascriptbatman['first-name'] = 'Damian';

若是對象以前並無這個屬性名,那麼該屬性將會被擴充到該對象中。

javascriptbatman['middle-name'] = 'AI';
batman['nickname'] = 'Robin';
flight.equipment = {
    model: 'Boeing 777'
};
flight.status = 'overdue';

4. 引用

對象經過引用來傳遞,它們永遠不會被拷貝。

javascriptvar x = batman;
x.nickname = 'Joker';
var nick = batman.nickname;  // 由於x和batman是指向同一個對象的引用,因此nick爲"Joker"
var a = {},b = {},c = {};    // a、b、c 每一個都分別引用一個不一樣的空對象
a = b = c = {};              // a、b、c 都引用一個相同的空對象

5. 原型

每一個對象都會鏈接到一個原型對象,而且它能夠從中繼承屬性。全部經過字面量建立的對象,都鏈接到 Object.prototype 這個JS中的標準的對象。

當建立一個新對象時,能夠選擇某個對象做爲它的原型,給Object增長一個beget方法,這個beget方法建立一個使用原對象做爲其原型的新對象,這個咱們之後會在專門的博文作詳細瞭解。

javascriptif(typeof Object.beget !== 'function'){
    Object.beget = function(o){
        var F = function(){};
        F.prototype = o;
        return new F();
    };
};

var next_batman = Object.beget(batman);

原型鏈接在更新時是不起做用的,當咱們對某個對象作出改變時,不會觸及到該對象的原型:

javascriptnext_batman['first-name'] = 'Damian55';
next_batman['middle-name'] = 'Ai22';
next_batman.nickname = 'Robin5';

原型鏈接只有在檢索值的時候纔會被用到。若是咱們嘗試去獲取對象的某個屬性值,且該對象沒有該屬性名,那麼,JS會試着從原型對象中獲取屬性值,若是那個原型對象也沒有該屬性,則再從它的原型中尋找,以此類推,直到最後到達終點Object.prototype,若想要的屬性徹底不存在於原型鏈中,則返回undefined值,這個過程稱爲委託

原型關係是一種動態的關係,若是咱們在原型中添加一個新的屬性,該屬性會當即對全部基於該原型建立的對象可見。

javascriptbatman.profession = 'JSL';
next_batman.profession;      // 'JSL'

6. 反射

檢查對象並確認對象有什麼屬性,能夠去檢索該屬性並驗證取得的值。而肯定屬性的類型,可使用typeof操做符。

javascripttypeof flight.number        // 'number'
typeof flight.status        // 'string'
typeof flight.arrival       // 'object'
typeof flight.manifast      // 'undefined'

請務必注意原型鏈中的任何屬性也會產生一個值:

javascripttypeof flight.toString      // 'function'
typeof flight.constructor   // 'function'

有兩種方法去處理這些不須要的屬性:

  • 讓你的程序檢查並剔除函數值,通常來講,作反射的目標是數據,所以其中一些值可能會是函數。
  • 使用hasOwnProperty方法,若是對象擁有獨立屬性,它將返回true。

另外,hasOwnProperty方法不會檢查原型鏈。

javascriptflight.hasOwnProperty('number');        // true
flight.hasOwnProperty('constructor');   // false

7. 枚舉

for in 語句可用來遍歷一個對象中的全部屬性名,固然,也包括函數和咱們可能不關心的原型中的屬性,因此咱們有必要過濾掉沒必要要的值。
最經常使用的過濾器(即過濾原型中的屬性)是hasOwnProperty方法,以及使用typeof來排除函數:

javascriptvar name;
for(name in next_batman){
    if(typeof next_batman[name] !== 'function'){
        document.writeln(name + ': ' + next_batman[name]);
    }
}

以上,屬性名出現的順序是不肯定的,所以要想確保屬性以特定的順序出現,最好是徹底避免使用 for in 語句,而是建立一個數組,在其中以正確的順序包含屬性名:

javascriptvar i;
var properties = ['first-name','middle-name','last-name','profession'];
for(i = 0;i < properties.length;i ++){
    document.writeln(properties[i] + ': ' + next_batman[properties[i]]);
}

經過使用普通for而不是for in ,能夠獲得咱們想要的屬性,而不用擔憂可能發掘出原型鏈中的屬性,並按正確的順序取得它們的值。

8. 刪除

delete運算符能夠用來刪除對象的屬性,它將會移除該對象的肯定包含的屬性,它不會觸及原型鏈中的任何對象。

刪除對象的屬性可能會讓來自原型鏈中的屬性浮現出來。

javascriptnext_batman.nickname        // 'Robin5'
// 刪除next_batman的nickname屬性,從而暴露出原型的nickname的屬性值
delete next_batman.nickname; 
next_batman.nickname;       // 'Robin'

9. 減小全局變量污染

JS能夠隨意定義可保存全部應用資源的全局變量,不幸的是,全局變量會削弱程序的靈活性,因此應該避免。

最小化使用全局變量的一個方法是在你的應用中只建立惟一一個全局變量:

javascriptvar MyApp = {};

該變量此時變成了你的應用容器:

javascriptMyApp.batman = {
    'first-name': 'Bruce',
    'last-name': 'Wayne'
};

MyApp.flight = {
    airline: 'Domestic',
    number: 1024,
    departure: {
        IATA: 'SZ',
        time: '2015-08-03 15:00:00',
        city: 'shenzhen'
    },
    arrival: {
        IATA: 'BJ',
        time: '2015-08-04 00:00:00',
        city: 'beijing'
    }
};

只要把多個全局變量都整理在同一個命名空間下,你將顯著下降與其餘應用程序、組件或類庫之間產生糟糕的相互影響(即耦合度高)的可能性,也使其變得更容易閱讀,由於MyApp.batman指向的時頂層結構。固然,也可使用閉包來進行信息隱藏,它是另外一種有效減小全局污染的方法。

相關文章
相關標籤/搜索