核心: 將父類的實例做爲子類的原型app
缺點: 父類新增原型方法/原型屬性,子類都能訪問到,父類一變其它的都變了函數
function Person (name) { this.name = name; }; Person.prototype.getName = function () { //對原型進行擴展 return this.name; }; function Parent (age) { this.age = age; }; Parent.prototype = new Person('老明'); //這一句是關鍵 //經過構造器函數建立出一個新對象,把老對象的東西都拿過來。 Parent.prototype.getAge = function () { return this.age; }; // Parent.prototype.getName = function () { //能夠重寫從父類繼承來的方法,會優先調用本身的。 // console.log(222); // }; var result = new Parent(22); console.log(result.getName()); //老明 //調用了從Person原型中繼承來的方法(繼承到了當前對象的原型中) console.log(result.getAge()); //22 //調用了從Parent原型中擴展來的方法
基本思想
借用構造函數的基本思想就是利用call
或者apply
把父類中經過this
指定的屬性和方法複製(借用)到子類建立的實例中。
由於this
對象是在運行時基於函數的執行環境綁定的。也就是說,在全局中,this
等於window
,而當函數被做爲某個對象的方法調用時,this
等於那個對象。call
、apply
方法可將一個函數的對象上下文從初始的上下文改變爲由 thisObj 指定的新對象。性能
因此,這個借用構造函數就是,new
對象的時候(new建立的時候,this
指向建立的這個實例),建立了一個新的實例對象,
而且執行Parent
裏面的代碼,而Parent
裏面用call
調用了Person
,也就是說把this
指向改爲了指向新的實例,
因此就會把Person
裏面的this
相關屬性和方法賦值到新的實例上,而不是賦值到Person
上面,
因此全部實例中就擁有了父類定義的這些this
的屬性和方法。this
由於屬性是綁定到this
上面的,因此調用的時候才賦到相應的實例中,各個實例的值就不會互相影響了。prototype
核心:使用父類的構造函數來加強子類實例,等因而複製父類的實例屬性給子類(沒用到原型)code
缺點: 方法都在構造函數中定義, 只能繼承父類的實例屬性和方法,不能繼承原型屬性/方法,沒法實現函數複用,每一個子類都有父類實例函數的副本,影響性能對象
function Person (name) { this.name = name; this.friends = ['小李','小紅']; this.getName = function () { return this.name; } }; // Person.prototype.geSex = function () { //對原型進行擴展的方法就沒法複用了 // console.log("男"); // }; function Parent = (age) { Person.call(this,'老明'); //這一句是核心關鍵 //這樣就會在新parent對象上執行Person構造函數中定義的全部對象初始化代碼, // 結果parent的每一個實例都會具備本身的friends屬性的副本 this.age = age; }; var result = new Parent(23); console.log(result.name); //老明 console.log(result.friends); //["小李", "小紅"] console.log(result.getName()); //老明 console.log(result.age); //23 console.log(result.getSex()); //這個會報錯,調用不到父原型上面擴展的方法
組合繼承(全部的實例都能擁有本身的屬性,而且可使用相同的方法,組合繼承避免了原型鏈和借用構造函數的缺陷,結合了兩個的優勢,是最經常使用的繼承方式)繼承
核心:經過調用父類構造,繼承父類的屬性並保留傳參的優勢,而後再經過將父類實例做爲子類原型,實現函數複用原型鏈
缺點:調用了兩次父類構造函數,生成了兩份實例(子類實例將子類原型上的那份屏蔽了)get
function Person (name) { this.name = name; this.friends = ['小李','小紅']; }; Person.prototype.getName = function () { return this.name; }; function Parent (age) { Person.call(this,'老明'); //這一步很關鍵 this.age = age; }; Parent.prototype = new Person('老明'); //這一步也很關鍵 var result = new Parent(24); console.log(result.name); //老明 result.friends.push("小智"); // console.log(result.friends); //['小李','小紅','小智'] console.log(result.getName()); //老明 console.log(result.age); //24 var result1 = new Parent(25); //經過借用構造函數都有本身的屬性,經過原型享用公共的方法 console.log(result1.name); //老明 console.log(result1.friends); //['小李','小紅']
核心:經過寄生方式,砍掉父類的實例屬性,這樣,在調用兩次父類的構造的時候,就不會初始化兩次實例方法/屬性,避免的組合繼承的缺點
缺點:堪稱完美,但實現較爲複雜
function Person(name) { this.name = name; this.friends = ['小李','小紅']; } Person.prototype.getName = function () { return this.name; }; function Parent(age) { Person.call(this,"老明"); this.age = age; } (function () { var Super = function () {}; // 建立一個沒有實例方法的類 Super.prototype = Person.prototype; Parent.prototype = new Super(); //將實例做爲子類的原型 })(); var result = new Parent(23); console.log(result.name); console.log(result.friends); console.log(result.getName()); console.log(result.age);