今天呢,我们来谈谈继承,它也是JS语言中的一大重点,一般什么时候我们会用继承呢,比如有两个拖拽的面板,两个功能基本一致,只是第二个面板多了一些不同的东西,这个时候,我们就会希望,要是第二个直接能继承第一个面板相同的功能就好了。所以这个时候继承就登场啦。。。

  继承:在原有对象的基础上,略作修改,得到一个新的对象,并且不影响原有对象的功能

在具体讲继承前,首先来了解一个东西,这个东西叫做原型链,是继承的基础。我们先来看一段代码:

function Aaa(){}
Aaa.prototype.num = 3;
var a1 = new Aaa();
alert(a1.num); //3 a1是怎么找到的原型下面的num呢?

这是一个很简单的代码,但是我们有没有想过一个问题,既然我们把变量放到了原型下面,那么a1是怎么找到这个变量的呢?实际上就是通过原型链啦。

原型链是指:实例对象与原型之间的连接,__proto__(它是一种隐式连接 ,我们看不到,但确实存在,a1能跟着这个链找到对应的原型下面的东西)。

看下面的这个图:首先a1先看看自己的下面有没有num,发现没有之后,就会随着原型链,找找找,找到了原型,发现下面有,就弹出了这个num.打开firebug可以看到num是通过原型链中原型下被找到的。

那如果是下面这种情况呢:

function Aaa(){
this.num =10;
}
Aaa.prototype.num = 3;
var a1 = new Aaa();
alert(a1.num); //

我们之前讲过原型的优先级是比较低的,其实也是原型链的原因,对象会首先在自己的地盘找,找不到才会从原型链上找,而且最外层的原型链是object,所以上面的意思其实下面就是这样的:

   1 拷贝继承

首先来看个栗子:父类有属性name,age, 方法show,子类有属性name,age,sex,怎么能让子类直接继承父类的属性和方法呢?

对于属性的继承:其实我们可以在子类里面直接调用父类的函数。

方法的继承:因为方法在原型下面,原型本身也是一个对象,我们可以直接把父类的原型对象赋给子类的原型对象。那么子类就会有父类的方法了。

function Create(name,age){
this.name = name;
this.age = age;
}
Create.prototype.show = function(){
alert(this.name);
}
function Create2(name,age,sex){
Create(name,age); //这样调用this指的是window
this.sex = sex;
}
Create2.prototype = Create.prototype; //这样对象赋值会存在引用关系

但是这个方法存在两个问题:

因为在子类中,我们希望的是this指的是当前的对象,但直接这样调用就指的是window,所以我们需要用call()方法修改一下this的指向。

对象复制会存在引用问题,也就是说现在两个对象指向的是同一个地址,其中一个原型的一些东西的更改会影响另一个,这肯定不是我们所希望的。所以我们通过拷贝赋值,来避免引用。

function Create(name,age){
this.name = name;
this.age = age;
}
Create.prototype.show = function(){
alert(this.name);
}
function Create2(name,age,sex){
Create.call(this,name,age);
this.sex = sex;
}
extend(Create2.prototype ,Create.prototype ); //函数之间赋值不会存在引用
Create2.prototype.showJob = function(){}; //不会影响父类
var p2 = new Create2('hua',11,'men');
p2.show(); // hua
function extend(obj1,obj2){
for(var attr in obj2){ //循环遍历对象下面的属性和方法,进行赋值,需要知道的是函数之间的复制是不存在引用的,所以方法之间就不存在引用了
obj1[attr] = obj2[attr];
}
}

这种继承方式叫做拷贝继承。(jquery也是采用拷贝继承extend)

2 类式继承(利用构造函数继承,一句话即可完成继承)

来看下面的代码:

