繼承
一個對象直接使用另外一個對象的屬性和方法
JS 并不提供原生的繼承機制,但實現(xiàn)方法有很多,下面介紹一種最為通用的
實現(xiàn)繼承需要實現(xiàn)的兩個點:
- 得到了一個類的屬性
- 得到了一個類的方法
function Person(name, sex) {
this.name = name
this.sex = sex
}
Person,prototype.printName = function() {
console.log(this.name)
}
function Male(age) {
this.age = age
}
Male.prototype.printAge = function() {
console.log(this.age)
}
屬性獲取
對象屬性的獲取是通過構(gòu)造函數(shù)的執(zhí)行,在一個類中執(zhí)行另外一個類的構(gòu)造函數(shù),就可以把屬性賦值道自身內(nèi)部,但是需要把環(huán)境改到本身的作用域,借助函數(shù) call
function Male(name, sex, age) {
Person.call(this, name, sex)
this.age = age
}
Male.prototype.printAge = function() {
console.log(this.age)
}
實例化
var man = new Male('Bryant', 'male', 40)
console.log(man.sex) // "male"
方法獲取
類的方法都定義在了 prototype 里面,只要把子類的 prototype 改為 父類的 prototype 的備份就可以了
Male.prototype = Object.create(Person.prototype)
通過 object.create clone 一個新的 prototype 而不是直接把 Person.prototype 直接賦值,如果直接賦值會因為引用關(guān)系,導(dǎo)致后續(xù)修改子類的 prototype 時也會修改父類的 prototype,因為修改的是同一個值
同時需要注意的是 對子類添加方法 和 修改子類 prototype 的順序,必須在修改其 prototype 之后,再對子類添加方法,否則方法的添加會被覆蓋
此外還存在一個問題是,prototype 對象有一個屬性 constructor 指向其類型,因為復(fù)制父類的 prototype,所以這個時候的 constructor 屬性指向是不對的,會導(dǎo)致判斷類型時出錯
ES5正確完整的繼承方式
function Male(name, sex, age) {
Person.call(this, name, sex)
this.age = age
}
Male.prototype = Object.create(Person.prototype) // 修改 prototype 在先
Male.prototype.constructor = Male // 重新指定一下 constructor 屬性到子類的類型
Male.prototype.printAge = function() { // 添加方法在后
console.log(this.age)
}
繼承三步走:
- 屬性獲取
- 修改 prototype
- 重定 constructor
最終方案
使用一個函數(shù)實現(xiàn)上述繼承內(nèi)容
function inherit(superType, subType) {
var _prototype = Object.create(superType.prototype)
_prototype.constructor = subType
subType.prototype = _prototype
}
使用方法
function Person(name, sex) {
this.name = name
this.sex = sex
}
Person.prototype.printName = function() {
console.log(this.name)
}
function Male(name, sex, age) {
Person.call(this, name, sex)
this.age = age
}
inherit(Person, Male)
Male.prototype.printAge = function() {
console.log(this.age)
}
var man = new Male('Bryant', 'male', 40)
man.printName() // "Bryant"

以上是ES5的實現(xiàn)方法,下面的代碼是不用ES5實現(xiàn)的類似繼承效果
function Person(name, sex) {
this.name = name
this.sex = sex
}
Person.prototype.printName = function() {
console.log(this.name)
}
function Male(name, sex, age) {
Person.call(this, name, sex)
this.age = age
}
Male.prototype = new Person()
Male.prototype.constructor = Male
Male.prototype.printAge = function() {
console.log(this.age)
}
var man = new Male('Bryant', 'male', 40)
man.printName() // "Bryant"
hasOwnProperty
繼承之后,子類的實例有了符父類的方法,如何判斷某個方法是自身的還是父類的呢?
hasOwnProperty 是 Object.prototype 的一個方法,可以判斷一個對象是否包含自定義屬性而不是原型鏈上的屬性,hasOwnProperty是JS中唯一一個處理屬性但是不查找原型鏈的函數(shù)。
man.hasOwnProperty('name') // true
man.hasOwnProperty('printName') // false
man.hasOwnProperty('printAge') // true