理解 JavaScript(一)

JavaScript 中的 new

首先,new 是一個操做符,它能夠用來建立兩種對象的實例,一種是用戶定義的對象類型,另外一種則是擁有構造函數的內建對象類型。javascript

建立用戶定義的對象須要兩個步驟:java

  1. 經過編寫函數來定義對象類型;
  2. 使用 new 來建立對象實例。

示例一:函數

var Person = function(personName) {
    this.name = personName;
};

這是一個典型的經過編寫函數來定義對象類型的範例,咱們能夠這樣來表述其行爲:this

Person 函數定義了一種對象類型,其 類型名稱 就叫 Person
在使用 Person 函數建立對象實例的時候能夠傳入變量 personName,該變量會成爲對象實例的一個屬性,這個屬性的名字叫 name
爲對象實例定義 name 屬性的過程發生在 Person 函數的函數體內;this 即指代將被建立的對象實例。prototype

值得初學者注意的是,在現實中你更多地會看到這樣的代碼:翻譯

var Person = function(name) {
    this.name = name;
};

有些人會搞不清楚究竟哪個 name 纔是對象的屬性,在這裏詳細解釋以下:code

  1. function(name) 裏的 name待傳入參數的名字,一般被稱做:形式參數(Formal Parameter),或簡稱 形參 ——由於它只是表明參數的形式而並不是真正傳入的參數(後者則被稱做:實際參數(Actual Parameter),或簡稱 實參)。
  2. this.namename 是對象的屬性名字。
  3. = namename 仍是形參,和 1. 裏的 name 等價;這就是所謂的 參數傳遞,或傳參

示例二:orm

var albert = new Person('Albert');
albert.name;       // "Albert"
albert['name'];    // "Albert"

這是承接示例一,使用定義好的 Person 對象類型來實例化對象的範例,這個範例的表述相對容易一些:對象

定義一個變量 albert,而後實例化一個新的 Person 類型的對象,並將變量 albert 指向這個新的對象。繼承

若是你對 形參實參 還不夠清楚的話,看到這裏就應該徹底明瞭了。保險起見再加以解釋以下:

  1. 在示例二中,new Person('Albert') 中的 'Albert' 即對應着示例一中 function(name) 中的 name,同時也是接下來一行中等號右邊的 name
  2. 所以,'Albert' 就是 實際參數name 就是 形式參數

示例二中還演示了兩種對象屬性的獲取方法,分別爲 object.propertyobject['property']。前一種比較經常使用,不事後一種因爲能夠用字符串來訪問對象屬性,所以在某些場合下很是有用(好比說用字符串傳遞了對象的屬性)。


回到 new 的話題。

new Person('Albert') 執行的時候,會有以下事情發生:

  1. 建立一個新的對象,其類型是 Person 並繼承 Person.prototype 的全部屬性。這就是 原型繼承
  2. 構造函數 Person 被調用並傳入指定的參數(示例二中的 'Albert'),而後 this 被綁定給新建立的對象。另外,若構造函數不須要參數,則 new Person 等價於 new Person()
  3. 若構造函數沒有明確的返回值,那麼新建立的對象就是整個 new 表達式的結果;反之,若構造函數內顯式定義了返回值,則該返回值爲整個 new 表達式的結果。

關於第三點,舉例示之:

示例三:

var Person = function(name) {
    return {
        name: 'Mr. ' + name
    }
};

var albert = new Person('Albert');

albert.name;        // "Mr. Albert"
var Person = function(name) {
    return {
        rawName: name,
        getName: function(gender) {
            if (gender === 'male') {
                return 'Mr. ' + name;
            } else {
                return 'Mrs. ' + name;
            }
        }
    }
};

var albert = new Person('Albert');

albert.getName('male');        // "Mr. Albert"
albert.getName('female');      // "Mrs. Albert"
var Person = function(name, gender) {
    return {
        rawName: name,
        name: (function() {
            if (gender === 'male') {
                return 'Mr. ' + name;
            } else {
                return 'Mrs. ' + name;
            }
        }())
    }
};

var albert = new Person('Albert', 'male');
albert.rawName;             // "Albert"
albert.name;                // "Mr. Albert"

var annie = new Person('Annie', 'female');
annie.rawName;              // "Annie"
annie.name;                 // "Mrs. Annie"

示例三演示了三種看起來類似但實際上具備顯著差別的對象類型定義和對象實例化的例子:

  • 第一種:在 new Person('Albert') 時返回自定義的對象,而不是默認由 new 建立的新對象。在這個自定義對象裏,沒有簡單地把參數 name 賦給屬性 this.name,而是作了進一步的修改。這種修改很顯然是很是簡單但卻不夠靈活,爲了改進它,看下面兩個例子:

  • 第二種:一樣返回自定義對象,這一次定義了兩個屬性,一個是 rawName,保存實例化時傳遞的參數;另外一個是 getName,它是一個函數聲明,所以不能直接用 albert.getNamealbert['getName'] 來訪問(只會返回函數聲明自己,但不會有返回值)。不過你能夠用albert.getNam('male')albert['getName']('male') 的方式來執行這個函數並求得結果,這就是所謂的 方法
    若是不想用方法調用,但仍然但願像方法聲明體內那樣作一些邏輯判斷是否能夠呢?能夠,繼續看第三種:

  • 第三種:這一次 name 屬性又能夠像之前那樣直接訪問了,緣由是 name 指向的函數聲明使用了 IIFE(Immediately Invoked Function Expression) 技巧,該技巧使得函數聲明直接轉變成了函數表達式(並即刻執行)。咱們知道,函數表達式是可以直接返回值的,而函數聲明則須要執行(調用)才能返回值,因而 name 屬性得到了返回值,就能夠像原來那樣直接訪問了。
    這種屬性定義方式有時被稱之爲 計算後屬性(Computed Property),顧名思義:不是直接返回實例化時傳遞的值,而是對值進行了必定的處理(計算)以後才返回。


屬性與方法:不少人都覺得對象有 屬性方法,其中屬性是能夠直接訪問到值的,而方法是須要執行才能得到值的。但有的時候也會聽到「方法也是屬性」這樣的說法,這是爲何呢?
其實緣由在於對術語的翻譯不夠準確。英文裏的 propertyattribute 都被咱們翻譯爲屬性,然而在談及對象時這二者是不一樣的。在一個對象裏,attributemethod 被統稱爲 property,直接保存值的 property 稱之爲 attribute,保存函數聲明能夠用來執行的 property 纔是 method。在用中文描述時很容易把兩種「屬性」搞混,須要注意分辨清楚。

補充說明:本文發表出去以後,有人感謝我幫他分清了 屬性方法 在一些書中的歧義性,也有人拿着別的書來向我表示疑惑。以再版的 Object Oriented in JavaScript 爲例,該書中在講解面向對象基礎的時候,明確地指出:保存數據的屬性叫作 Property,保存行爲的屬性叫作 Method,根本就不使用 Attribute。這卻是也簡單明瞭,這樣一來就不存在 Method 也是 Property 一說了。

老實說,對此我也不知該如何迴應。不一樣的書用不一樣的術語,不一樣的做者也有不一樣的理解,我沒有「統一業界術語」的能量,因此也只能把它們一一列舉出來。對於初學者若形成理解上的誤差我表示道歉,總而言之你要記住:一個對象有兩類東西:一類記錄數據,另外一類記錄方法(方法老是作一件什麼事,其中也包括返回新的數據),至於這兩類在不一樣的情境中叫法不一,也就要靠你本身去分辨了。

相關文章
相關標籤/搜索