javascript中實現繼承的方式有不少種,通常都是經過原型鏈和構造函數來實現。下面對各類實現方式進行分析,總結各自的優缺點。javascript
一 原型繼承
let Super = functioin(name) { this.name = name; this.setName = (newName) => { this.name = name; }; this.getName = () => { return this.name; } } let Sub = function(sex) { this.sex = sex; } Sub.prototype = new Super('eric'); //經過改變原型對象實現繼承 let sub1 = new Sub('male') sub2 = new Sub('female'); sub1.setName('ada'); // 這裏必須經過setName方法來修改繼承來的name屬性。 // 若是經過sub1.name== 'ada',就打不到目的,由於此時sub1對象上沒有name屬性, // 這樣等於爲該對象添加了新的屬性,而不是修改繼承而來的name屬性。 console.log(sub2.name); // ada,可見此sub2的name也會被修改掉 console.log(sub1.getName === sub2.getName) // true,複用了方法
優勢:父類的方法(getName)獲得了複用。java
缺點:同理父類的屬性(name)也是複用,即子類實例沒有本身的屬性。es6
二 構造函數實現繼承
let Super = function(name) { this.name = name; this.getName = () => { return this.name; } } let Sub = function(sex,name) { Super.call(this,name); // 調用父類方法爲子類實例添加屬性 this.sex = sex; } let sub1 = new Sub('male','eric'), sub2 = new Sub('female','eric'); sub1.name = 'ada'; console.log(sub2.name); // eric,實例的屬性沒有相互影響 console.log(sub1.getName === sub2.getName); // false,可見方法沒有複用
優勢:子類的每一個實例都有本身的屬性(name),不會相互影響。函數
缺點:可是繼承父類方法的時候就不須要這種特性,沒有實現父類方法的複用。ui
三 組合式繼承
let Super = function(name) { this.name = name; } Super.prototype = { constructor: Super, // 保持構造函數和原型對象的完整性 getName() { return this.name; } } let Sub = function(sex) { Super.call(this,'eric'); //繼承父類屬性 this.sex = sex; } Sub.prototype = new Super('eric'); //繼承父類方法 Sub.prototype.constructor = Sub; let sub1 = new Sub('male'), sub2 = new Sub('female'); // 能夠按上述兩種方法驗證,複用了父類的方法,實例沒有複用,達到目的
優勢:繼承了上述兩種方式的優勢,摒棄了缺點,複用了方法,子類又有各自的屬性。this
缺點:由於父類構造函數被執行了兩次,子類的原型對象(Sub.prototype)中也有一份父類的實例屬性,並且這些屬性會被子類實例(sub1,sub2)的屬性覆蓋掉,也存在內存浪費。spa
四 寄生組合式繼承
let Super = function(name) { this.name = name; } Super.prototype = { constructor: Super, getName() { return this.name; } } let Sub = function(sex,name) { Super.call(this,name); this.sex = sex; } // 組合繼承的缺點就是在繼承父類方法的時候調用了父類構造函數,從而形成內存浪費, // 如今只要解決了這個問題就完美了。那在複用父類方法的時候, // 使用Object.create方法也能夠達到目的,沒有調用父類構造函數,問題解決。 Sub.prototype = Object.create(Super.prototype); Sub.prototype.constructor = Sub;
五 es6中的class
class Super() { constructor(props = { name: 'eric' }) { this.name = props.name; } setName(name) { this.name = name; } getName() { return this.name; } } class Sub extends Super { constructor(props) { super(props = { sex: 'male' }); // 建立實例,繼承父類屬性和方法 this.sex = props.sex; } } let sub1 = new Sub({ name: 'eric', sex: 'male' }) let sub2 = new Sub({ name: 'eric', sex: 'female' })