理解 JavaScript(三)

JavaScript 中的構造器

什麼是構造器?

構造器也叫構造函數,它就是一個普通的函數,只不過它的主要目的是用於和 new 操做符配合來建立特定類型的對象。(關於 new 操做符,個人理解 JavaScript(一)裏有進一步描述)javascript

舉例:java

var me = new Person('Albert', 'Yu', 32);    // Person 便是構造函數

在本例中,me 對象具備特定的類型,可稱之爲:一個 Person 對象。而 Person 就是它的類型名字。程序員

那麼構造函數內部又是如何工做的?segmentfault

function Person(firstName, lastName, age) {
    this.firstName = firstName;
    this.lastName = lastName;
    this.age = age;
};

和普通的函數相比,有兩個明顯的區別,解釋以下:瀏覽器

  1. 函數名稱首字母大寫:這其實只是一個約定而不是強制行爲,絕大多數 JavaScript 程序員都會遵照這個約定,即首字母大寫的函數名是一個構造函數;固然,首字母小寫的函數同樣能夠充當構造函數
  2. 使用 this 捆綁局部變量:通常性的函數都是直接建立本地變量來保存值,而構造函數使用 this 捆綁局部變量是爲了配合 new 操做符。由於 new 操做符會建立一個新對象,而且把新對象綁定在構造函數內部的 this 上,因而被捆綁在 this 上的局部變量事實上就成爲新對象的屬性了

所以,這樣的構造函數所建立的對象大體等價於:函數

var me = {
    firstName: 'Albert',
    lastName: 'Yu',
    age: 32
};

那麼既然如此,咱們爲啥還要寫構造函數?this

構造函數的用處

1. 用做建立對象的模板

若是隻須要建立少許對象(好比一個),編寫構造函數的確沒太大意義。可是遇到須要重複建立對象的場合,構造函數顯然是 DRY(Don't Repeat Youself)的上佳選擇。編碼

不只僅是爲了減小重複編碼的工做量,並且常常會有對於輸入參數進行驗證並拋出錯誤的功能設計,也能夠藉助構造函數來完成。prototype

2. 用做對象類型的標記

使用構造函數建立的對象能夠很方便的檢查它們的類型,好比:設計

var me = new Person('Albert', 'Yu', 32);
var you = {
    firstName: 'Super',
    lastName: 'Man',
    age: 18
};

console.log(me instanceof Person);          // true
console.log(you instanceof Person);         // false

3. 爲對象建立共享屬性

這多是使用構造函數最重要的理由了。基於原型繼承的 JavaScript 能夠很方便的爲對象擴充成員屬性:

var me = new Person('Albert', 'Yu', 32);
me.firstName;                               // "Albert"
me.lastName;                                // "Yu"
me.age;                                     // 32

// 我想要標記全部的 Person 對象都是活着的……
Person.prototype.isAlive = true;
me.isAlive;                                 // true

// 我還想要輸出用戶的全名……
me.firstName + ' ' + me.lastName;           // "Albert Yu"
// 這樣太二了吧?

Person.prototype.fullName = function() {
    return [this.firstName, this.lastName].join(' ');
};
me.fullName();                              // "Albert Yu"
// 嗯,文藝多了……

更好的構造函數

有一點特別須要注意的!

使用構造函數建立對象必定要使用 new 操做符

這是由於(再次強調):真正建立新對象的不是構造函數,而是 new 操做符。構造函數只是充當新對象的模板,它接收 new 建立的對象而後用模板填充這個對象的屬性設置。

鑑於此,忘記使用 new 的話是比較危險的。由於沒有 new 建立新對象的時候,構造函數內的 this 會被捆綁給全局對象,一般是 window(瀏覽器)或者 global(Node.js),讓咱們看看會發生啥事兒吧……

var me = new Person('Albert', 'Yu', 32);
me.firstName;                                    // "Albert"

var you = Person('Super', 'Man', 18);
you.firstName;                                   // undefined... WTF?!

this.firstName;                                  // "Super"...Shiiiit!
// 上面的 this 是全局對象

那麼如何改進構造函數呢?簡單。

function Person(firstName, lastName, age) {
    if (this instanceof Person) {                // 想想還有沒有其餘的判斷方式?
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    } else {
        throw new Error('不用 `new` 是不能夠的喲~~~');
    }
}

這個思路就是先判斷構造函數接收到的 this 是否是本身的實例,如果則一切好說,若不是則拋出錯誤強制用戶使用 new 操做符。

固然,這個改進雖然可靠了,但仍是不夠「聰明」,要是能讓構造函數本身判斷來自動使用 new 該多好呀!沒錯,這是更好地方式,不過在這裏我就不演示了,仍是由您本身來動手實踐一下吧?(提示:考慮一下構造函數的原型對象。若是想不出來的話沒關係,咱們之後接着聊)

相關文章
相關標籤/搜索