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)得到了復用。
缺點:同理父類的屬性(name)也是復用,即子類實例沒有自己的屬性。
二 構造函數實現繼承
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),不會相互影響。
缺點:但是繼承父類方法的時候就不需要這種特性,沒有實現父類方法的復用。
三 組合式繼承
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'); // 可以按上述兩種方法驗證,復用了父類的方法,實例沒有復用,達到目的
優點:繼承了上述兩種方式的優點,摒棄了缺點,復用了方法,子類又有各自的屬性。
缺點:因為父類構造函數被執行了兩次,子類的原型對象(Sub.prototype)中也有一份父類的實例屬性,而且這些屬性會被子類實例(sub1,sub2)的屬性覆蓋掉,也存在內存浪費。
四 寄生組合式繼承
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' })