1、原型链:

每个构造函数都有一个原型对象,且有一个指针指向该原型对象(prototype),原型对象都包含一个指向构造函数的指针(constructor),而实例都包含一个指向原型对象的内部指针(proto)。若实例的原型是另一个构造函数的实例,该实例的原型有一个指向另一个原型的指针,层层递进,构成原型链。

原型上的属性和方法为所有实例所共有,当访问一个实例属性时,首先会在实例中搜索该属性,如果没有找到该属性,则会继续搜索该实例的原型,沿着原型链网上搜索,到原型链末端或找到为止。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 子类
function Sub(){
  this.property = 'Sub Property'
}
Sub.prototype = new Super()
// 注意这里new Super()生成的超类对象并没有constructor属性,故需添加上
Sub.prototype.constructor = Sub
```缺点:
 
1.  包含引用类型的原型属性会被所有实例共享,一个实例对引用类型属性进行修改,就是直接修改原型上的该属性;
2.  在创建子类型的实例时,没有办法给超类型的构造函数传递参数。
 
注意:原型上的引用值属性和方法使用时均为指针,但构造函数中的不同,不同实例中的同名属性和方法也不相同!!!

2、借用构造函数:

1
2
3
4
5
在子类型构造函数中,使用call或apply方法在将来新建的对象上执行父类构造函数
function Sub(){
Super.call(this,'参数')//将Super的属性和方法都复制了一遍
 this.property = 'Sub Property'
}
  1. 实例并不是父类的实例,只是子类的实例
  2. 只能继承父类的属性和方法,不能继承父类原型上的属性/方法
  3. 无法实现函数复用(父类上的方法也都复制到最后的实例中,方法不能复用),每个子类都有父类属性和方法的副本,影响性能

3、组合继承:

使用原型链来实现对原型属性和方法的继承,通过借用构造函数来实现对实例属性的继承
1
2
3
4
5
6
function Sub(){
 Super.call(this)              //第二次调用Super() Super中的属性和方法复制进来 this.property = 'Sub Property'
 }
 Sub.prototype = new Super()//第一次调用Super() Super.prototype上的方法则可以共享
 // 注意这里new Super()生成的超类对象并没有constructor属性,故需添加上
 Sub.prototype.constructor = Sub
无论什么情况都会调用两次超类型构造函数,
第一次是将子类的原型指向父类的实例,这样可以共享父类的原型上的属性和方法,但父类中的属性和方法会写入到子类的原型上;
第二次是将父类中的属性和方法复制到子类构造函数中,会覆盖子类原型上的同名属性

4、原型式继承:

1
2
3
4
5
function objectCreate(obj){
 function F(){}
 F.prototype = obj
 return new F()
 }
但是新对象原型的那个对象(obj)中,引用类型的属性始终都会共享相应的值

5、寄生式继承:

创建一个仅仅用于封装继承过程的函数,然后在内部以某种方式增强对象,最后返回对象
1
2
3
4
5
6
7
8
9
10
function objectCreate(obj){
 function F(){}
 F.prototype = obj
 return new F()
 }
 function createSubObj(superInstance){
 var clone = objectCreate(superInstance)//任何能够返回新对象的函数都适用
 clone.property = 'Sub Property'
 return clone
 }
组合继承的问题是:会调用两次构造函数,(一次生成实例并作为子类的原型,一次是当做普通函数)导致父类中的属性会有两组:一组在子类的原型上;一组在实例上。
解决这个问题的方法--------寄生组合式继承

6、寄生组合式继承:

结合寄生式继承和组合式继承,完美实现不带两份超类属性的继承方式。
1
2
3
4
5
6
7
8
9
10
function inheritPrototype(Super,Sub){
 var superProtoClone = Object.create(Super.prototype)
 superProtoClone.constructor = Sub
 Sub.prototype = Super
 }
 function Sub(){
 Super.call()
 Sub.property = 'Sub Property'
 }
 inheritPrototype(Super,Sub)

7、ES6 extends继承

类的实质是基于原型的和基于构造函数的语法糖

类声明:class 类名 {类体} ;//类声明不会提升

类表达式:let 类名 = class 类名 {类体}

extends 来创建子类,并继承父类 : class 子类名 extends 父类名 {类体}

1
class Point{ ....   } typeof Point // "function" Point === Point.prototype.constructor // true

类的数据类型就是函数,类本身就指向构造函数。

使用的时候,也是直接对类使用new命令,跟构造函数的用法完全一致。

1
2
3
4
class Bar{
    doStuff(){console.log('stuff');}
} var b = new Bar();
b.doStuff();// "stuff"

构造函数的prototype属性,在 ES6 的“类”上面继续存在。事实上,类的所有方法都定义在类的prototype属性上面。

1
2
3
4
5
6
//定义类 class Point{
 constructor((x, y){  this.x = x; this.y = y;
}
toString(){ return  '('  +  this.x +  ', '  +  this.y +  ')';
}
}
constructor方法是类的默认方法,通过new命令生成对象实例时,自动调用该方法。一个类必须有constructor方法,如果没有显式定义,一个空的constructor方法会被默认添加。constructor方法默认返回实例对象(即this)
类必须使用new调用,否则会报错。实例的属性除非显式定义在其本身(即定义在this对象上),否则都是定义在原型上(即定义在class上)
Class 可以通过extends关键字实现继承:在子类的构造函数中,只有调用super之后,才可以使用this关键字,super代表父类的构造函数,子类的构造函数必须执行一次super函数。
1
2
3
4
5
6
7
8
9
class ColorPoint extends Point {
 consturctor(x,y,color){
 super(x,y); // 调用父类的constructor(x, y)
 this.color = color;
}
 toString(){
 return this.color + " " super.toString();//调用父类的toString()方法
 }
}

 

JS继承方法的更多相关文章

  1. js继承的方式及其优缺点

    js继承方法 前因:ECMAScript不支持接口继承,只支持实现继承 一.原型链 概念:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针,让 ...

  2. JS继承(简单理解版)

    童鞋们,我们今天聊聊js的继承,关于继承,平时开发基本用不到,但是面试没有不考的,我就想问,这是人干的事吗? 好吧,迫于社会主义核心价值观,我们今天就来简单说一说js的继承,谁让它是面向对象编程很重要 ...

  3. 各种实现js继承的方法总结

    昨天主要介绍了原型,在js中,原型,原型链和继承是三个很重要的概念,而这几个概念也是面试中经常会被问到的问题,今天,就把昨天还没总结的原型链和继承继续做一个整理,希望大家一起学习,一起进步呀O(∩_∩ ...

  4. js oop中的三种继承方法

    JS OOP 中的三种继承方法: 很多读者关于js opp的继承比较模糊,本文总结了oop中的三种继承方法,以助于读者进行区分. <继承使用一个子类继承另一个父类,子类可以自动拥有父类的属性和方 ...

  5. 实现JS继承的几种方法

    总的来说,JS的继承大体上分为两种:借用构造函数方式和原型方式 首先,我们来看看借用构造函数方式的几种做法: //方式一function Person(name, sex){ this.name = ...

  6. JS中常见的几种继承方法

    1.原型链继承 // 1.原型链继承 /* 缺点:所有属性被共享,而且不能传递参数 */ function Person(name,age){ this.name = name this.age = ...

  7. js各继承方法的优缺点

    在js中有很多种继承的方法,下面总结这些方法的优缺点. ####1.原型链继承 优点: 非常纯粹的继承关系,实例是子类的实例,也是父类的实例 父类新增原型方法/原型属性,子类都能访问到 简单,易于实现 ...

  8. JS中的类,类的继承方法

    大牛请无视此篇! 首先我们定义一个类,方法很简单,就像我们定义函数一样,只不过我们为了与函数区分,名称首字母要大写,看代码: function Person (){ } 这就是一个很简单的Poson类 ...

  9. JS继承的6种方法

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

随机推荐

  1. Kali-linux无线网络嗅探工具Kismet

    如果要进行无线网络渗透测试,则必须先扫描所有有效的无线接入点.刚好在Kali Linux中,提供了一款嗅探无线网络工具Kismet.使用该工具可以测量周围的无线信号,并查看所有可用的无线接入点.本节将 ...

  2. (转)ci

    1  从代码管理器签出源文件 2  修改代码 3  编译代码 4  遇到错误,转到2继续修改直到达到预期 5  运行单元测试,期望所有的测试绿色(通过) 6  单元测试出错,转入2 7  重构代码,按 ...

  3. PHP文档

    http://php.net/manual/zh/function.socket-close.php

  4. [转]SQL Server 数据库中的 MD5 和 SHA1

    MD5 和 SHA1 是一种单向加密算法,常用于密码的验证等需要加密操作的场合,在一般情况下,开发人员可以通过 Delphi 或 PHP 这类语言自己编写相关函数或者使用自带的函数,然后将加密过的结果 ...

  5. Android性能监控

    Android性能监控 一.搭建Android性能测试环境,参见<Android性能测试之Monkey使用>中内容. 二.启动Android虚拟机,可以通过eclipse启动,也可以通过命 ...

  6. SQL修改字段默认值、获取字段默认值

    一.SQL修改字段默认值 alter table 表名 drop constraint 约束名字 说明:删除表的字段的原有约束 alter table 表名 add constraint 约束名字 D ...

  7. 多线程系列 - 基础篇01 - 线程基本概念 & 线程优先级 & 守护线程 60%

    1.什么是线程 将线程理解为轻量级进程,它与进程的最大的区别是: 多个线程共享一个进程资源: 对于OS的许多资源的分配和管理(如内存)通常都是进程级别的,线程只是os调度的最小单位: 相对于进程来说更 ...

  8. 翻译 TI SerialBLEbridge V 1.4.1

    原文地址:http://processors.wiki.ti.com/index.php/SerialBLEbridge_V_1.4.1 Sample App Overview This page d ...

  9. oracle json 解析函数

    CREATE OR REPLACE TYPE ty_tbl_str_split IS TABLE OF ty_row_str_split;CREATE OR REPLACE TYPE ty_row_s ...

  10. python散记

    1.AOP 将不同的类的内部中雷同的代码和重复的功能,提取出来以重用. 装饰器是一个很著名的设计模式,经常被用于有切面需求的场景,较为经典的有插入日志.性能测试.事务处理等 2.新式类,经典类 新式类 ...