function Aaa(){   //父类
this.name = [1,2,3];
}
Aaa.prototype.showName = function(){
alert( this.name );
};
function Bbb(){ }//子类
Bbb.prototype = new Aaa();
//这句话覆盖了Bbb所有的原型,所以构造函数指向改变(这里不懂的话,参建之前的博客,JS面向对象之创建对象中讲到的constructor)
//这句话就可以让子类找到父类的方法和属性
var b1 = new Bbb();
b1.showName();//弹出[1,2,3]
alert(b1.constructor);//Aaa 可见构造函数指向变了
b1.name.push(4);// 改变b1.name
var b2 = new Bbb();
alert(b2.name) // [1,2,3,4] 由此可见属性存在引用

我们通过看一个图看理解是怎么继承的:

Bbb.prototype = new Aaa(); 这句话,使得图上的a1和Bbb的原型指向了同一个地方,所以当指向b1.showName();这句的时候,它现在自己下寻找有没有这个方法,没有就通过原型链去原型下找,发现也没有,又通过原型链去父级那边找,最终就找到了。

不过通过注释可以看到,其实这种方法其实是存在一些问题的:

1 构造函数指向问题      2 属性存在引用

解决:1 修正构造函数指向  2 方法和属性(call)分开继承
代码如下:1 属性继承和拷贝继承一样,通过构造函数调用继承  2 方法继承,通过中间人来做到之继承方法(看注释应该能懂,也可以自己试着画原型链图理解)
function Aaa(){ //父类
this.name = [1,2,3];
}
Aaa.prototype.showName = function(){
alert( this.name );
};
function Bbb(){ //子类
Aaa.call(this); //属性继承
}
var F = function(){}; //声明空的构造函数,中间媒介
F.prototype = Aaa.prototype;//把Aaa的原型赋给F,这个时候F会拥有Aaa原型下所有的方法
Bbb.prototype = new F(); //这个同上,Bbb会用于F的所有方法和属性,因为上一句复制F只是拥有了Aaa的方法,所以这里实质上Bbb拥有的也只是Aaa的方法
Bbb.prototype.constructor = Bbb; //修正指向问题
var b1 = new Bbb();
b1.name // [1,2,3]
b1.constructor;//Bbb 指向正常
b1.name.push(4);
var b2 = new Bbb();
b2.name // [1,2,3] 属性互相不影响

3 原型继承(借助原型来实现对象继承对象)

var a = {
name : '小明'
}; var b = cloneObj(a); b.name = '小强';
alert( b.name );//小强 会优先在自己的下面找name
alert( a.name );//小明
function cloneObj(obj){
var F = function(){}; //声明一个构造函数
F.prototype = obj; //F原型下拥有obj的方法和属性
return new F(); // 返回声明通过F声明的对象,通过上一句知道,这个对象具有obj的方法和属性
}

以上就是三种继承方法,其实也有别的,后续可以继续补充,对于继承也许用的不是很多,但对理解JS语言还是很重要的。一起加油把。

												

浅谈JS继承的更多相关文章

  1. 【前端笔记】浅谈js继承

    我们先想想我们用js最后要怎样实现面向对象的编程.事实上我们必须用上原型链这种东西. 我们的父类superType有属性和方法,并且一些能被子类subType继承,一些能被覆盖,但是丝毫不会影响到父类 ...

  2. 浅谈JS面向对象

    浅谈JS面向对象 一 .什么是面向过程 就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用的时候一个一个依次调用就可以了.注重代码的过程部分. 二.什么是面向对象 最先出现在管理学 ...

  3. 浅谈JS之AJAX

    0x00:什么是Ajax? Ajax是Asynchronous Javascript And Xml 的缩写(异步javascript及xml),Ajax是使用javascript在浏览器后台操作HT ...

  4. 浅谈JS中的闭包

    浅谈JS中的闭包 在介绍闭包之前,我先介绍点JS的基础知识,下面的基础知识会充分的帮助你理解闭包.那么接下来先看下变量的作用域. 变量的作用域 变量共有两种,一种为全局变量,一种为局部变量.那么全局变 ...

  5. 浅谈 js 正则字面量 与 new RegExp 执行效率

    原文:浅谈 js 正则字面量 与 new RegExp 执行效率 前几天谈了正则匹配 js 字符串的问题:<js 正则学习小记之匹配字符串> 和 <js 正则学习小记之匹配字符串优化 ...

  6. 浅谈 js 字符串之神奇的转义

    原文:浅谈 js 字符串之神奇的转义 字符串在js里是非常常用的,但是你真的了解它么?翻阅<MDN String>就可以了解它的常见用法了,开门见山的就让你了解了字符串是怎么回事. 'st ...

  7. 浅谈 js 正则之 test 方法

    原文:浅谈 js 正则之 test 方法 其实我很少用这个,所以之前一直没注意这个问题,自从落叶那厮写了个变态的测试我才去看了下这东西.先来看个东西吧. var re = /\d/; console. ...

  8. 浅谈 js 数字格式类型

    原文:浅谈 js 数字格式类型 很多人也许只知道 ,123.456,0xff 之类的数字格式.其实 js 格式还有很多数字格式类型,比如 1., .1 这样的,也有 .1e2 这样的. 可能有人说这是 ...

  9. 浅谈 js 语句块与标签

    原文:浅谈 js 语句块与标签 语句块是什么?其实就是用 {} 包裹的一些js代码而已,当然语句块不能独立作用域.可以详细参见这里<MDN block> 也许很多人第一印象 {} 不是对象 ...

