JavaScript中的继承方式详解

js继承的概念

js里常用的如下两种继承方式:

原型链继承(对象间的继承)

类式继承(构造函数间的继承)

由于js不像java那样是真正面向对象的语言,js是基于对象的,它没有类的概念。所以,要想实现继承,可以用js的原型prototype机制或者用apply和call方法去实现

在面向对象的语言中,我们使用类来创建一个自定义对象。然而js中所有事物都是对象,那么用什么办法来创建自定义对象呢?这就需要用到js的原型:

我们可以简单的把prototype看做是一个模版,新创建的自定义对象都是这个模版(prototype)的一个拷贝 (实际上不是拷贝而是链接,只不过这种链接是不可见,新实例化的对象内部有一个看不见的__Proto__指针,指向原型对象)。

js可以通过构造函数和原型的方式模拟实现类的功能。 另外,js类式继承的实现也是依靠原型链来实现的。

原型式继承与类式继承

类式继承是在子类型构造函数的内部调用超类型的构造函数。

严格的类式继承并不是很常见,一般都是组合着用:

function Super(){

this.colors=["red","blue"];

}

function Sub(){

Super.call(this);

}

原型式继承是借助已有的对象创建新的对象,将子类的原型指向父类,就相当于加入了父类这条原型链

原型链继承

为了让子类继承父类的属性(也包括方法),首先需要定义一个构造函数。然后,将父类的新实例赋值给构造函数的原型。代码如下:

function Parent(){

this.name = 'mike';

}

function Child(){

this.age = 12;

}

Child.prototype = new Parent();//Child继承Parent,通过原型,形成链条

var test = new Child();

alert(test.age);

alert(test.name);//得到被继承的属性

//继续原型链继承

function Brother(){   //brother构造

this.weight = 60;

}

Brother.prototype = new Child();//继续原型链继承

var brother = new Brother();

alert(brother.name);//继承了Parent和Child,弹出mike

alert(brother.age);//弹出12

以上原型链继承还缺少一环,那就是Object,所有的构造函数都继承自Object。而继承Object是自动完成的,并不需要我们自己手动继承,那么他们的从属关系是怎样的呢?

确定原型和实例的关系

可以通过两种方式来确定原型和实例之间的关系。操作符instanceof和isPrototypeof()方法:

alert(brother instanceof Object)//true

alert(test instanceof Brother);//false,test 是brother的超类

alert(brother instanceof Child);//true

alert(brother instanceof Parent);//true

只要是原型链中出现过的原型,都可以说是该原型链派生的实例的原型,因此,isPrototypeof()方法也会返回true

在js中,被继承的函数称为超类型(父类,基类也行),继承的函数称为子类型(子类,派生类)。使用原型继承主要由两个问题:

一是字面量重写原型会中断关系,使用引用类型的原型,并且子类型还无法给超类型传递参数。

伪类解决引用共享和超类型无法传参的问题,我们可以采用“借用构造函数”技术

借用构造函数(类式继承)

function Parent(age){

this.name = ['mike','jack','smith'];

this.age = age;

}

function Child(age){

Parent.call(this,age);

}

var test = new Child(21);

alert(test.age);//21

alert(test.name);//mike,jack,smith

test.name.push('bill');

alert(test.name);//mike,jack,smith,bill

借用构造函数虽然解决了刚才两种问题,但没有原型,则复用无从谈起,所以我们需要原型链+借用构造函数的模式,这种模式称为组合继承

组合继承

function Parent(age){

this.name = ['mike','jack','smith'];

this.age = age;

}

Parent.prototype.run = function () {

return this.name  + ' are both' + this.age;

};

function Child(age){

Parent.call(this,age);//对象冒充,给超类型传参

}

Child.prototype = new Parent();//原型链继承

var test = new Child(21);//写new Parent(21)也行

alert(test.run());//mike,jack,smith are both21

组合式继承是比较常用的一种继承方法,其背后的思路是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性的继承。这样,既通过在原型上定义方法实现了函数复用,又保证每个实例都有它自己的属性。

call()的用法:调用一个对象的一个方法,以另一个对象替换当前对象。

call([thisObj[,arg1[, arg2[, [,.argN]]]]])

