類式繼承
場景: 我們需要目前有一個(gè)超類Person,現(xiàn)在需要一個(gè)Author類來繼承超類的所有方法及屬性,并且擁有自己的方法和屬性
// Person 超類
function Person(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
- 原型鏈
// 繼承超類的類 Author
function Author(name, books) {
// 在使用new運(yùn)算符時(shí),系統(tǒng)會(huì)先創(chuàng)建一個(gè)空對(duì)象,然后調(diào)用構(gòu)造函數(shù),此過程中空對(duì)象處于作用域鏈最前端
// 這里我們調(diào)用超類的構(gòu)造函數(shù),就需要手懂模擬這個(gè)過程。此時(shí)this代表空對(duì)象,name為參數(shù)
Person.call(this, name);
this.books = books;
}
Author.prototype = new Person(); // 使Author的原型指向Person的實(shí)例 此時(shí)原型的構(gòu)造函數(shù)(constructor)被重置
Author.prototype.constructor = Author; // 重定向Author原型的構(gòu)造函數(shù) 不定義的話此構(gòu)造函數(shù)為空,那么將會(huì)向上查找,指向Person
Author.prototype.getBooks = function () {
return this.books;
}
var author = [];
author[0] = new Author('Dustin Diaz', ['JavaScript Design Patterns']);
author[1] = new Author('Ross Harmes', ['JavaScript Design Patterns']);
console.log(author[1].getName()) // Ross Harmes
console.log(author[1].getBooks()) // ['JavaScript Design Patterns']
- extend函數(shù)
// extend函數(shù)
function extend(subClass, superClass) {
var F = function () {}; // 先創(chuàng)造一個(gè)空對(duì)象
F.prototype = superClass.prototype; // 使空對(duì)象的原型指向超類的原型
subClass.prototype = new F(); // 使當(dāng)前類的原型指向F的實(shí)例
subClass.prototype.constructor = subClass; // 重定向當(dāng)前類的原型的構(gòu)造函數(shù)
// superclass 用于直接訪問超類的方法
// 使用場景 在既想重定義超類的方法而又想訪問其在超類中的實(shí)現(xiàn)時(shí) 栗子在下面
subClass.superclass = superClass.prototype;
// 判斷構(gòu)造器指向
if (superClass.prototype.constructor == Object.prototype.constructor) {
superClass.prototype.constructor = superClass
}
}
// Author 類
function Author(name, books) {
Author.superclass.constructor.call(this, name)
this.books = books
}
extend(Author, Person)
var xhui = new Author('xhui', ['123'])
console.log(xhui.getName()) //xhui
// 利于supercalss來重定義超類的getName方法
Author.prototype.getName = function () {
var name = Author.superclass.getName.call(this)
return `${name}123123`
}
console.log(xhui.getName()) //xhui123123
原型式繼承
// clone 函數(shù)
function clone(object) {
function F(params) {};
F.prototype = object;
return new F();
}
// Person 超類
var Person = {
name: 'default name',
getName: function () {
return this.name
}
}
var Author = clone(Person);
Author.books = [];
Author.getBooks = function () {
return this.books;
}
var author;
author = clone(Author);
console.log(author.getName()) //default name
author.name = 'xhui';
author.books = ['js設(shè)計(jì)模式']
console.log(author.getName()) // 'xhui'
console.log(author.getBooks()) // ['js設(shè)計(jì)模式']
繼承而來的成員的讀和寫具有不對(duì)等性。 在類式繼承中,Author的每一份實(shí)例都有自己的books數(shù)據(jù)副本。但是在原型式繼承中大不相同, 一個(gè)克隆并非其原型對(duì)象的一份獨(dú)完全立的副本,它只是一個(gè)以那個(gè)對(duì)象為原型對(duì)象的空對(duì)象。
克隆剛被創(chuàng)建時(shí),author.name其實(shí)是一個(gè)反指最初的Person.name的鏈接。對(duì)于從原型對(duì)象繼承而來的成員,其讀和寫具有內(nèi)在的不對(duì)等性。在你讀取author.name時(shí),如果你沒有為其賦值,那么得到的是其原型對(duì)象的同名屬性值。而你在為author.name賦值時(shí),其實(shí)是在為author定義一個(gè)新屬性。
摻元類
我們平時(shí)總會(huì)定義一個(gè)包含各種通用方法的類,然后用它來擴(kuò)充其他類。這種包含各種通用方法的類就是摻元類。
// argument 輔助函數(shù)
function argument(receivingClass, givingClass) {
if (arguments[2]) {
// 如果有第三個(gè)參數(shù) 則為擴(kuò)充類擴(kuò)充名為第三個(gè)參數(shù)的方法
for (var i = 2; i < arguments.length; i++) {
receivingClass.prototype[arguments[i]] = givingClass.prototype[arguments[i]]
}
} else {
// 如果只有兩個(gè)參數(shù) 為擴(kuò)充類擴(kuò)充摻元類所有的方法
for (methodName in givingClass.prototype) {
if (!receivingClass.prototype[methodName]) {
receivingClass.prototype[methodName] = givingClass.prototype[methodName]
}
}
}
}
// 摻元類
var Mixin = function () {};
Mixin.prototype = {
serialize: function () {
var output = [];
for (key in this) {
output.push(`key:${this[key]}`)
}
return output
}
}
function Author(name, books) {
this.name = name;
this.books = books;
}
argument(Author, Mixin) // argument(Author, Mixin, 'serialize')
var author = new Author('xhui', ['js設(shè)計(jì)模式']);
console.log(author.serialize())
結(jié)果為

1544515452.jpg
舉個(gè)栗子
書上栗子有點(diǎn)長懶得寫了。。。