JavaScript之继承的几种形式

继承
原型链继承

在 es5 中,为了实现方法的共享和复用,使用原型链作为实现继承的主要方法。每一个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,实例都包含一个指向原型对象的内部指针。

一个例子:

function Test() {
  console.log("1111");
}
Test.prototype.foo = function() {
  console.log("foo");
};
var oo = new Test();

console.log(oo.__proto__ === Test.prototype); // true
console.log(oo.constructor === Test); // true
console.log(Test.prototype.constructor === Test); // true
console.log(Test.prototype === Test.prototype); //true

构造函数(Test) 有 原型对象(Test.prototype)
原型对象(Test.prototype) 包含 指向构造函数的指针(Test.prototype.constructor)
实例(oo) 包含 指向原型对象的内部指针(oo.__proto__)

  • 使用原型链继承

    当我们需要共享一些方法,并且,方法能够

function Parent(name, age) {
  this.name = name;
  this.age = age;
}

Parent.prototype.message = function() {
  console.log("个人信息:" + this.name + this.age);
};

var Parent = new Parent("张三", 24);

function Child(name, age) {
  this.name = name;
  this.age = age;
}

Child.prototype = new Parent();

var child = new Child("李四的儿子:", 1);

child.message();
  • 使用 call、apply 实现继承
function Parent(name, age) {
  this.name = name;
  this.age = age;
  this.message = function() {
    console.log("个人信息:" + this.name + this.age);
  };
}

function Child() {
  Parent.apply(this, arguments);

  // function Child(name, age) {
  // Parent.call(this,name,age)
}

var child = new Child("张三的儿子", 1);
child.message();

使用 call/apply,在 Child 构造函数内调用 Parent 函数,初始化 Parent 中定义的对象,Child 的每个实例就拥有来自 Parent 的副本对象了。当对 Parent 的对象进行修改,Child 继承的属性不会被修改。例如:

function Parent(name, age) {
  this.name = name;
  this.age = age;
  this.test = "aaaaa";
  this.message = function() {
    console.log("个人信息:" + this.name + this.age);
  };
}

var parent = new Parent();
parent.test = "bbbb";
parent.name = "oooo";

console.log(parent.test); // bbbb
console.log(parent.name); // oooo

function Child(name, age) {
  Parent.call(this, name, age);
}

var child = new Child("张三的儿子", 1);
console.log(child.test); // aaaaa
console.log(child.name); // 张三的儿子
  • 原型链 prototype 和 call/apply 一起使用
function Parent(name, age) {
  this.name = name;
  this.age = age;
}
Parent.prototype.message = function() {
  console.log("个人信息:" + this.name + this.age);
};

function Child() {
  Parent.apply(this, arguments);
}

Child.prototype = new Parent();

var child = new Child("张三的儿子", 1);

使用 apply/call 继承的是 Parent 构造函数中的属性,使用原型链继承的是 Parent 原型链上的属性。

class 继承

es6 中可以使用 class 关键字定义一个类

class Parent {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }
}

typeof Parent; // 'function'
Parent === Parent.prototype.constructor; // true

Parent 类的数据类型为函数,Parent 指向构造函数(constructor)。构造函数的 prototype 属性在 ES6 的"类"上依然存在,类的所有方法(除 constructor)都定义在类的 prototype 属性上。

class Parent {
  constructor(name, age) {
    this.name = name;
    this.age = age;
  }

  message() {
    console.log("个人信息:" + this.name + this.age);
  }
}
//可以等同于
Parent.prototype.message = function() {
  // ...
};
class Parent {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    console.log("ppppooo");
  }

  message() {
    console.log("个人信息:" + this.name + this.age);
  }
}

let parent = new Parent("张三", 24); // ppppooo

parent.message(); // 个人信息:张三24
console.log(parent.hasOwnProperty("constructor")); // false
console.log(parent.hasOwnProperty("message")); // false
console.log(parent.hasOwnProperty("name")); // true

从上例可以看出,constructor 在构建实例的时候就已经调用,hasOwnProperty 返回实例对象自身的属性,而 message 是原型对象所以打印出 false。

实现继承:

class Parent {
  constructor(name, age) {
    this.name = name;
    this.age = age;
    console.log("ppppooo");
  }

  message() {
    console.log("个人信息:" + this.name + this.age);
  }
}

class Child extends Parent {
  constructor(name, age, home) {
    super(name, age);
    this.home = home;
  }
  getMess() {
    console.log("extends:" + this.name);
  }
}

let child = new Child("lisi", 55, 10086);
child.getMess(); // extends:lisi
child.message(); // 个人信息:lisi55

Child 类通过extends super继承了 Parent 的属性和方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值