`
ouyangfei0426
  • 浏览: 126857 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

JavaScript面向对象的继承机制——原型式继承

 
阅读更多

JavaScript面向对象的继承机制——原型式继承

前言

         上篇文章说了一下类式继承,今天来说一下JavaScript的另一种继承机制——原型式继承,之所以过了这么久才写原型式继承,一是因为时间问题,二是因为,我不知道该怎么组织语言来说清楚原型式继承,原型式继承本身的实现是很简单的,但是其牵涉到的概念以及原理却不好说明白。原型式继承与类式继承截然不同。原型的本质是就是一个对象,所以说起原型继承时,我们最好忘掉关于类式继承的类与实例的相关知识。

原型式继承

         在介绍原型式继承之前,有必要先说一下原型以及原型链的概念,因为原型式继承是基于原型与原型链实现的。

原型

         原型是什么?原型该如何定义?我们创建一个新的构造函数(为方便描述,这里称其为对象A)时,JavaScript都会根据特定的规则为该函数创建一个prototype属性,该属性为指向一个对象(对象B)的引用,这个对象就是函数的原型,而且这个原型包含且一个名为constructor属性,默认情况下,JavaScript产生的原型,其constructor属性的值为指向该函数的一个引用,用表达式表示即为:

         A. prototype==B;

         B. constructor==A;

         可是当我们改变prototype属性的值时,也就是变更其原型为其他对象(对象C)时,这时由于C可能没有constructor属性或者其constructor属性不再是A,我们需要再修正Cconstructor属性的值:

         C. constructor=A;

         这一点在上一篇文章中《JavaScript面向对象继承机制——类式继承》也有说到。

         当调用构造函数创建一个新实例后,该实例的内部将包含一个指针(内部属性,该内部属性在有的实现中名字是_proto_,并且可以访问到,但在有的实现中不可访问到,但确实存在),指向构造函数的原型,其用表达式表述为:

         var a1=new A();

         a1.proto_==A. prototype==B;

ABa1a2a1a2A的实例对象)的关系可以通过下图来进行表述:



 

 

图画的不是很好,但我想基本能表达出图中几个对象之间的关系,在图中我额外加了两个对象,一个是Object对象,一个Object对象的原型。之所以加这两个对象,就是想表述所有函数的默认原型都是Object的实例。因此默认原型的内部指针_proto_指向Object.prototype,这也正是自定义类型默认都会有toString()方法与valueOf()方法等的根本原因。

关于实例对象与原型的观点我是这么看的:

原型本质上只是一个实例对象,而实例对象本质上也只是一个指向其原型的(不是构造函数),并持有一个成员列表的结构。

原型链

         理解了原型对于原型链的理解就轻松了,由于原型的本质是一个对象,而对象的本质是一个指向其原型的(不是构造函数),并持有一个成员列表的结构。也就是说,一个对象的原型,会有其自己的原型,如此递推,直到某个原型对象的原型为Object的实例对象,也即达到了最后一个对象节点,这就构成了一条链表结构,这就是原型链。

         当我们以如下代码的方式取得一个对象的属性值时:

         Var a=new A(…);

         var name=a.name;

         JavaScript会先在对象a的成员列表中查找name属性,如果找到了,则返回其值,如果没有找到,则会沿着对象a的内部属性_proto_属性,去其引用的原型对象b的成员列表中查找name属性,如果找到,则返回name的值,如果没有找到则继续去对象b的内部属性_proto_指向的原型的成员列表中去查找,如此反复,直到如果其中某个原型对象的原型为Object的实例对象,如果还是没有找到,则返回undefined,否则返回name属性的值。这就是整个原型链在JavaScript中最最基本的一种使用方式。

原型式继承

我们知道基于类的办法来创建一个对象包含两个步骤,第一,定义一个类;第二,实例化该类以创建一个新对象,用这种方式创建的对象都有一套该类的所有实例属性的副本,但每个实例方法却是所有实例对象共享的,只有一份,只是每个实例对象都有一个指向该实例方法的引用,实际上这个引用也可以看作是实例对象的实例属性。

使用原型式继承时,并不需要定义类,只需直接创建一个对象即可,这个对象随后可以被其他新的对象重用,这主要得益于原型链(关于原型链的有关概念,会在文章结尾给于解说,有兴趣的朋友可以先去看那部分的知识,再回头继续接下来的内容)的查找机制,该对象即被称为原型对象。原型对象为其他对象应有的结构提供了一个模型或者说原型,这也是原型式继承这个名称的由来。

接下来我们首先演示一下使用原型式继承来重新设计实现上篇文章中的PersonMan

 

/**

 * Person原型对象

 */

 var Person={

    name:"default name",

    getName:function(){

       return this.name;

    }

};

 

这里并没有定义一个Person的类,只是定义了一个Person对象字面量。然后我们可以定义一个Man类继承Person

/**

  * Man类继承自Person

  * @param {Object} wife

  */

 function Man(wife){

    this.wife=wife;

    this.getWife=function(){

       return this.wife;

    }

 }

 Man.prototype=Person;

 

上面的代码最后的一句就实现了ManPerson的继承。非常简单的继承方式!

而实际上我们可以有一种更简单的方式来实现这种继承,即编写一个clone函数:

/**

  * 返回一个继承了Object对象的对象!

  * @param {Object} object

  */

 function clone(object){

    function F(){};

    F.prototype=object;

    return new F();

 }

 

如下要取得继承Person的对象只需下面一句话即可:

var a1=clone(Person);

alert(a1.getName());//输出:default name

 

原型式继承与类式继承对比

JavaScript中类式继承与原型式继承是两种完全不同的继承方式,他们生成的对象也有不同的行为方式,两种继承方式各有其优缺点。

类式继承更加符合我们接触到的类似Java语言那样的继承机制,虽然只是一个模仿,但是更容易为熟悉Java等类似的面向对象的编程语言的程序员所接受。

原型式继承更能节约内存,原型链读取成员的方式使得所有克隆出来的对象都共享每个属性与方法的唯一一份实例。只有在直接设置了某个克隆出来的对象的属性或者方法时,情况才会发生改变,但是原型式继承的这种优势在某些情况下因为其对继承而来的成员的读与写的不对等性,在有共享的引用型属性时,这种优势又会变为原型式继承的一种劣势,限于时间、精力以及个人水平,这里不多做解说。有兴趣的兄弟们可以与我交流。

 

结语

         JavaScript看似只是一种脚本语言,可是其复杂性并不简单,因为JavaScript的入门极易造成了其给人极其简单的假象,实际上,JavaScript也是一门极其精深的编程语言,由于时间、精力、以及个人水平的问题,很多地方本人可能说的都不是很清晰,或者比较简略,但是我已经尽自己的能力来尽量的想方设法的去描述清楚自己想要表达的意思,如果有疑问的兄弟,可以与本人互相交流学习。

  • 大小: 42.6 KB
分享到:
评论
1 楼 nidongsheng 2017-07-07  
有点乱....看了这篇文章终于看明白些了:http://www.qianduanzaixian.com/detail.do?id=131;JavaScript的继承还是蛮有意思的。 

相关推荐

    学习javascript面向对象 javascript实现继承的方式

    实际上不是SubType的原型的constructor属性被重写了,而是SubType的原型指向了另一个对象——SuperType的原型,而这个原型对象的construtor属性指向的是SuperType function SuperType(){ this.property = true; }...

    深入理解javascript原型链和继承

    在上一篇文章中,介绍了原型的概念,了解到在javascript中构造函数、原型对象、实例三个好基友之间的关系:每一个构造函数都有一个“守护神”——原型对象,原型对象心里面也存着一个构造函数的“位置”,两情相悦,...

    javascript面向对象三大特征之继承实例详解

    本文实例讲述了javascript面向对象三大特征之继承。分享给大家供大家参考,具体如下: 继承 在JavaScript中的继承的实质就是子代可以拥有父代公开的一些属性和方法,在js编程时,我们一般将相同的属性放到父类中,...

    JavaScript面向对象的程序设计(犯迷糊的小羊)

    本章开始进入JavaScript核心知识点的高级部分——面向对象的程序设计,这一部分的内容将会对对象这一数据类型做进一步的深化理解,并且讲述几种创建对象的设计模式以及JavaScript独特的继承机制; 1.理解对象和面向...

    写给大家看的面向对象编程书(第3版).[美]Matt Weisfeld(带详细书签).pdf

    1.2 从过程式开发转向面向对象开发 4 1.2.1 过程式程序设计 5 1.2.2 OO程序设计 5 1.3 对象到底是什么 5 1.3.1 对象数据 5 1.3.2 对象行为 6 1.4 类到底是什么 9 1.4.1 类是对象模板 9 1.4.2 属性 11 ...

    不用构造函数(Constructor)new关键字也能实现JavaScript的面向对象

    那是因为JavaScript试图去隐藏它传统的面向对象的特性——最终导致了它的双重人格(译者注:作者意思是JavaScript既有面向过程的特征,又有面向对象的特征)。 我认为正是由于JavaScript对象模型的难以理解和使用,...

    JS Pro-深入面向对象的程序设计之继承的详解

    一般的面向对象程序语言,有两种继承方法——接口继承(interface inheritance)和实现继承(implementation inheritance)。接口继承只继承方法签名,而实现继承则继承实际的方法。在JavaScript中,函数没有签名,...

    阿里巴巴技术文章分享 Javascript继承机制的实现

    Javascript作为一门脚本语言,在设计之初并没有考虑到面向对象的特性。即便到了当今这个遍布现代浏览器的年代,各种Javascript 框架/库如雨后春笋般地疯狂生长,Javascript中连个 class 关键字都没有。如果你要编写...

    worldwindjava源码-javascript-oop:面向对象编程和面向对象JavaScript

    中的面向对象编程 学习目标 使用构造函数生成特定类型的对象。 使用构造函数将属性附加到新对象。 回想一下在构造函数中定义方法的成本。 通过将自定义对象附加到原型来定义自定义对象的方法。 使用 ES6 类语法重构...

    玩转JavaScript OOP – 类的实现详解

    对象和类是面向对象的基础,封装、继承和多态是面向对象编程的三大特性。 JavaScript提供了对象却缺乏类,它不能像C#一样能显式地定义一个类。 但是JavaScript的函数功能非常灵活,其中之一就是构造函数,结合构造...

    tangramjs:在 JavaScript 中用于无类面向对象编程的库

    我曾经认为 JavaScript 的重要创新是原型继承。 我现在认为它是无类的面向对象编程。 我认为这是 JavaScript 给人类的礼物。 这就是使它真正有趣、特别和重要的语言的原因。 ——内容 入门 安装npm install ...

    JS继承与闭包及JS实现继承的三种方式

    我们都知道,面向对象的三大特征——封装、继承、多态。 封装无非就是属性和方法的私有化,所以我们JS中提供了私有属性和私有方法。 而JS中并没有多态,因此我们说JS是一门基于对象的语言,而非面向对象的语言。 ...

    javascript学习笔记.docx

    11) JavaScript中面向对象的特性: a) 实例属性:在构造函数创建或初始化的属性。 b) 实例方法:在构造函数中把原型对象中的一个属性设为函数来实现。 c) 类属性:构造函数本身的属性。 d) 类方法:用合适的函数作为...

    JavaScript类的写法

    早期的javascript需求都很简单,基本都是写成函数的,然后是面向过程的写法,后来慢慢的引入面向对象开发思想,再后来就慢慢写成类。 在js中,写成类的本质基本都是 构造函数+原型。下面,就讨论一下js类的几种写法...

    程序员面试刷题的书哪个好-front-end-interview:前端面试

    数据类型、面向对象、继承、闭包、插件、作用域、跨域、原型链、模块化、自定义事件、内存泄漏、事件机制、异步装载回调、模板引擎、Nodejs、JSON、ajax 等。 1.浅拷贝和深拷贝的区别 2.defer 和 async 的区别(JS ...

    java俄罗斯方块源码代码最少-JS-Apps-Online-Team-Fortress-:JSApps在线团队“堡垒”

    使用对象、模块和数据隐藏的应用程序逻辑原型继承和经典继承都可以 至少3个模块 至少 7 类对象 单元测试使用 , 和 为您的应用程序实现 UI 使用 KendoUI、jQueryUI 或实现您自己的 UI 逻辑 使用某种网络数据

    asp.net知识库

    动态调用对象的属性和方法——性能和灵活性兼备的方法 消除由try/catch语句带来的warning 微软的应试题完整版(附答案) 一个时间转换的问题,顺便谈谈搜索技巧 .net中的正则表达式使用高级技巧 (一) C#静态成员和...

    深入浅出ES6 简体中文

    类的加入虽然有助于其它语言的使用者开始使用JavaScript,但是却无法发挥出JavaScript原型继承的巨大优势);以及为了保持非侵入式弥补其它新特性而诞生的Symbols。 其它的新特性也相当诱人,熟练掌握可以大幅度提升...

    【卷一/共两卷】AJAX实战pdf高清版90M

    附录B 面向对象程序员Javascript指南 B.1 JavaScipt不是Java B.2 JavaScript中的对象 B.2.1 创建即时对象 B.2.2 构造函数、类和原型 B.2.3 扩展内建类 B.2.4 原型的继承 B.2.5 JavaScijpt对象的反射 B.2.6 接口和...

    JavaScript高级教程

    3.1.1 面向对象语言的要求..............................................58 3.1.2 对象的构成..............................................59 3.2 对象应用..............................................59 ...

Global site tag (gtag.js) - Google Analytics