JS繼承的幾種方式

一、屬性拷貝

就是將對象的成員複製一份給需要繼承的對象

// 創建父對象
var superObj = {
  name: 'Li',
  age: 25,
  friends: ['小明', '小李', '小趙'],
  showName: function(){
    alert(this.name);
  }
}

// 創建需要繼承的子對象
var subObj = {};

// 開始拷貝屬性(使用for...in...循環)
for( var i in superObj ){
  subObj[i] = superObj[i];
}

console.log(subObj)
console.log(superObj)

如果繼承過來的成員是引用類型的話,那麼這個引用類型的成員在父對象和子對象之間是共享的,也就是說修改了之後, 父子對象都會受到影響.

二、原型式繼承

借用構造函數的原型對象實現繼承

// 創建父構造函數
function SuperClass(name){
  this.name = name;
  this.showName = function(){
    alert(this.name);
  }
}

// 設置父構造器的原型對象
SuperClass.prototype.showAge = function(){
  console.log(this.age);
}

// 創建子構造函數
function SubClass(){

}

// 設置子構造函數的原型對象實現繼承
SubClass.prototype = SuperClass.prototype;

var child = new SubClass()
  1. 父構造函數的原型對象和子構造函數的原型對象上的成員有共享問題
  2. 只能繼承父構造函數的原型對象上的成員, 不能繼承父構造函數的實例對象的成員

三、原型鏈繼承

父構造函數的原型對象和子構造函數的原型對象上的成員有共享問題

只能繼承父構造函數的原型對象上的成員, 不能繼承父構造函數的實例對象的成員

// 創建父構造函數
function SuperClass(){
    this.name = 'liyajie';
    this.age = 25;
    this.showName = function(){
        console.log(this.name);
    }
}
// 設置父構造函數的原型
SuperClass.prototype.friends = ['小名', '小強'];
SuperClass.prototype.showAge = function(){
    console.log(this.age);
}
// 創建子構造函數
function SubClass(){

}
// 實現繼承
SubClass.prototype = new SuperClass();
// 修改子構造函數的原型的構造器屬性
SubClass.prototype.constructor = SubClass;

var child = new SubClass();
console.log(child.name); // liyajie
console.log(child.age);// 25
child.showName();// liyajie
child.showAge();// 25
console.log(child.friends); // ['小名','小強']

// 當我們改變friends的時候, 父構造函數的原型對象的也會變化
child.friends.push('小王八');
console.log(child.friends);["小名", "小強", "小王八"]
var father = new SuperClass();
console.log(father.friends);["小名", "小強", "小王八"]

不能給父構造函數傳遞參數,父子構造函數的原型對象之間有共享問題

四、借用構造函數

使用call和apply借用其他構造函數的成員, 可以解決給父構造函數傳遞參數的問題, 但是獲取不到父構造函數原型上的成員.也不存在共享問題

// 創建父構造函數
function Person(name){
  this.name = name;
  this.freinds = ['小王', '小強'];
  this.showName = function(){
     console.log(this.name);
  }
}

// 創建子構造函數
 function Student(name){
  // 使用call借用Person的構造函數
  Person.call(this, name);
 }

 // 測試是否有了 Person 的成員
 var stu = new Student('Li');
 stu.showName(); // Li
 console.log(stu.friends); // ['小王','小強']

 五、組合繼承

 借用構造函數 + 原型式繼承

// 創建父構造函數
function Person(name,age){
    this.name = name;
    this.age = age;
    this.showName = function(){
        console.log(this.name);
    }
}
// 設置父構造函數的原型對象
Person.prototype.showAge = function(){
    console.log(this.age);
}
// 創建子構造函數
function Student(name){
    Person.call(this,name);
}
// 設置繼承
Student.prototype = Person.prototype;
Student.prototype.constructor = Student;

上面代碼解決了 父構造函數的屬性繼承到了子構造函數的實例對象上了,並且繼承了父構造函數原型對象上的成員解決了給父構造函數傳遞參數問題

六、借用構造函數 + 深拷貝

function Person(name,age){
    this.name = name;
    this.age = age;
    this.showName = function(){
        console.log(this.name);
    }
}
Person.prototype.friends = ['小王','小強','小王八'];

function Student(name,25){
    // 借用構造函數(Person)
    Person.call(this,name,25);
}
// 使用深拷貝實現繼承
deepCopy(Student.prototype,Person.prototype);
Student.prototype.constructor = Student;

這樣就將Person的原型對象上的成員拷貝到了Student的原型上了, 這種方式沒有屬性共享的問題.

原文:https://www.jianshu.com/p/1016160e91fe

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章