javascript
java
原型模式架構
function Person (name, age) { this.name = name; this.age = age; } Person.prototype.sayName = function () { return this.name; } Person.prototype.sayAge = function () { return this.age; } function Student (name, age, school) { this.name = name; this.age = age; this.school = school; } Student.prototype = new Person(); Student.prototype.saySchool = function () { return this.school; } let stu = new Student('zhang', 18, 'zust'); console.log(stu.getName()); // 'zhang'
以上的繼承方式是比較好理解的,當訪問Student實例的sayName()方法時,先遍歷實例方法(無匹配),再搜索函數
原型對象Person實例(無匹配), 最後搜索Person.prototype對象上,獲得sayName()方法。優化
借用構造函數this
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.sayName = function () { return this.name; } Person.prototype.sayAge = function () { return this.age; } function Student(name, age, school){ Person.call(this, name, age); this.school = school; }
所謂的借用構造函數是借用父類的構造函數來設置本身的屬性,進一步避免了代碼的重複。spa
以上是單純使用了借用構造函數實現的繼承,能夠看到在子類中經過重用父類的構造方法爲子類設置屬性,可是僅僅使用借用構造函數,子類將沒法繼承父類構造函數原型中的方法。prototype
組合式繼承(原型模式與借用構造函數的組合)設計
function Person(name, age){ this.name = name; this.age = age; } Person.prototype.sayName = function () { return this.name; } Person.prototype.sayAge = function () { return this.age; } function Student(name, age, school) { Person.call(this, name, age); this.school = school; } Student.prototype = new Person();
以上的繼承方式是原型模式和借用構造函數模式的組合方式,經過原型鏈的方式繼承父類構造函數原型對象上的方法,使用借用構造函數重用父類構造函數中的代碼。至關因而對於原型鏈繼承模式的優化,將父類構造函數中的代碼加以重用。對象
原型式繼承
let sup = {name: 'zhang', age: 18}; let extend = function (obj) { function F () {}; F.prototype = obj; return new F(); } let sub = extend(sup); console.log(sub.name);
就以上的繼承方式而言,我的感受與如下實現方式並無太大區別
let sup = {name: 'zhang', age: 18}; let sub = {}; Object.setPrototypeOf(sub, sup); console.log(sub.name);
在子類對象建立的過程當中,全部的父類變量將會被子類共享,尤爲是引用類型的變量
const sup = {name: 'zhang', age: 18, arr: ['a', 'b', 'c']} const extend = function (obj) { function F(){}; F.prototype = obj; return new F(); } const a = extend(sup); const b = extend(sup); console.log(a.arr); // ['a', 'b', 'c'] b.arr.push('d'); console.log(a.arr); // ['a', 'b', 'c', 'd']
在原型上定義了一個引用類型的屬性arr,而後經過繼承建立兩個對象,經過對象b訪問arr屬性時,因爲對象b上並無arr屬性,所以,會訪問b的原型對象,也就是sup對象中的arr屬性,這是全部子類對象共享父類對象中的屬性的實質。
ES5中經過Object.create()方法實現原型式繼承的標準API
寄生式繼承
function createPerson (obj) { var clone = Object.create(obj); clone.getName = function () { return this.name; } return clone; } var person = {name: 'zhang', age: 18}; var p = createPerson(person); console.log(person.name); // 'zhang'
寄生式繼承是將原型式繼承以及增長實例方法這兩個步驟封裝成一個工廠函數,而後將生成的對象返回
代碼仍是比較簡單的,可是具體是幹嗎用的,emmmmmm...因此,再也不贅述
寄生組合式繼承
function Person (name, age) { this.name = name; this.age = age; } Person.prototype.getName = function () { return this.name; } Person.prototype.getAge = function () { return this.age; } function Student (name, age, school) { Person.call(name, age); this.school = school; } Student.prototype = Object.create(Person.prototype); Student.prototype.getSchool = function () { return this.school; }