過完年,立刻又到了金三銀四的季節,這段時間不管是身經百戰的老鳥,仍是在程序界中殺個七進七出的高手,抑或是菜鳥都在這段時間內,瘋狂的惡補本身的知識面,以便於在跳槽的時候拿到一個趁心如意的offer —— 而js繼承沒必要說必然是一個很是高頻的基礎面試題面試
說它基礎是由於絕大部分都能說出幾點來,接下來我就帶你們全面的回顧一下這個知識點bash
JS是一種弱類型的面嚮對象語言(抽象,封裝,繼承,多態),因此在實現繼承上仍是一如既往的靈活函數
//父類
function Person(name) {
this.name = name || '無名'
this.sayHello = function () {
console.log('hello everyBody i am ' + this.name)
}
}
Person.prototype.doWork = function (work) {
console.log(this.name + '的工做是--' + work)
}
複製代碼
原型繼承基本上是人人都會的功能無非就是 將父類的實例看成子類的原型, 其中牽扯到的知識點有兩個優化
this的指向ui
原型的鏈條繼承this
//子類
function Teacher() {}
Teacher.prototype = new Person('張三')
var ls = new Teacher()
console.log(ls.name) // 張三
ls.sayHello() //hello everyBody i am 張三
ls.doWork('教師') //張三的工做是--教師
var zs = new Teacher()
console.log(zs.name) // 張三
zs.sayHello() //hello everyBody i am 張三
zs.doWork('教師') //張三的工做是--教師
複製代碼
優勢:spa
缺點:prototype
經過call來調用父類構造函數,因此每個子類都會有一個父類實例的副本code
知識點對象
//子類
function Teacher(name) {
Person.call(this,name)
this.name = name || '無名'
}
var zs = new Teacher('張三')
console.log(zs.name)
zs.sayHello()
zs.doWork('教師') //報錯
複製代碼
優勢
缺點
這個有點相似於上面,就是把父類的實例化遍歷,經過賦值的方式賦值給子類的原型
//子類
function Teacher(name) {
var example = new Person();
for(var p in example){
Teacher.prototype[p] = example[p];
}
Teacher.prototype.name = name || 'Tom';
}
複製代碼
優勢
缺點
經過實例化父類,而後爲這個實例添加新的屬性
//子類
function Teacher(name) {
let example = new Person()
example.name = name || '無名'
return example
}
var zs = new Teacher('張三')
console.log(zs.name)
zs.sayHello()
zs.doWork('教師')
複製代碼
優勢
缺點
上面的四種方法都各有本身的優缺點,可是整體來看要麼是不全面要麼是麻煩或者佔內存,通常在開發中不建議這樣使用,可是也根據你本身的實際狀況,好比上面的某個方式很符合你的業務場景,而又不考慮擴展之類的其它東西,也是可使用的
固然除了這些,js發展了這麼多年確定是有比上面四種更好的方法,咱們接着介紹
經過call拷貝來父類的屬性給子類使用,而且經過原型鏈的方式實現原型鏈的繼承
//子類
function Teacher(name) {
Person.call(this,name)
this.name = name || '無名'
}
Teacher.prototype = Object.create(Person.prototype)
Teacher.prototype.constructor = Teacher
var zs = new Teacher('張三')
console.log(zs.name)
zs.sayHello()
zs.doWork('教師')
複製代碼
優勢
這種方式能夠理解爲第五種方法的優化
//子類
function Teacher(name) {
Person.call(this,name)
this.name = name || '無名'
}
(function(){
let Example = function(){};
Example.prototype = Person.prototype;
Teacher.prototype = new Example();
Teacher.prototype.constructor = Teacher
})();
var zs = new Teacher('張三')
console.log(zs.name)
zs.sayHello()
zs.doWork('教師')
複製代碼
優勢
缺點
class Person{
constructor(name){
this.name = name
}
sayName(){
console.log('my name is ' + this.name)
}
}
class Teacher extends Person{
constructor(name){
super()
this.name = name
}
}
console.log(new Teacher('zs'))
new Teacher('zs').sayName()
複製代碼
子類必須在constructor方法中調用super方法,不然新建實例時會報錯。這是由於子類沒有本身的this對象,而是繼承父類的this對象,而後對其進行加工,若是不調用super方法,子類就得不到this對象。所以,只有調用super以後,纔可使用this關鍵字
底層實現:一個繼承語句同時存在兩條繼承鏈:一條實現屬性繼承,一條實現方法的繼承
class A extends B{}
A.__proto__ === B; //繼承屬性
A.prototype.__proto__ == B.prototype;//繼承方法
複製代碼
從上面能夠看到不論是ES5仍是ES6繼承的基本實現方式是同樣的,我想這就是所謂的萬變不離其宗吧
若是有錯誤的地方 歡迎指正批評