這幾天在學習react的時候學習到ES6的 class extends 繼承方式,就複習一下ES5的繼承機制,並整理下來。python
- ES5繼承機制
- ES6繼承機制
- 二者的區別總結
在js萬物皆對象,但事仍是區分普通對象和函數對象,那你們須要知道是隻有函數對象纔有prototype屬性,但全部對象都有__proto__屬性react
function A(){
}
var B = new A;
複製代碼
那這裏就得出幾個公式:es6
B.__proto__== A.prototype;
B.constructor == A;
a.prototype.constuctor = A;
複製代碼
那這是實現繼承的基礎; 也就是說A.prototype是A的原型對象,A是構造函數,B是A的實例,原型對象(A.prototype)是 構造函數(A)的一個實例。而此時this指向是指向實例。 明白這個關係實現繼承就很簡單了!看一下下面的代碼app
經過重寫子類的原型 等於 父類的一個實例,(父類的實例屬相變成子類的原型屬性)函數
function father() {
this.faName = 'father';
}
father.prototype.getfaName = function() {
console.log(this.faName);
};
function child() {
this.chName = 'child';
}
child.prototype = new father();
child.prototype.constructor = child;
child.prototype.getchName = function() {
console.log(this.chName);
};
複製代碼
經過子類的原型對象指向父類實例的方式來實現繼承,那咱們不難發現原型鏈的造成是真正是靠__proto_ 而非prototype,子類的實例能夠訪問父類原型上的方法,是由於子類實例經過 _proto 與父類的原型對象有鏈接工具
//先來個父類,帶些屬性
function Super(){
this.flag = true;
}
//爲了提升複用性,方法綁定在父類原型屬性上
Super.prototype.getFlag = function(){
return this.flag;
}
//來個子類
function Sub(){
this.subFlag = false;
}
//實現繼承
Sub.prototype = new Super;
//給子類添加子類特有的方法,注意順序要在繼承以後
Sub.prototype.getSubFlag = function(){
return this.subFlag;
}
//構造實例
var es5 = new Sub;
複製代碼
所謂寄生組合式繼承,即經過藉助構造函數來繼承屬性,經過原型鏈的混成形式來繼承方法。 其背後的基本思路是:沒必要爲了指定子類型的原型而調用超類型的構造函數,咱們所須要的無非就是超類型原型的一個副本而已。本質上,就是使用寄生式繼承來繼承超類型的原型,而後再將結果指定給子類型的原型。學習
function inserit(son, father) {
var obj = Object.create(father.prototype);
son.prototype = obj;
obj.constructor = son
}
function SuperType(name,colors) {
this.name = name;
this.colors = colors;
}
SuperType.prototype.sayName = function () {
return this.name;
}
function SubType(job,name,color) {
SuperType.call(this, name,color);
this.job = job;
}
//核心方法
inserit(SubType, SuperType);
SubType.prototype.sayjob = function () {
return this.job;
}
var instance= new SubType("doctor","John",["red","green"]);
console.log(instance.sayjob(),instance.sayName()) //doctor,John
複製代碼
ES5的繼承機制簡單來講就是:實質是先創造子類的實例對象this,而後再將父類的方法添加到this上面(Parent.apply(this))this
class Point {
constructor(x) {
this.x = 1;
this.p = 2;
}
print() {
return this.x;
}
}
Point.prototype.z = '4'
class ColorPoint extends Point {
constructor(x) {
this.color = color; // ReferenceError
super(x, y);
this.x = x; // 正確
}
m() {
super.print();
}
}
複製代碼
ES6繼承是經過class丶extends 關鍵字來實現繼承 Point是父類,ColorPoint 是子類 經過 class 新建子類 extends繼承父類的方式實現繼承,方式比ES5簡單的多。es5
constructor 方法是類的構造函數,是一個默認方法,經過 new 命令建立對象實例時,自動調用該方法。一個類必須有 constructor 方法,若是沒有顯式定義,一個默認的 consructor 方法會被默認添加。因此即便你沒有添加構造函數,也是會有一個默認的構造函數的。通常 constructor 方法返回實例對象 this ,可是也能夠指定 constructor 方法返回一個全新的對象,讓返回的實例對象不是該類的實例。spa
class Points {
constructor(x) {
this.x = 1;
this.p = 2;
}
print() {
return this.x;
}
statc getname(){
return new.target.name;
}
}
等同於:
function Points(x) {
this.x = x;
this.p = 2;
}
Points.prototype.print = function() {
return '(' + this.x +')';
}
複製代碼
也就是說constructor就表明在父類上加屬性,而在class對象加方法屬性 等於在原型上的加。而這些屬性方法 只有經過new出的實例 或者是extends 繼承出來的實例才能夠獲取到 因此咱們能夠獲得
new Points().__proto__.print() //能夠調用到Points的print方法
new Points().x = 1 //能夠調用到constructor 裏面的 this.x=1
複製代碼
super既能夠當作函數使用,也能夠當作對象使用兩種使用的時候徹底不同, 函數用時 : 在 constructor 中必須調用 super 方法,由於子類沒有本身的 this 對象,而是繼承父類的 this 對象,而後對其進行加工,而 super 就表明了父類的構造函數。super 雖然表明了父類 A 的構造函數,可是返回的是子類 B 的實例,即 super 內部的 this 指的是 B,所以 super() 在這裏至關於
A.prototype.constructor.call(this, props)
複製代碼
在 super() 執行時,它指向的是 子類 B 的構造函數,而不是父類 A 的構造函數。也就是說,super() 內部的 this 指向的是 B。因此在第一個es6的例子中子類的this指向的是本身。、
當作對象使用 : 在普通方法中,指向父類的原型對象;在靜態方法中,指向父類。 因此在子類的方法中super.print();指向的是父類原型上的方法。 可是由於super的兩種用法,因此es6規定在使用必需要明確使用方式,像單獨console.log(super) 就會報錯。
顧名思義是靜態方法的意思,類至關於實例的原型, 全部在類中定義的方法, 都會被實例繼承。 若是在一個方法前, 加上static關鍵字, 就表示該方法不會被實例繼承, 而是直接經過類來調用, 這就稱爲「 靜態方法」。靜態方法調用直接在類上進行,而在類的實例上不可被調用。靜態方法一般用於建立 實用/工具 函數。
new.target屬性容許你檢測函數或構造方法是否經過是經過new運算符被調用的。在經過new運算符被初始化的函數或構造方法中,new.target返回一個指向構造方法或函數的引用。在普通的函數調用中,new.target 的值是undefined。
也就是說new.target的功能就是用來檢測函數的調用是否是經過 new 去建立一個新對象的,並且new.target返回的是一個指向函數的引用,也就是說咱們可以肯定是哪一個函數進行了new操做。
先建立父類實例this 經過class丶extends丶super關鍵字定義子類,並改變this指向,super自己是指向父類的構造函數但作函數調用後返回的是子類的實例,實際上作了父類.prototype.constructor.call(this),作對象調用時指向父類.prototype,從而實現繼承。