class Person { constructor(x,y) { this.x = x this.y = y } add() { return this.x + this.y } } let person = new Person(1,2) console.log(person.add()) // 3
經過類Person
的構造函數實例化了一個對象person
,person
繼承了類的add
方法
ES6以前是沒有類的概念,因此要實現上面的操做,須要function
出馬函數
function Person(x, y) { // 首字母大寫表示它是個類函數 this.x = x this.y = y this.add = function() { return this.x + this.y } } let person = new Person(1,2) console.log(person.add()) // 3
這樣雖然實現了,可是明顯有缺點,上面ES6類的構造函數僅初始化了x,y
,默認繼承了add
方法,而function
方式的須要初始化全部,因此須要優化優化
function Person(x, y) { this.x = x this.y = y } Person.prototype.add = function() { return this.x + this.y } let person = new Person(1,2) console.log(person.add()) // 3
很明顯,經過Person.prototype
實現了class
中this
的做用,這就叫實例原型(實例對象自己就是從類實例化而來,可不就是實例原型)
既然與ES6 class
掛上了鉤,這時還缺乏一個constructor
,巧了,實例原型剛好有一個屬性constructor
指向構造函數自己
並且爲了造成一個閉環,實例對象也有一個屬性__proto__
指向實例原型
this
由於全部對象都繼承於
Object
,因此會有下面的一部分
class Father{ constructor(name,age) { this.name = name this.age = age } // 此處的方式實際上是掛載在prototype屬性上的,反推上面的ES5 語法 sayName() { console.log(this.name + this.age) } } class Child extends Father{ constructor(name, age, job) { super(name,age) // 必須調用super方法,而且必定要在使用this以前調用,至關於Father.prototype.constructor.call() this.job = job } sayJob() { console.log(this.job) } // 覆蓋父類的方法 sayName() { console.log('hello world') // 調用父類的屬性,輸出:hello world } } let kid = new Child('nike','20','teacher') kid.sayJob() // teacher kid.sayName() // hello world
其中的關鍵是super
,super
做爲一個方法在調用父類的構造函數,同時也能夠做爲一個對象,指向父類的prototype
對象,而上面的調用父類屬性會出現undefined
,由於name
並無掛載在父類的prototype
上,從新改造一下spa
class Father{ constructor(name,age) { Father.prototype.name = name this.age = age } }
由於sayName
方法是掛載在prototype
屬性上的,因此能夠直接super.sayName()
調用,並且調用方法執行的上下文this
是指向子類的prototype
class Father{ constructor(name,age) { this.name = name this.age = age this.job = 'Hello world' } sayJob() { console.log(this.job) } } class Child extends Father{ constructor(name, age, job) { super(name,age) // 必須調用super方法,而且必定要在使用this以前調用 this.job = job } sayJob() { super.sayJob() // teacher } } let kid = new Child('nike','20','teacher') kid.sayJob() // teacher
從上面的分析可知,xxx.prototype
做爲實例原型,它擁有跟實例對象同樣的屬性和方法,因此只須要把父類的實例對象賦值給子類的prototype
屬性,那麼不就繼承了code
function Father(name) { this.name = name } function Child(age) { this.age = age } Child.prototype = new Father('nike') // 將父類的實例對象賦值給Child的prototype let kid = new Child(20) // 實例子類對象 console.log(kid.name) // nike console.log(kid.age) // 20
由於ES5的類
是個函數,因此藉助函數的特性能夠實現另一種繼承對象
function Father(name) { this.name = name } function Child(age) { Father.call(this, 'nike') this.age = age } let kid = new Child(20) console.log(kid.name) // nike
這兩個就夠了,其餘方式都是多此一舉繼承
person instanceof Person // true person instanceof Object // true Person.prototype.isPrototypeOf(person) // true Object.prototype.isPrototypeOf(person) // true