JS继承

    继承是OO语言中最为人津津乐道的概念,许多OO语言都支持两种方式的继承:接口继承;实现继承。

       接口继承:只继承方法签名。

       实现继承:继承实际的方法。

    由于ES里函数没有签名,所以在ES里面无法实现接口继承,ES只支持实现继承。

                                                                                                                                              ——《js高程》 

  根据高程上面的介绍,结合自己的理解,来谈一谈js中的继承。

1.原型链

  基本思想是利用原型让一个引用类型继承另一个引用类型的属性和方法。

          

      function car() {
this.name = name || '车';
this.Oncar=['小明','小红'];//车上的人 this.drive =function(){
console.log(this.name +'在行驶');
}
} function dazhong() {
this.V = 200;
this.chesu = function() {
console.log('车速是'+this.V+'km/h');
} } dazhong.prototype = new car();//继承 var Dz1 = new dazhong();
Dz1.name = '大众suv';
Dz1.drive();//大众suv在行驶
Dz1.Oncar.push('大白');//为大众suv加一个乘客
console.log(Dz1.Oncar);//["小明", "小红", "大白"] var Dz2 =new dazhong();
Dz2.name = '冒牌大众';
Dz2.drive();//冒牌大众在行驶
console.log(Dz2.Oncar);//["小明", "小红", "大白"] 冒牌大众上居然也共享了这个乘客!

  利用原型链的方法,我们可以方便的实现继承,但是有一个问题,那就是 所有的实例共享了引用类型的值!

  只是引用类型的值共享了,实例中非引用类型的值并没有共享。(Dz1.drive和Dz2.dirve 不一样);

  为了解决原型中包含引用类型值所带来的问题,又推出了另外一种方法: 借用构造函数(constructor stealing)

2.借用构造函数

  基本思想是  在子类型构造函数的内部调用超类型构造函数。

  函数只不过是在特定环境中执行代码的对象,因此通过使用apply()和call()方法也可以在新创建的对象上执行构造函数。

        function dazhong() {

            car.call(this);//继承

            this.V = 200;
this.chesu = function() {
console.log('车速是'+this.V+'km/h');
} } var Dz1 = new dazhong();
Dz1.name = '大众suv';
Dz1.drive();//大众suv在行驶
Dz1.Oncar.push('大白');//为大众suv加一个乘客
console.log(Dz1.Oncar);//["小明", "小红", "大白"] var Dz2 =new dazhong();
Dz2.name = '冒牌大众';
Dz2.drive();//冒牌大众在行驶
console.log(Dz2.Oncar);//["小明", "小红"]

  通过这种方法,可以在子类型构造函数里向超类型构造函数里传值啦。

function car(driver) {
this.name = name || '车';
this.Oncar=['小明','小红'];//车上的人 this.driver = driver; this.drive =function(){
console.log(this.name +'在行驶');
}
} function dazhong() { car.call(this,'小明');//继承 this.V = 200;
this.chesu = function() {
console.log('车速是'+this.V+'km/h');
} } var dz1 = new dazhong();
console.log('司机是'+ dz1.driver);//司机是小明 var dz2 =new dazhong();
dz2.driver = '小红';
console.log('司机是'+ dz1.driver);//司机是小明
console.log('司机是'+ dz2.driver);//司机是小红 console.log(dz1 instanceof car);//false dz1 并不是 car 的实例
console.log(dz1 instanceof dazhong);//true dz1 是 dazhong 的实例

  借用构造函数的办法虽然解决了传值和引用类型不共享的问题,但是他依然存在着构造函数模式存在的问题——函数无法复用。

  方法都写到了构造函数中,对内存是一种损耗。 所以这时候又引出了另外一种方法: 组合继承

3.组合继承

  组合继承其实是将之前的两种继承方式结合起来,各取其长的继承方式。

  核心思想是 使用原型链实现对原型属性和方法的继承,而通过借用构造函数来实现对实例属性(每个实例各自不同的东西)的继承。