原型式继承

这种继承借助原型并基于已有的对象创建新对象,同时还不用创建自定义类型的方式称为原型式继承

function obj(o){

function F(){}

F.prototype = o;

return new F();

}

var box = {

name : 'trigkit4',

arr : ['brother','sister','baba']

};

var b1 = obj(box);

alert(b1.name);//trigkit4

b1.name = 'mike';

alert(b1.name);//mike

alert(b1.arr);//brother,sister,baba

b1.arr.push('parents');

alert(b1.arr);//brother,sister,baba,parents

var b2 = obj(box);

alert(b2.name);//trigkit4

alert(b2.arr);//brother,sister,baba,parents

原型式继承首先在obj()函数内部创建一个临时性的构造函数 ,然后将传入的对象作为这个构造函数的原型,最后返回这个临时类型的一个新实例。

寄生式继承

这种继承方式是把原型式+工厂模式结合起来,目的是为了封装创建的过程。

function create(o){

var f= obj(o);

f.run = function () {

return this.arr;//同样,会共享引用

};

return f;

}

组合式继承的小问题

组合式继承是js最常用的继承模式,但组合继承的超类型在使用过程中会被调用两次;一次是创建子类型的时候,另一次是在子类型构造函数的内部

function Parent(name){

this.name = name;

this.arr = ['哥哥','妹妹','父母'];

}

Parent.prototype.run = function () {

return this.name;

};

function Child(name,age){

Parent.call(this,age);//第二次调用

this.age = age;

}

Child.prototype = new Parent();//第一次调用

以上代码是之前的组合继承,那么寄生组合继承,解决了两次调用的问题。

寄生组合式继承

function obj(o){

function F(){}

F.prototype = o;

return new F();

}

function create(parent,test){

var f = obj(parent.prototype);//创建对象

f.constructor = test;//增强对象

}

function Parent(name){

this.name = name;

this.arr = ['brother','sister','parents'];

}

Parent.prototype.run = function () {

return this.name;

};

function Child(name,age){

Parent.call(this,name);

this.age =age;

}

inheritPrototype(Parent,Child);//通过这里实现继承

var test = new Child('trigkit4',21);

test.arr.push('nephew');

alert(test.arr);//

alert(test.run());//只共享了方法

var test2 = new Child('jack',22);

alert(test2.arr);//引用问题解决

call和apply

全局函数apply和call可以用来改变函数中this的指向,如下:

// 定义一个全局函数

function foo() {

console.log(this.fruit);

}

// 定义一个全局变量

var fruit = "apple";

// 自定义一个对象

var pack = {

fruit: "orange"

};

// 等价于window.foo();

foo.apply(window);  // "apple",此时this等于window

// 此时foo中的this === pack

foo.apply(pack);    // "orange"相关阅读:

举例讲解Java中final关键字的用法

手机端转盘抽奖代码分享

CI框架学习笔记(一) - 环境安装、基本术语和框架流程

微软Surface Pro 3/2固件更新:提升Win10系统下显卡性能

SQL Server查询数据库中表使用空间信息实现脚本

MySQL插入数据时插入无效列的解决方法

浅谈js基本数据类型和typeof

PHP5.3新特性小结

ASP.NET MVC小结之基础篇(二)

js获取元素外链样式的方法

javascript实现自动填写表单实例简析

简述MySQL分片中快速数据迁移

Win10 Mobile最新稳定预览版10586.494升级截图曝光

Javascript实现获取及设置光标位置的方法

