JS继承的6种方式(非ES6)

本篇博客主要来整合一下JS继承的六种方式及其优缺点。首先我们提供一个父类:

// 父类
function Person(name) {
  this.name = name;
  this.showName = function () {
    console.log(this.name);
  }
}

原型链继承

本节中我们使用到的子类如下:

// 子类
function Staff(office) {
  this.office = office;
  this.showOffice = function(){
    console.log(this.office);
  }
}
Staff.prototype = new Person('staff');
const a = new Staff('D302');
const b = new Staff('D232');
a.showName();		// satff
a.showOffice();		// D302
b.showName();		// staff
b.showOffice();		// D232

上述语句即为原型链继承,此时,ab有一个共有属性name,要注意此时name为基本数据类型,而原型链继承构造的子对象之间共享的是引用数据类型,如果我单独对aname属性进行修改,那么bname属性不会因此而改变。举例说明如下:

Staff.prototype = new Person('staff');
const a = new Staff('D302');
const b = new Staff('D232');
a.name = 'change'
a.showName();	// change
b.showName();	// staff

但是,如果Person对象的name属性值引用类型的话,那么构造出的子对象的属性就有可能会受到影响,实例如下:

Staff.prototype = new Person([1,2,3]);
const a = new Staff('D302');
const b = new Staff('D232');
a.showName();	// [1,3]
b.showName();	// [1,3]
a.name.push(4);
a.showName();	// [1,3,4]
b.showName();	// [1,4]
a.name = [1,2]
a.showName();	// [1,2]
b.showName();	// [1,4]

大家可以看到如上两种情况,我在往name属性里面push的时候ab的属性值都发生了变化,但是我在将aname属性重新赋值为[1,2]时,bname值并没有发生变化。这是因为进行push操作之后引用数据类型的地址值并没有发生变化,而bname属性指向的地址与aname属性指向的地址相同,所以ab会同时发生变化。但是我将其重新复制时,aname属性指向的地址发生了变化,b指向的还是原来的地址,所以ab并没有发生同步变化。

优点: 能通过instanceOfisPrototypeOf的检测

缺点

  1. 父对象中的属性也变成了子对象的prototype中的公用属性

     		2. 不能向父类型的构造函数中传递参数
     		3. 只能继承一个父类
    

借用构造函数

function Staff(name,office) {
  Person.call(this,name);
  this.office = office;
  this.showOffice = function(){
    console.log(this.office);
  }
}

const a = new Staff('a','D302');
const b = new Staff('b','D232');
a.showName();	// a
b.showName();	// b
console.log(a instanceof Person);  // false

通过这个实例我们可以看出我们可以向父类传递参数了,并且可以继承多个父类函数,只要调用多次call函数即可.

优点

  1. 可以向父类传递参数
  2. 可以实现多父类继承
  3. 父类的属性不会被子类共享

缺点:调用构造函数的话就相当于在每个新建对象内都有一个独立的属性已经函数,StaffPerson并不能使用instanceof方法,两者并不存在指向关系,函数复用并没有派上用场。

组合继承

function Staff(name,name);
  this.office = office;
  this.showOffice = function(){
    console.log(this.office);
  }
}
Staff.prototype = new Person();
const a = new Staff('a','D232');
a.showName();	// a
b.showName();	// b
console.log(a instanceof Person);  // true

这种方法就是对原型链继承和构造函数继承的结合。

优点

  1. 继承前两者的优点
  2. 可以实现对构造函数的复用

缺点:调用了两次父类构造函数,更耗内存

原型式继承

function container(obj){
  function F() {}
  F.prototype = obj;
  return new F();
}
const child = new Person('child');
const staff = container(child);
staff.showName();  // child

这种继承方式其实可以看做是直接复制了父类。

缺点:无法复用

寄生式继承

function container(obj){
  function F() {}
  F.prototype = obj;
  return new F();
}

function Staff(obj,office) {
  const sub = container(obj);
  sub.office = office;
  sub.showOffice = function(){
    console.log(this.office);
  }
  return sub;
}
const child = new Person('child');
const a = Staff(child,'D232');
const b = Staff(child,'C433');
a.showName();	// child
a.showOffice();	// D232
b.showName();	// child
b.showOffice();	// C433

这种继承方式就是在原型式继承的基础上又加了一个函数用来新增加属性,解决了原型式继承需要后续增加属性的问题。

寄生组合继承(常用)

寄生组合式继承强化的部分就是在组合继承的基础上减少一次多余的调用父类的构造函数:

function Staff(name,name);
  this.office = office;
  this.showOffice = function () {
    console.log(this.office);
  }
}
Staff.prototype = Object.create(Person.prototype);
Staff.prototype.constructor = Person;
const a = new Staff('a','D232');
const b = new Staff('b','C433');
a.showName();	// a
a.showOffice();	// D232
b.showName();	// b
b.showOffice(); // C433

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


kindeditor4.x代码高亮功能默认使用的是prettify插件,prettify是Google提供的一款源代码语法高亮着色器,它提供一种简单的形式来着色HTML页面上的程序代码,实现方式如下: 首先在编辑器里面插入javascript代码: 确定后会在编辑器插入这样的代码: <pre
这一篇我将介绍如何让kindeditor4.x整合SyntaxHighlighter代码高亮,因为SyntaxHighlighter的应用非常广泛,所以将kindeditor默认的prettify替换为SyntaxHighlighter代码高亮插件 上一篇“让kindeditor显示高亮代码”中已经
js如何实现弹出form提交表单?(图文+视频)
js怎么获取复选框选中的值
js如何实现倒计时跳转页面
如何用js控制图片放大缩小
JS怎么获取当前时间戳
JS如何判断对象是否为数组
JS怎么获取图片当前宽高
JS对象如何转为json格式字符串
JS怎么获取图片原始宽高
怎么在click事件中调用多个js函数
js如何往数组中添加新元素
js如何拆分字符串
JS怎么对数组内元素进行求和
JS如何判断屏幕大小
js怎么解析json数据
js如何实时获取浏览器窗口大小
原生JS实现别踩白块小游戏(五)
原生JS实现别踩白块小游戏(一)