总的来说,JS的继承大体上分为两种:借用构造函数方式和原型方式

首先,我们来看看借用构造函数方式的几种做法:

//方式一
function Person(name, sex){
this.name = name;
this.sex = sex;
this.move = function(){
alert("move");
};
}; function Man(name, sex, address, phone){
this.pe = Person;
this.pe(name, sex);
delete this.pe;
this.address = address;
this.phone = phone;
};

原理是这样的,将整个方法替换掉pe,当我们调用 this.(name,sex); 时,

相当于在Man里面执行上面的那一段代码,而此时的this已经代表的是Man对象,使Man也具有了name,sex等属性与及move方法。

//方式二
function Person(name, sex){
this.name = name;
this.sex = sex;
this.move = function(){
alert("move");
};
}; function Man(name, sex, address, phone){
Person.call(this, name, sex);
this.address = address;
this.phone = phone;
};

call方法实现继承,call方法会将this及Man中的参数传递到调用的方法(Person)中,此时Person里的this代表的是Man对象

当调用到Person的构造方法的时候,调用this.name的时候已经是Man.name了,这种方法也可以实现继承。

//方式三
function Person(name, sex){
this.name = name;
this.sex = sex;
this.move = function(){
alert("move");
};
}; function Man(name, sex, address, phone){
Person.apply(this, new Array(name, sex));
this.address = address;
this.phone = phone;
};

apply方法实现继承,其实apply方法和call方法是一样,只不过apply传递过去的参数要用一个数组包装起来而已。

上面就是借用构造函数方式的三种做法,原理其实就是上下文环境变量this的替换。

它可以实现多重继承,但真正这样用的不多,因为它有着明显的性能缺陷。

借用构造函数方式模拟的继承里,所有的成员方法都是针对this而创建的,也就是所有的实例都会拥有一份成员方法的副本,这是对内存资源的一种极度浪费。

还有就是借用构造函数方式无法继承prototype域的变量和方法。

再来看看原型方式:

function Person(){};
Person.prototype.name = "";
Person.prototype.sex = "";
Person.prototype.move = function(){
alert("move");
};

function Man(){};
Man.prototype = new Person();

关键是对最后一句Man的原型指向Person类构造的对象(注意是对象,是实例)。

Js对象在读取某个对象属性的时候,总是先查看自身域的属性列表,如果有就返回,否则去读取prototype域(每个对象共享构造对象的类的prototype域所有属性和方法),如果找到就返回,由于prototype可以指向别的对象,所以Js解释器会递归的去查找prototype域指向对象的prototype域,直到prototype为本身,查找变成了一种循环,就停止,此时还没找到就成undefined了。

这样看来,最后一句发生的效果就是将父类所有属性和方法连接到子类的prototype域上,这样子类就继承了父类所有的属性和方法。

原型继承的缺陷也相当明显,就是继承时父类的构造函数时不能带参数,以及不支持多继承。

综合两种方式的利弊,可以总结出一种混合式继承方法:

function Person(name){
this.name = name;
};
Person.prototype.move = function(){
alert("move");
}; function Man(name){
Person.call(this, name);
};
Man.prototype = new Person();
Man.prototype.showName = function(){
alert("My name is " + this.name + ".");
};

用借用构造函数方式来继承父类属性,用原型方式来继承父类的方法。这样在对子类进行实例化的时候,就可以同时初始化从父类继承下来的属性。

同时,由于父类的方法都是定义在prototype域上,通过原型方式继承,这样就不会造成资源的浪费。

美中不足就是始终不支持多继承,但足可满足大多数情况的需要了。

除去上面的几种方式外,这里再补充一种名为寄生组合式的继承方式:

function inheritPrototype(subClass, superClass){
var prototype = Object(superClass.prototype);
prototype.constructor = subClass;
subClass.prototype = prototype;
} function Person(name){
this.name = name;
};
Person.prototype.move = function(){
alert("move");
}; function Man(name){
Person.call(this, name);
};
inheritPrototype(Man, Person);
Man.prototype.showName = function(){
alert("My name is " + this.name + ".");
}; var person = new Person();
console.info(person instanceof Man); // 结果是true,这并非是我们想要的,是此方法的缺点

与上面混合方式相比,都使用了借用构造函数的方式来继承父类属性。

但这里没有把子类的原型指向父类的实例,而是直接把子类的原型指向改写了constructor属性的父类原型

以此来实现了原型链,达到继承的目的。

