構造器也叫構造函數,它就是一個普通的函數,只不過它的主要目的是用於和 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; };
和普通的函數相比,有兩個明顯的區別,解釋以下:瀏覽器
this
捆綁局部變量:通常性的函數都是直接建立本地變量來保存值,而構造函數使用 this
捆綁局部變量是爲了配合 new
操做符。由於 new
操做符會建立一個新對象,而且把新對象綁定在構造函數內部的 this
上,因而被捆綁在 this
上的局部變量事實上就成爲新對象的屬性了所以,這樣的構造函數所建立的對象大體等價於:函數
var me = { firstName: 'Albert', lastName: 'Yu', age: 32 };
那麼既然如此,咱們爲啥還要寫構造函數?this
若是隻須要建立少許對象(好比一個),編寫構造函數的確沒太大意義。可是遇到須要重複建立對象的場合,構造函數顯然是 DRY(Don't Repeat Youself)的上佳選擇。編碼
不只僅是爲了減小重複編碼的工做量,並且常常會有對於輸入參數進行驗證並拋出錯誤的功能設計,也能夠藉助構造函數來完成。prototype
使用構造函數建立的對象能夠很方便的檢查它們的類型,好比:設計
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
這多是使用構造函數最重要的理由了。基於原型繼承的 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
該多好呀!沒錯,這是更好地方式,不過在這裏我就不演示了,仍是由您本身來動手實踐一下吧?(提示:考慮一下構造函數的原型對象。若是想不出來的話沒關係,咱們之後接着聊)