php中 继承中的概念,JavaScript_JavaScript中的继承方式详解,js继承的概念 js里常用的如下 - phpStudy...相关推荐

  1. ajax校验的优点,django框架中ajax的使用及避开CSRF 验证的方式详解

    本文实例讲述了django框架中ajax的使用及避开CSRF 验证的方式.分享给大家供大家参考,具体如下: ajax(Asynchronous Javascript And Xml) 异步javasc ...

  2. Spring中bean的初始化和销毁几种实现方式详解

    关联博文:Spring中Bean的作用域与生命周期 Bean的生命周期 : 创建bean对象 – 属性赋值 – 初始化方法调用前的操作 – 初始化方法 – 初始化方法调用后的操作 – --- 销毁前操 ...

  3. java none怎么用tomcat_在docker中部署tomcat并且部署java应用程序的步骤详解

    先给大家简单说下Docker的概念 Docker 是一个开源的应用容器引擎,让开发者可以打包他们的应用以及依赖包到一个可移植的容器中,然后发布到任何流行的 Linux 机器上,也可以实现虚拟化.容器是 ...

  4. ios开发读取剪切板的内容_iOS中管理剪切板的UIPasteboard粘贴板类用法详解

    一.自带剪切板操作的原生UI控件在iOS的UI系统中,有3个控件自带剪切板操作,分别是UITextField.UITextView与UIWebView.在这些控件的文字交互处进行长按手势可以在屏幕视图 ...

  5. c++中.dll与.lib文件的生成与使用的详解

    c++中.dll与.lib文件的生成与使用的详解 --------------------------------------------------------------------------- ...

  6. python中with open写csv文件_Python中的CSV文件使用with语句的方式详解

    是否可以直接使用with语句与CSV文件?能够做这样的事情似乎很自然: import csv with csv.reader(open("myfile.csv")) as read ...

  7. python跨函数调用变量_对python中不同模块(函数、类、变量)的调用详解

    首先,先介绍两种引入模块的方法. 法一:将整个文件引入 import 文件名 文件名.函数名( ) / 文件名.类名 通过这个方法可以运行另外一个文件里的函数 法二:只引入某个文件中一个类/函数/变量 ...

  8. python中ndim是什么_Numpy中ndim、shape、dtype、astype的用法详解

    本文介绍numpy数组中这四个方法的区别ndim.shape.dtype.astype. 1.ndim ndim返回的是数组的维度,返回的只有一个数,该数即表示数组的维度. 2.shape shape ...

  9. python语言中split-python中的split()函数和os.path.split()函数使用详解

    Python中有split()和os.path.split()两个函数: split():拆分字符串.通过指定分隔符对字符串进行切片,并返回分割后的字符串列表. os.path.split():将文件 ...

最新文章

  1. 字符串的规范使用(二)
  2. 简单技能之程序调试入门
  3. python分配问题_Python字符串分配问题!
  4. 详细分析小米抢购软件的实现步骤
  5. matlab simulink节点,ROS与Matlab语言入门教程-从Simulink中创建单独的ROS节点
  6. 湖南科技大学计算机考研难吗,湖南科技大学考研难吗
  7. Hive建外表操作以及其它修改表操作 hive外表与内表区别
  8. 答题器——游戏工作室的亲密搭档!
  9. Android开发英语单词积累
  10. 安装思源笔记/siyuan插件pandoc
  11. 每日三思:优化微信小程序中倒计时占内存较大(19-0612-1917)
  12. python做excel数据分析带gui_Python进阶量化交易专栏场外篇25-GUI工具实现excel功能...
  13. android 点击变色的两种情况、textview点击变色以及自定义checkbox
  14. ARM架构下使用NEON向量化指令集入门基础
  15. 透视变换完成目标跟踪物体速度测试
  16. matlab保存数据用什么指令_MATLAB文件操作及保存文件save load fopen | 学步园
  17. Windows下SVN的Server+Client的安装
  18. houdini使用数字资产hda文件
  19. UR5构型机械臂正逆运动学
  20. 大数据用户画像实战之业务数据调研及ETL

热门文章

  1. iOS 中的CoreImage框架(framework)
  2. python连接服务器怎么用_使用Python连接到远程服务器
  3. gd mysql_简单的图形计数器需要MYSQL,GD的支持_MySQL
  4. 教程:4、文件权限和访问方式
  5. argument在python里什么意思_在Python中星号*是什么意思?
  6. php管理txt文件系统,PHP文件系统管理详解
  7. mqtt 负载均衡_EMQ百万级MQTT消息服务(分布式集群)
  8. vbs 服务器获取输入信息,取得服务器上用户组列表脚本之VBS版
  9. excel总行数 java_计算Excel工作表列中的行数(提供的Java代码)
  10. c 普通的文本变成注释文本的快捷键_2019年IntelliJ IDEA快捷键终极大全,绝版!速度收藏!...