这种方式的优点是,实现继承只调用了一次父类的构造函数。缺点是,父类的实例使用instanceof操作符判断它是子类的实例时也会返回true。另外,父类的cunstructior属性也跟着指向了子类的构造函数了。显然这并非是我们想要的。

这种方法,实际上也相当于所有类共用同一个原型,试想一下,当出现复杂的继承关系,原型就变得很难维护了(容易出现方法重写覆盖的情况)。

所以,个人还是更推荐用前一种方法,混合式继承。  

实现JS继承的几种方法的更多相关文章

  1. JS继承的6种方法

    1.原型链 基本思想:利用原型让一个引用类型继承另外一个引用类型的属性和方法. 构造函数,原型,实例之间的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,而实例都包含一个指向原 ...

  2. js继承的几种方法理解和代码演示

    1.属性继承 :call .apply:不建议使用浪费内存. function Person(name,age,sex){ this.name = name; this.age = age; this ...

  3. JS学习笔记——JavaScript继承的6种方法(原型链、借用构造函数、组合、原型式、寄生式、寄生组合式)

    JavaScript继承的6种方法 1,原型链继承 2,借用构造函数继承 3,组合继承(原型+借用构造) 4,原型式继承 5,寄生式继承 6,寄生组合式继承 1.原型链继承. <script t ...

  4. js对象之间的"继承"的五种方法

    今天要介绍的是,对象之间的"继承"的五种方法. 比如,现在有一个"动物"对象的构造函数. function Animal(){ this.species = & ...

  5. js去除空格12种方法

    注:本文非本人原著:原文作者: 黄卉  <js去除空格12种方法> //JS去除空格的方法目前共有12种: //实现1 String.prototype.trim = function() ...

  6. 判断数组的方法/判断JS数据类型的四种方法

    参考文: 以下 3 个判断数组的方法,请分别介绍它们之间的区别和优劣Object.prototype.toString.call() . instanceof 以及 Array.isArray() h ...

  7. js继承的几种实现方法

    一.用function实现: function Person(name) { this.name = name; } Person.prototype.getName = function() { r ...

  8. js继承的几种方法和es6继承方法

        一.原型链继     1.基本思想     利用原型链来实现继承,超类的一个实例作为子类的原型     2.具体实现     function F() {}     //原型属性,原型方法: ...

  9. js继承的三种实现

    概念:在有些面向对象语言中,可以使用一个类(子类)继承另一个类(父类),子类可以拥有父类的属性和方法,这个功能可以在js中进行模拟. 三种方法: 第一种:扩展Object方法 Object.proto ...

随机推荐

  1. centos7 编译安装nginx

    转载文章 原文地址 https://www.cnblogs.com/liujuncm5/p/6713784.html 安装所需环境 Nginx 是 C语言 开发,建议在 Linux 上运行,当然,也可 ...

  2. Java中的多态方法

    public class Main { public void test(Object o) { System.out.println("Object"); } public vo ...

  3. Visual Studio Error

    Visual Studio Error 注意:文中所有“系统”用词,均指Windows Console操作系统IO Debug Error 错误类型 #0表示调用约定错误 可以考虑在指针前面加上_st ...

  4. [SIP00]SIP 概念总结

    SIP ---------------------------   Session Initiation Protocol ---------------------------   create, ...

  5. python读写Excel文件(xlrd、xlwr)

    一.首先需要安装第三方库:pip install xlrd 1.打开Excel文件,由于写入时需要copy,所以这里加上保留原格式参数:formatting_info=True excel_file ...

  6. C#文件和目录的操作

    根据文件名获取文件 /// <summary> /// 根据文件名获取文件 /// </summary> /// <param name="directory& ...

  7. mysql安装 卸载 查字符集编码

    下载地址 :     https://cdn.mysql.com//Downloads/MySQL-8.0/mysql-8.0.11-winx64.zip 解压zip  解压完之后的目录 在里面新建一 ...

  8. Conditional Expressions

    Conditional Expressions建立一些逻辑关系 The conditional expression classes from django.db import models clas ...

  9. ABP架构

    ABP架构 一.什么是ABP架构? ABP是“ASP.NET Boilerplate Project (ASP.NET样板项目)”的简称. ASP.NET Boilerplate 基于DDD的经典分层 ...

  10. 爆款AR游戏如何打造?网易杨鹏以《悠梦》为例详解前沿技术

    本文来自网易云社区. 7月31日,2018云创大会游戏论坛在杭州国际博览中心103B圆满举行.本场游戏论坛聚焦探讨了可能对游戏行业发展有重大推动的新技术.新实践,如AR.区块链.安全.大数据等. 网易 ...