function car(driver) {
this.name = name || '车';
this.Oncar=['小明','小bai'];//车上的人
this.driver = driver;
} car.prototype.drive = function() {
console.log('司机'+this.driver+'驾驶着'+this.name+',在高速公路上');
}; function dazhong(driver,v) { car.call(this,driver);//继承 this.V = v || 0; } // 继承
dazhong.prototype = new car();
dazhong.prototype.constructor = dazhong;
dazhong.prototype.chesu = function() {
console.log('车速是'+this.V+'km/s');
}; var dz1 = new dazhong('小明',100);
dz1.name = '斯柯达';
dz1.Oncar.push('小黑');//["小明", "小bai", "小黑"]
dz1.drive();//司机小明驾驶着斯柯达,在高速公路上
dz1.chesu();//车速是100km/s
console.log(dz1.Oncar); var dz2 =new dazhong('小红',40);
dz2.name = '高尔夫';
dz2.Oncar.push('小红');
dz2.drive();//司机小红驾驶着高尔夫,在高速公路上
dz2.chesu();//车速是40km/s
console.log(dz2.Oncar);//["小明", "小bai", "小红"] console.log(dz1 instanceof car);//true
console.log(dz1 instanceof dazhong);//true
console.log(dz2 instanceof car);//true
console.log(dz2 instanceof dazhong);//true

  组合继承的方式是现在js里常用的继承方式。

4.原型式继承

  function object(o){
    function F(){ }
    F.prototype = o;
    return new F();
  }

在object()函数内部,先创建了一个临时性的构造函数,然后将传入的对象作为这个构造函数的原型,最后返回了这个临时类型的一个新实例。从本质上讲,object()对传入其中的对象执行了一次浅复制。                          ——《js高程》

  在高程里面讲的原型式的继承就是这个原理。而ES5新增了 Object.create() 方法 规范化了原型式继承。

 

        var car ={
name:"车",
Oncar:['小明','小白'],
driver:'人', drive: function() {
console.log('司机'+this.driver+'驾驶着'+this.name+',在高速公路上');
}
} var dz1 = Object.create(car);//继承
dz1.name = '斯柯达';
dz1.driver = '小明';
dz1.V = 200; dz1.Oncar.push('小黑');
dz1.chesu = function() {
console.log('车速为'+this.V+'km/h');
} dz1.drive();//司机小明驾驶着斯柯达,在高速公路上
dz1.chesu();//车速为200km/h
console.log(dz1.Oncar);//["小明", "小白", "小黑"] var dz2 = Object.create(car);
dz2.name = '高尔夫';
dz2.driver = '小红';
dz2.V = 40; dz2.Oncar.push('小白');
dz2.chesu = function() {
console.log('车速为'+this.V+'m/s');
} dz2.drive();//司机小红驾驶着高尔夫,在高速公路上
dz2.chesu();//车速为40km/h
console.log(dz2.Oncar);//["小明", "小白", "小黑", "小白"]

  和原型链的方式一样,原型式继承依然存在 引用类型变量共享的问题。

5.寄生式继承

  寄生式继承是与原型式继承紧密相关的一种思路,创建一个仅用于封装继承过程的函数,该函数在内部用某种方式来增强对象,最后再像其他真地是它做了所有工作一样返回对象

 

    function object(oo){
   function F(){}
   F.prototype = oo;
   return new F();
   }   function jicheng(o) {
   var clone = object(o);    clone.drive =function() {
   console.log('司机'+this.driver+'驾驶着'+this.name+',在高速公路上'); //强化...
   };
   return clone;
   }
var car ={
name:"车",
Oncar:['小明','小白'],
driver:'人', } var dz1 = jicheng(car);//继承
dz1.name = '斯柯达';
dz1.driver = '小明';
dz1.V = 200; dz1.Oncar.push('小黑');
dz1.chesu = function() {
console.log('车速为'+this.V+'km/h');
} dz1.drive();//司机小明驾驶着斯柯达,在高速公路上
dz1.chesu();//车速为200km/h
console.log(dz1.Oncar);//["小明", "小白", "小黑"]

  可是我觉得...这个方法好像和原型式继承差不多(没啥用)....希望大佬们能给出这个方法存在的意义...

6.寄生组合式继承

  据说是很棒的继承方式,就是写法比较复杂...寄生组合继承是对组合继承的改进.为什么要对组合继承进行改进呢?

  因为在组合继承里面,无论什么情况下,都会调用两次超类构造函数。

     function a(name) {
this.name = name;
this.type = [1,2,3];
} a.prototype.sayName = function() {
console.log(this.name);
}; function b(name,age){ a.call(this,name);//第二次调用a()
this.age = age;
} b.prototype = new a();//第一次调用a()
b.prototype.constructor = b;
b.prototype.sayAge =function(){
console.log(this.age);
}

注释部分,第一次调用a构造函数的时候 b.prototype 会得到两个属性:name 和 type,他们位于b的原型里面。

第二次调用a的时候 则是在新对象上面创建了属性name 和type。新实例上面的name 和 type 屏蔽了原型中的name 和 type。因此就引出了 寄生组合式继承

其基本思想是 通过借用构造函数来继承属性,通过原型链的混成形式来继承方法。

        function object(o){
function F(){};
F.prototype = o;
return new F();
} function jsInherit(zi,chao){
var proto = object(chao.prototype);//创建对象
proto.constructor = zi;//增强对象
zi.prototype = proto;//指定对象
} function car(driver) {
this.name = name || '车';
this.Oncar=['小明','小bai'];//车上的人
this.driver = driver;
} car.prototype.drive = function() {
console.log('司机'+this.driver+'驾驶着'+this.name+',在高速公路上');
}; function dazhong(driver,v) { car.call(this,driver);//继承 this.V = v || 0; } jsInherit(dazhong,car); dazhong.prototype.chesu = function () {
console.log('车速是'+this.V+'km/h');
} var a = new dazhong('大白',69);
a.name = 'suv'; a.drive();
a.chesu();
a.Oncar.push('大白');

以上就是我根据 js高程 里的内容结合自己的实践谈的js的继承,如果有什么地方不合理的希望大佬们指出来。

结合着这篇文章来看继承,会有更多的收获!

xiexiedajia

      

    

    

  

 

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

  1. 浅谈js中继承的理解和实现

    一.前言 java.C#等正统面向对象语言都会提供类似extend之类的处理类的继承的方法,而javascript并没有提供专门的方法用于继承,在javascript中使用继承需要一点技巧.js中实例 ...

  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. Linux,activemq-cpp之消息过滤器

    假设过滤器字符串如下: filt1=aaaa filt2=bbbb filt3=cccc activeMQ-cpp中消息过滤器,在发送消息的producer.cpp中,对message进行属性设置,m ...

  2. 《深入理解Java虚拟机》虚拟机类加载机制

    上节学习回顾 上一节,我们深入到类文件去了解其结构细节,也大概对类文件的编写规则略知一二了,解析来我们就得学习这个类文件是如何被加载到Java虚拟机的,看看有什么引人入胜的奥秘. 本节学习重点 大部分 ...

  3. ORACLE - 管理重做日志文件

    ORACLE重做日志文件用于在数据库崩溃等情况下用于恢复数据,默认情况下为三个文件redo01.log/redo02.log/redo03.log,文件组循环使用,在录入与更新操作比较多的应用中,日志 ...

  4. Hibernate批量操作(二)

    Hibernate提供了一系列的查询接口,这些接口在实现上又有所不同.这里对Hibernate中的查询接口进行一个小结. 我们首先来看一下session加载实体对象的过程:Session在调用数据库查 ...

  5. 到底什么样的企业才适合实施SAP系统?

    SAP系统作为全宇宙第一的ERP,号称世界500强里面有80%的企业部署了SAP系统,总部位于德国沃尔多夫市,在全球拥有6万多名员工,遍布全球130个国家,并拥有覆盖全球11,500家企业的合作伙伴网 ...

  6. git远程仓库之从远程库克隆

    上次我们讲了先有本地库,后有远程库的时候,如何关联远程库. 现在,假设我们从零开发,那么最好的方式是先创建远程库,然后,从远程库克隆. 首先,登陆GitHub,创建一个新的仓库,名字叫gitskill ...

  7. ansible批量分发免密钥登陆python脚本

    最近看了看强大的号称自动化运维的三大利器之一的--ansible,ok,亲测之后,确实感觉,对于我们这种DBA工作者来说,确实很受益. 值得注意的是ansible要求被管理服务器python版本不低于 ...

  8. Luogu P2690 接苹果

    题目背景 USACO 题目描述 很少有人知道奶牛爱吃苹果.农夫约翰的农场上有两棵苹果树(编号为1和2), 每一棵树上都长满了苹果.奶牛贝茜无法摘下树上的苹果,所以她只能等待苹果 从树上落下.但是,由于 ...

  9. .NET并行计算和并发2-Foreground and Background Threads

    后台线程不会使托管执行环境处于运行状态,除此之外,后台线程与前台线程是一样的. 一旦所有前台线程在托管进程(其中 .exe 文件是托管程序集)中被停止,系统将停止所有后台线程并关闭.

  10. Oracle维护:每天的工作

    Oracle维护:每天的工作 检查数据库状态 确认所有的INSTANCE状态以及listener状态正常,登陆到所有数据库或例程,检测ORACLE后台进程: $ ps –ef|grep ora $ l ...