# 面向對象復習
## 普通構造函數
~~~
function Person(name, age) {
?this.name = name;
?this.age = age;
}
Person.prototype.say = function(){
?console.log('i can say')
}
Person.go = function () {
?console.log('走一下');
}
~~~
~~~
var p1 = new Person('小白',10);
console.log(p1);
p1.say();
Person.go();
~~~
## class關鍵詞
~~~
class Per{
?constructor(name,age){
? ?this.name ?= name;
? ?this.age = age;
}
?say(){
? ?console.log('i can say')
}
?static go(){
? ?console.log('要走一走')
}
}
var p2 ?= new Per('小黑',15);
console.log(p2);
p2.say();
Per.go();
~~~
# 面向對象繼承
實現人類和中國人(重點) 與美國人(輔助了解)
## 實現人類
~~~
function Person(name,age){
?this.name = name;
?this.age = age;
}
?
Person.prototype.say = function(){
?console.log('i can say ');
}
~~~
## 原型鏈繼承
~~~
?
//原型鏈繼承
?
function Chinese(skin,language){
?this.skin = skin;
?this.language = language;
}
Chinese.prototype = new Person();
var p1 = new Chinese('黃色','中文')
console.log(p1);
p1.say();
~~~
### 圖解

### 問題
Chinese構造函數的原型對象的constructor指向誰。它指向Person,原因是為什么因為new Person()身上沒有constructor,它通過`__proto__`指向Person的原型對象(Person.prototype),這個對象的constructor指向Person。
構造函數的原型對象的constructor指向構造函數自身,按照這個原則我們這個代碼或者關系圖是有錯誤的。如何解決?
將new Person()手動添加constructor并且手動指向Chinese。即可修復。
### 修改后的代碼
~~~
//原型鏈繼承
function Chinese(skin,language){
?this.skin = skin;
?this.language = language;
}
var person1 = new Person();
person1.constructor = Chinese;
Chinese.prototype = person1;
var p1 = new Chinese('黃色','中文')
console.log(p1);
p1.say();
console.log(Chinese.prototype.constructor)
~~~
### 完成后的圖

## 構造函數繼承(對象冒充繼承)
上面的繼承只能繼承原型對象的方法。并不能繼承父類的屬性。如何解決?可以通過關鍵字call或者applay來實現當前類借用擴充。不屬于原型或者原型鏈的操作方式。幫不需要畫圖。
~~~
// 構造函數繼承 對象冒充
function Chinese(skin,language,name,age){
?this.skin = skin;
?this.language = language;
?Person.call(this,name,age);
}
var p1 = new Chinese('黃色','中文','小白',18);
console.log(p1);
~~~
## 組合繼承
組合繼承其實就是原型鏈接繼承和構造函數繼承的結合體
~~~
//原型鏈繼承
function Chinese(skin,language,name,age){
this.skin = skin;
this.language = language;
Person.call(this,name,age);// 第一次調用父類
}
var person1 = new Person(); //第二次調用父類
person1.constructor = Chinese;
Chinese.prototype = person1;
var p1 = new Chinese('黃色','中文','小白',18);
console.log(p1);
p1.say();
~~~
### 問題
組合繼承的問題在于在子類中調用父類一次。會導致性能浪費。

## 原型式繼承(原型繼承)
### 簡易版
~~~
function Chinese(skin,language,name,age){
this.skin = skin;
this.language = language;
}
Chinese.prototype = Person.prototype;
var p1 = new Chinese('黃色','中文')
console.log(p1);
p1.say();
function America(skin,language,name,age){
this.skin = skin;
this.language = language;
}
Chinese.prototype = Person.prototype;
var a1 = new Chinese('白色','英語')
console.log(a1);
a1.say();
~~~
### 圖解

