說明:前端
此摘要筆記系列是我最近看《JavaScript高級程序設計(第3版)》隨手所記。
裏面分條列舉了一些我認爲重要的、須要記下的、對我有幫助的點,是按照我看的順序來的。
摘要筆記自己沒有系統性,沒有全面性可言,寫在這裏供有必定基礎的前端開發者參考交流。
裏面的知識點、例子大部分來源於本書,或者延伸出來的,都通過個人測試是對的,可是沒辦法保證100%正確,若是有人看到錯誤的地方,但願指出來,謝謝。函數
用這種方法若是不設置原型的 constructor 屬性,則原型的 constructor 屬性跟普通對象同樣,指向 Object,
如:測試
var Person = function () {} Person.prototype = { name: 'abc', sayHello: function () { console.log('hello') } } Person.prototype.constructor === Person // false Person.prototype.constructor === Object // true var ming = new Person() ming.constructor === Person // false ming.constructor === Object // true ming.__proto__ === Person.prototype // true ming instanceof Person // true
以後的表現跟在原生的原型對象上添加屬性同樣,
如:this
var Person = function () {} Person.prototype = { constructor: Person, name: 'abc', sayHello: function () { console.log('hello') } } Person.prototype.constructor === Person // true var ming = new Person() ming.constructor === Person // true ming.__proto__ === Person.prototype // true ming instanceof Person // true
可是,重設 constructor 屬性會致使它的 [[Enumerable]] 特性被設置成 true,變成可枚舉的。
這個問題能夠用 Object.defineProperty() 來改正。
如:prototype
var Person = function () {} Person.prototype = { name: 'abc', sayHello: function () { console.log('hello') } } Object.defineProperty(Person.prototype, 'constructor', { enumerable: false, value: Person })
若是不重設構造函數的 prototype 原型對象,那麼,咱們對原型對象的任何修改都可以反映到實例上,即便先建立實例後修改原型。設計
若是重設構造函數的 prototype 原型對象,那麼,會切斷新的原型對象和任何以前已經存在的構造函數實例之間的聯繫,它們引用的仍然是最初的原型。code
建立自定義類型的最經常使用方式,就是組合使用構造函數模式和原型模式。構造函數用於定義實例屬性,原型模式用於定義方法和共享的屬性。對象
好處:每一個實例都會有本身的實例屬性的副本,同時又共享着對方法的引用,最大限度的節省了內存。
還支持向構造函數傳遞參數。
如:繼承
function Person (name, age) { this.name = name this.age = age this.friends = ['Ming', 'Li'] } Person.prototype = { constructor: Person, sayName: function () { console.log(this.name) } } var zhang = new Person('zhang', 12) var yang = new Person('yang', 15) zhang.friends.push('wang') console.log(zhang.friends) // ['Ming', 'Li', 'wang'] console.log(yang.friends) // ['Ming', 'Li'] zhang.sayName === yang.sayName // true
如:ip
function Person (name, age) { this.name = name this.age = age if (typeof this.sayName !== 'function') { Person.prototype.sayName = function () { console.log(this.name) } } } // 注意在用這種模式時,不能使用對象字面量重寫原型。
這種模式的基本思想就是建立一個函數,該函數的做用僅僅是封裝建立對象的代碼,而後再返回新建立的對象。但從表面看,這個函數很像構造函數。
如:
function Person (name, age) { var person = { name: name, age: age, sayName: function () { console.log(this.name) } } return person } var ming = new Person('ming', 12) ming.sayName() // 'ming' ming instanceof Person // false ming instanceof Object // true ming.__proto__ === Object.prototype // true ming.constructor === Object // true
注意:這個模式除了使用new操做符並把包裝的函數叫作構造函數外,跟工廠模式是一摸同樣的。
說明:返回的對象與構造函數或者與構造函數的原型屬性沒有關係。
(由於不使用new操做符,因此函數名稱就不首字母大寫了)
穩妥構造函數模式與寄生構造函數相似,但有兩點不一樣:一是新建立的實例方法不引用this;二是不使用new操做符調用構造函數。
如:
function person (name, age) { var o = {} o.sayName = function () { console.log(name) } return o; } var ming = person('ming', 12) ming.sayName() // 'ming' ming instanceof person // false ming instanceof Object // true
注意:在這裏除了調用 sayName 方法,沒有其它辦法訪問 name 的值
說明:同寄生構造函數模式,返回的對象與構造函數或者與構造函數的原型屬性沒有關係。
關於對象原型部分結束。下一篇是繼承相關的內容