JavaScript 继承

179 阅读3分钟

JavaScript 继承

原型链继承

function Parent() {
    this.name = '父亲'; // 实例基本属性 (该属性,强调私有,不共享)
    this.arr = [1]; // (该属性,强调私有)
}
Parent.prototype.say = function() { // -- 将需要复用、共享的方法定义在父类原型上
    console.log('hello')
}
function Child(like) {
    this.like = like;
}
Child.prototype = new Parent() // 核心

let boy1 = new Child()
let boy2 = new Child()

// 优点:共享了父类构造函数的say方法
console.log(boy1.say(), boy2.say(), boy1.say === boy2.say); // hello , hello , true

// 缺点1:不能传参数
// 缺点2:
console.log(boy1.name, boy2.name, boy1.name===boy2.name); // 父亲,父亲,true

boy1.arr.push(2); // 修改了boy1的arr属性,boy2的arr属性,也会变化,因为两个实例的原型上(Child.prototype)有了父类构造函数的实例属性arr;所以只要修改了boy1.arr,boy2.arr的属性也会变化。  ----  原型上的arr属性是共享的。
console.log(boy2.arr); // [1,2]

注意:修改boy1的name属性,是不会影响到boy2.name。因为name是基本属性,不是引用属性。

构造函数继承

function Parent(name) {
    this.name = name; // 实例基本属性 (该属性,强调私有,不共享)
     this.arr = [1]; // (该属性,强调私有)
    this.say = function() { // 实例引用属性 (该属性,强调复用,需要共享)
        console.log('hello')
    }
}
function Child(name,like) {
    Parent.call(this,name);  // 核心
    this.like = like;
}
let boy1 = new Child('小红','apple');
let boy2 = new Child('小明', 'orange ');

// 优点1:可传参
console.log(boy1.name, boy2.name); // 小红, 小明

// 优点2:不共享父类构造函数的引用属性
boy1.arr.push(2);
console.log(boy1.arr,boy2.arr);// [1,2] [1]

// 缺点1:方法不能复用
console.log(boy1.say === boy2.say) // false (说明,boy1和boy2
的say方法是独立,不是共享的)

// 缺点2:不能继承父类原型上的方法
Parent.prototype.walk = function () {   // 在父类的原型对象上定义一个walk方法。
    console.log('我会走路')
}
boy1.walk;  // undefined (说明实例,不能获得父类原型上的方法)

组合继承

function Parent(name) {
    this.name = name; // 实例基本属性 (该属性,强调私有,不共享)
    this.arr = [1]; // (该属性,强调私有)
}
Parent.prototype.say = function() { // --- 将需要复用、共享的方法定义在父类原型上
    console.log('hello')
}
function Child(name,like) {
    Parent.call(this,name,like) // 核心   第二次
    this.like = like;
}
Child.prototype = new Parent() // 核心   第一次

<!--这里是修复构造函数指向的代码-->

let boy1 = new Child('小红','apple')
let boy2 = new Child('小明','orange')

// 优点1:可以传参数
console.log(boy1.name,boy1.like); // 小红,apple

// 优点2:可复用父类原型上的方法
console.log(boy1.say === boy2.say) // true

原型式继承

// 两种方法
// Object.create
// function object

function object(o) {
  function F() {}
  F.pototype = o;
  return new F();
}

let parent = {
  name: "parent",
  share: [1, 2, 3], // 父类的引用属性全部被子类所共享
  log: function() {
    //  父类方法可以复用
    return this.name;
  }
};

let child = Object.create(parent); //  子类不能向父类传递参数

寄生继承

function createAnother(original) {
  var clone = object(original);
  clone.sayHi = function() {
    alert("hi");
  };
  return clone;
}

var person = {
  name: "hello",
  friends: ["z", "x", "p"]
};

var anotherPerson = createAnother(person);

anotherPerson.sayHi(); //'hi'

寄生组合继承

function Parent(name, friends) {
  this.name = name;
  this.friends = friends;
}
Parent.prototype = {
  constructor: Parent, // 需要手动绑定 constructor
  share: [1, 2, 3],
  log: function() {
    return this.name;
  }
};

function Child(name, friends, gender) {
  Parent.call(this, name, friends); // 这里只需要调用一次 Parent
  this.gender = gender;
}
// 上半部分和组合继承一样

let F = function() {}; // 创建一个中介函数
F.prototype = Parent.prototype; // 这个中介的原型指向 Parent 的原型
Child.prototype = new F(); // 注意这里没有使用 new 操作符调用 Parent
Child.prototype.constructor = Child;

// 封装

function Parent(name, friends) {
  this.name = name; // 可以定义私有属性
  this.friends = friends; // 可以定义公有引用属性不会被共享
}
Parent.prototype = {
  constructor: Parent, // 需要手动绑定 constructor
  share: [1, 2, 3], // 这里定义的公有属性会被共享
  log: function() {
    // 方法被共享了
    return this.name;
  }
};

function Child(name, friends, gender) {
  Parent.call(this, name, friends); // 可以向父类传递参数  这里又调用了一次 Parent
  this.gender = gender;
}

function proto(child, parent) {
  let clonePrototype = Object.create(parent.prototype);
  //核心  通过创建中间对象,子类原型和父类原型,就会隔离开
  child.prototype = clonePrototype;
  child.prototype.constructor = child;
}

proto(Child, Parent);

ES2015 class 继承

class Parent {
  constructor(name, friends) {
    // 该属性在构造函数上,不共享
    this.name = name;
    this.friends = friends;
  }
  log() {
    // 该方法在原型上,共享
    return this;
  }
}
Parent.prototype.share = [1, 2, 3]; // 原型上的属性,共享

class Child extends Parent {
  constructor(name, friends, gender) {
    super(name, friends);
    this.gender = gender;
  }
}