随机推荐

  1. 挖一挖C#中那些我们不常用的东西之系列(2)——IsXXX 系列方法

    不知道有人做没做过对日外包,如果做过的话,那么对vb.net应该非常熟悉了,当年我刚毕业的时候也做过四个月的外包,那种日子简直 不是人过的,就连大楼下面买珠宝的阿姨都说,这些孩子,只看过他们上班,就没 ...

  2. 数据库 SQL Server 到 MySQL 迁移方法总结

    最近接手一起老项目数据库 SQL Server 到 MySQL 的迁移.因此迁移前进行了一些调查和总结.下面是一些 SQL Server 到 MySQL 的迁移方法. 1. 使用 SQLyog 迁移 ...

  3. [SqlServer]创建链接服务器

    把一个数据库中数据表中的内容,从一个SQL SERVER服务器 导出到另一个SQL Server服务器 不同服务器数据库之间的数据操作 --创建链接服务器  exec sp_addlinkedserv ...

  4. Hadoop环境常用命令

    用户可以通过dfsadmin -safemode value   来操作安全模式,参数value的说明如下: enter - 进入安全模式 leave - 强制NameNode离开安全模式 get - ...

  5. x01.Game.Main: 从零开始

    一切从零开始,一切皆有可能. 浅墨,90后,<逐梦之旅>深入浅出,堪比大师. 1.安装 DXSDK_June10.exe 或更新版本. 2.运行 vs2012,新建 VC Win32 空项 ...

  6. docker-5 docker仓库

    docker部署环境:CentOS release 6.5 (Final) Docker配置文件:/etc/sysconfig/docker  重要参数解释: -H 表示Docker Daemon绑定 ...

  7. [转载] Linux启动过程详解-《别怕Linux编程》之八

    本原创文章属于<Linux大棚>博客,博客地址为http://roclinux.cn.文章作者为rocrocket.为了防止某些网站的恶性转载,特在每篇文章前加入此信息,还望读者体谅. = ...

  8. [转]ASP.Net篇之Session与Cookie

    本文转自:http://www.cnblogs.com/japanbbq/archive/2011/08/31/2160494.html Session: Session是“会话”的意思,然而,因为h ...

  9. ARM学习篇 SDRAM理解

    1.SDRAM单管存储单元 SDRAM单管电路图 C记忆单元 T控制门管 Z字线 W位线 注:图示为N沟道耗尽型MOS管 写入:Z加高电平,MOS导通,W状态决定了电容C的状态 读出:Z加高电平,MO ...

  10. 150924-还是起得来床的好-HTML(CSS)

    一早醒来是9:10,这些天最晚的了,也可能是睡的最爽的了. 不废话,早上Matlab仿真干不出来,不如学学html,上代码~ <!DOCTYPE HTML><html>< ...