### 問題
如果把Chinese.prototype.say方法修改會產生什么問題?修改代碼嘗試。
~~~
Chinese.prototype.say = function(){
console.log('我是中國人')
}
~~~
完整代碼如下
~~~
function Chinese(skin,language,name,age){
this.skin = skin;
this.language = language;
}
Chinese.prototype = Person.prototype;
Chinese.prototype.say = function(){
console.log('我是中國人')
}
var p1 = new Chinese('黃色','中文')
console.log(p1);
p1.say();
function America(skin,language,name,age){
this.skin = skin;
this.language = language;
}
Chinese.prototype = Person.prototype;
var a1 = new Chinese('白色','英語')
console.log(a1);
a1.say();
~~~
### 執行結果
~~~
Chinese {skin: "黃色", language: "中文"}
我是中國人
Chinese {skin: "白色", language: "英語"}
我是中國人
~~~
我們發現一旦對say方法進行修改,那么導致,繼承于父類Person的所有子類的原型對象的say方法都發生改變。原因是因為他們用的同一份。如何解決?
### 改造原型繼承
其實想法很簡單,又要避開重復實例化父類多次,又要實現不同子類繼承同一父類,在原型對象方法修改時不會影響其它子類。
**看下圖,大家可以簡單理解,其實中間圈中的部分不過就是搭了個橋,讓子類修改原型時候,不會直接修改父類原型。而是創建一個新的空類,這個空類使用原型式繼承父類原型對象。再通過實例化一個對象作為子類Chinese的原型對象。**
**這樣的話子類的實例 p 可以通過`__proto__`查找到父類 Chinese 的原型對象,同樣的也可以通過原型對象的`__proto__`來查找到Person類的原型對象的公共方法。 這樣原型鏈得到繼承。**
**同時我們修改子類Chinese的原型對象也僅僅是修改了f對象的功能。沒有修改 父類Person類的原型對象。**
**簡單理解這個圖的意思就就我們將父類和子類中間橫插一腳。**

### 簡化后的圖

### 代碼實現
~~~
function Chinese(skin,language,name,age){
this.skin = skin;
this.language = language;
}
// Chinese.prototype = Person.prototype;
// 原型繼承改造
//1.創建F構造函數,并且返回實例 new F();
function object(parentPro){
var F = function () {}
F.prototype = parentPro;
return new F();
}
//將返回的實例作為子類的原型對象,同時修改子類原型對象的constructor指向子類。
function inhert(par,child) {
var mid = object(par.prototype);
mid.constructor = child;
child.prototype = mid;
}
inhert(Person,Chinese);
~~~
## 寄生式組合繼承
其實就是原型式繼承改造后和構造函數繼承的結合版。
~~~
// Chinese.prototype = Person.prototype;
// 原型繼承改造
//1.創建F構造函數,并且返回實例 new F();
function object(parentPro){
var F = function () {}
F.prototype = parentPro;
return new F();
}
//2.將返回的實例作為子類的原型對象,同時修改子類原型對象的constructor指向子類。
function inhert(par,child) {
var mid = object(par.prototype);
mid.constructor = child;
child.prototype = mid;
}
function Chinese(skin,language,name,age){
this.skin = skin;
this.language = language;
Person.call(this,name,age)
}
inhert(Person,Chinese);
var p1 = new Chinese('黃皮膚','中文','小白',18)
console.log(p1);
p1.say();
~~~

# class繼承
~~~
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name)
}
}
class Chinese extends Person{
constructor(name,age,skin,language){
super(name,age);
this.skin = skin;
this.language = language;
}
}
var p = new Chinese('小黑',18,'白','漢語')
console.log(p);
~~~
## 注意事項
如果子類要繼承父類,子類的構造函數中必須書寫super() 而且必須寫在首行。它其實就相當于構造函數中的對象冒充寫法。

## 給父類添加靜態方法
父類的靜態方法可以給子類繼承靜態方法。
~~~
class Person{
constructor(name,age){
this.name = name;
this.age = age;
}
say(){
console.log(this.name)
}
static go(){
console.log('i can go')
}
}
~~~
~~~
Person.go();//i can go
Chinese.go();//i can go
~~~
- webpack復習
- React基礎
- 前端三大主流框架對比
- React中幾個核心的概念
- React基礎語法
- React JSX語法
- React組件
- 普通組件
- 組件通信-父向子傳遞
- 組件拆成單個文件
- 面向對象復習
- Class組件基礎
- Class組件的私有狀態(私有數據)
- 案例:實現評論列表組件
- 組件樣式管理
- 組件樣式分離-樣式表
- CSS模塊化
- 生命周期
- React組件生命周期
- Counter組件來學習組件生命周期
- 生命周期總結
- 生命周期案例
- React評論列表
- React雙向數據綁定
- React版todolist
- 其它提高(了解)
- 組件默認值和數據類型驗證
- 綁定this并傳參的三種方式
- 祖孫級和非父子組件傳遞數據(了解)
- React路由
- 路由基礎
- 動態路由
- 路由嚴格模式
- 路由導航定位
- 路由重定向
- 路由懶加載
- WolfMovie項目
- 項目初始化
- AntDesign使用
- 其它相關了解