[深刻01] 執行上下文
[深刻02] 原型鏈
[深刻03] 繼承
[深刻04] 事件循環
[深刻05] 柯里化 偏函數 函數記憶
[深刻06] 隱式轉換 和 運算符
[深刻07] 瀏覽器緩存機制(http緩存機制)
[深刻08] 前端安全
[深刻09] 深淺拷貝
[深刻10] Debounce Throttle
[深刻11] 前端路由
[深刻12] 前端模塊化
[深刻13] 觀察者模式 發佈訂閱模式 雙向數據綁定
[深刻14] canvas
[深刻15] webSocket
[深刻16] webpack
[深刻17] http 和 https
[深刻18] CSS-interview
[react] Hooks前端
[部署01] Nginx
[部署02] Docker 部署vue項目
[部署03] gitlab-CIvue
[源碼-webpack01-前置知識] AST抽象語法樹
[源碼-webpack02-前置知識] Tapable
[源碼-webpack03] 手寫webpack - compiler簡單編譯流程react
Sub.prototype = new Super('woow_wu7')以後Sub.prototype.sex = 'man',否則會被新的引用代替
原型鏈繼承
- 原理:將子類的prototype指向父類的實例,同時要修改子類的constructor屬性讓其從新指向子類
- 由於修改了子類prototype指向父類實例後,子類的prototype.constructor就指向了父類(修改改回來,防止引用出錯)
- 缺點:
1. 生成子類實例時,不能向父類傳參
2. 不能實現多繼承
3. 屬性共享,修改子類實例上的原型鏈上的引用類型的屬性時,子類實例會相互影響
4. 在子類的prototype上掛屬性和方法時,須要在子類的prototype指向父類的實例以後
代碼示例:
// 父類
function Super(name) {
this.name = name
}
Super.prototype.age = 20
// 子類
function Sub(address) {
this.address = address
}
Sub.prototype = new Super('woow_wu7') // 原型鏈繼承:將子類的prototype指向父類的實例,子類實例就能訪問父類實例和父類實例原型鏈上的屬性和方法,缺點:不能實現多繼承
Sub.prototype.constructor = Sub // 記得在修改prototype後,須要修改constructor指向,防止引用出錯
Sub.prototype.sex = 'man' // 缺點:掛載屬性必須在上面步驟滯後
const sub = new Sub('hangzhou') // 缺點:只能向子類傳參,不能向父類傳參
console.log(sub.address, '子類實例自身屬性')
console.log(sub.sex, '子類實例原型上的屬性')
console.log(sub.name, '子類實例原型上的屬性 => 父類實例上的屬性')
console.log(sub.age, '子類實例原型的原型上的屬性 => 父類實例原型上的屬性') // 一層層上溯
複製代碼
修改constructor也能夠用下面的方式
Sub.prototype = Object.create(Super.prototype, {
// Oject.create第二個參數表示生成的原型上的屬性
// 不要忘了從新指定構造函數
constructor: {
value: Student
}
})
複製代碼
借用構造函數繼承
function Super1(name) {
this.name = name
}
function Super2(age) {
this.age = age
}
Super1.prototype.sex = 'man'
function Sub(name, age, address) {
Super1.call(this, name) // 經過call,綁定super1的this爲子類實例,並執行Super1(),至關於 this.name = name
Super2.call(this, age) // 優勢:能夠多繼承,同時繼承了Super1和Super2中的屬性,且在子類實例上修改屬性相互不受影響
this.address = address // 缺點:不能繼承父類實例原型鏈上的屬性和方法
}
const sub = new Sub('woow_wu7', 20, 'hangzhou') // 優勢:能夠向父類傳參
console.log(sub)
複製代碼
組合式繼承
- 借用構造函數繼承 + 原型鏈繼承
- 優勢:多繼承,將父類傳參,某些屬性不共享,繼承父類實例原型鏈上的屬性和方法
- 缺點:!!!!!!
- 父類被調用了兩次,一次是借用構造函數是的call調用,一次是原型鏈繼承時的new調用
- 由於父類兩次調用,因此子類和父類實例原型鏈上有相同的屬性和方法,形成浪費
代碼:
function Super1(name) {
this.name = name
}
function Super2(age) {
this.age = age
}
Super1.prototype.getName = function() {
return 'Super1' + this.name
}
Super2.prototype.getAge = function() {
return 'Super2' + this.age
}
function Sub(name, age, address) {
Super1.call(this, name) // 借用構造函數,多繼承,但不能繼承原型鏈上的屬性
Super2.call(this, age)
this.address = address
}
Sub.prototype = new Super1()
// 注意:這裏沒有傳參,在原型鏈繼承這條線上,父類實例上的nane屬性是undefined
// 注意:原型鏈繼承這條線,仍是不能多繼承,(如不能同時繼承Super1和Super2所在的prototye)由於是直接賦值
Sub.constructor = Sub // 記得修改constructor指向
Sub.prototype.getAddress = function() {
return 'Sub' + this.address
}
const sub = new Sub('woow_wu7', 20, 'hangzhou')
console.log(sub)
組合繼承最大的缺點:
1. 父類執行了兩次
- 1. 在new Sub('woow_wu7', 20, 'hangzhou')是會執行Super.call(this, name)------- 生成一次name // 'woow_wu7'
- 2. 在Sub.prototype = new Super1() 執行了一次,又會生成一次name // undefined
複製代碼
寄生組合式繼承
- 主要解決:
- 組合式繼承中,父類被屢次調用,致使子類實例屬性和子類實例原型鏈上有相同的屬性的問題
- 由於父類兩次被調用,call和new,構造函數中的屬性會兩次生成,形成資源的浪費
function Super(name) {
this.name = name
}
Super.prototype.getName = function() {
return 'Super' + this.name
}
function Sub(name, age) {
Super.call(this, name) // 借用構造函數
this.age = age
}
// Sub.prototype = new Super() ---------------- 原型鏈繼承,(沒用寄生組合繼承以前,即沒有使用過渡函數Parasitic)
function Parasitic(){}
Parasitic.prototype = Super.prototype
Sub.prototype = new Parasitic()
// Parasitic內沒有任何屬性
// 這樣就沒有執行父類(Super構造函數),而是間接的只繼承了父類實例原型上的屬性
Sub.constructor = Sub // 修改prototype要同時修改conscrutor指向
Sub.prototype.getAge = function() {
return 'Sub' + this.age
}
const sub = new Sub('woow_wu7', 20)
console.log(sub)
複製代碼
es5的繼承(借用構造函數式繼承)
- es5的借用構造函數式繼承:
- 是先建立子類的this,而後將父類的屬性和方法幫到子類的this對象上
es6的繼承:
- 是將父類實例的屬性和方法添加到this上,而後用子類的構造函數修改this
複製代碼
super做爲函數
- super做爲函數:只能用於構造函數中,表示父類的構造函數
- super做爲函數:內部的this指向的是子類的實例
class A {
constructor() {
console.log(this, 'this')
}
}
class B extends A {
constructor() {
super() // 注意:super最爲函數,只能用於構造函數中表示父類的構造函數,內部this指向子類的實例
}
}
new B() // B this ========> super做爲函數,內部this指向子類的實例
複製代碼
因爲this指向子類實例,因此若是經過super對某個屬性賦值,這時super就是this,賦值的屬性會變成子類實例的屬性。
class A {
constructor() {
this.x = 1;
}
}
class B extends A {
constructor() {
super();
this.x = 2;
super.x = 3; // !!!!!super對某個屬性賦值,super就表示this,即子類的實例!!!!!
console.log(super.x); // undefined // super在普通函數中是對象時,表示父類的原型
console.log(this.x); // 3
}
}
let b = new B();
複製代碼
super做爲對象,在靜態方法中:表示父類
class Parent {
static myMethod(msg) {
console.log('static', msg);
}
myMethod(msg) {
console.log('instance', msg);
}
}
class Child extends Parent {
static myMethod(msg) {
super.myMethod(msg); // super做爲對象,在靜態方法中,表示父類,調用父類的靜態方法myMethod
}
myMethod(msg) {
super.myMethod(msg);
}
}
Child.myMethod(1);
// static 1
// Child.myMethod()是調用Child的靜態方法,靜態方法中的super對象表示父類
var child = new Child();
child.myMethod(2);
// instance 2
// 實例上調用myMethod,沒構造函數中沒有,就去原型上查找,super對象在普通方法中表示父類的原型
複製代碼
__proto__
和 prototype__proto__
老是指向父類(表示構造函數的繼承)prototype.__proto__
老是指向父類的prototype(表示方法的繼承)個人簡書:www.jianshu.com/p/d8809038c…
川神:juejin.im/post/5c433e…
www.jianshu.com/p/a8844b28f…webpack