详解JavaScript基于面向对象之继承

一、面相对象继承机制
      这个实例使用UML很好的解释了继承机制。
      说明继承机制最简单的方式是,利用一个经典的例子就是几何形状。实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边)。圆是椭圆的一种,它只有一个焦点。三角形、矩形和五边形都是多边形的一种,具有不同数量的边。正方形是矩形的一种,所有的边等长。这就构成了一种完美的继承关系,很好的解释了面向对象的继承机制。
       在这个例子中,形状是椭圆形和多边形的基类(通常我们也可以叫它父类,所有类都由它继承而来)。椭圆具有一个属(foci),说明椭圆具有的焦点的个数。圆形继承了椭圆形,因此圆形是椭圆形的子类,椭圆形是圆形的超类。同样,三角形、矩形和五边形都是多边形的子类,多边形是它们的超类。最后,正方形继承了矩形。
      最好用图来解释这种继承关系,这是 UML(统一建模语言)的用武之地。UML的主要用途之一是,可视化地表示像继承这样的复杂对象关系。下面的图示是解释形状和它的子类之间关系的UML图示:

在UML中,每个方框表示一个类,由类名说明。三角形 、矩形和五边形顶部的线段汇集在一起,指向形状,说明这些类都由形状继承而来。同样,从正方形指向矩形的箭头说明了它们之间的继承关系。
二、ECMAScript继承机制的实现
      要用ECMAScript实现继承机制,您可以从要继承的基类入手。所有开发者定义的类都可作为基类。出于安全原因,本地类和宿主类不能作为基类,这样可以防止公用访问编译过的浏览器级的代码,因为这些代码可以被用于恶意攻击。
       选定基类后,就可以创建它的子类了。是否使用基类完全由你决定。有时,你可能想创建一个不能直接使用的基类,它只是用于给子类提供通用的函数。在这种情况下,基类被看作抽象类。尽管ECMAScript并没有像其他语言那样严格地定义抽象类,但有时它的确会创建一些不允许使用的类。通常,我们称这种类为抽象类。
      创建的子类将继承超类的所有属性和方法,包括构造函数及方法的实现。记住,所有属性和方法都是公用的,因此子类可直接访问这些方法。子类还可添加超类中没有的新属性和方法,也可以覆盖超类的属性和方法。由于JS并不是正统的面向对象语言,一些名词也需要做出改变。
三、ECMAScript继承的方式
      ECMAScript语言中将被继承的类(基类)称为超类型,子类(或派生类)称为子类型。和其他功能一样,ECMAScript实现继承的方式不止一种。这是因为JavaScript中的继承机制并不是明确规定的,而是通过模仿实现的。这意味着所有的继承细节并非完全由解释程序处理。作为开发者,你有权决定最适用的继承方式。下面为您介绍几种具体的继承方式。
(1)原型链方式
      继承这种形式在ECMAScript中原本是用于原型链的。上一篇博文已经介绍了创建对象的原型方式。原型链扩展了这种方式,以一种有趣的方式实现继承机制。prototype 对象是个模板,要实例化的对象都以这个模板为基础。总而言之,prototype 对象的任何属性和方法都被传递给那个类的所有实例。原型链利用这种功能来实现继承机制。我们来看一个例子:

function A() {//超类型A中必须没有参数
 this.color = "red";
 this.showColor = function () {
  return this.color;
 };
};
function B() {//子类型B
 this.name = "John";
 this.showName = function () {
  return this.name;
 };
};
B.prototype = new A();//子类型B继承了超类型A,通过原型,形成链条
var a = new A();
var b = new B();
document.write(a.showColor());//输出:blue
document.write(b.showColor());//输出:red
document.write(b.showName());//输出:John

在原型链中,instanceof运算符的运行方式也很独特。对B的所有实例,instanceof为A和B都返回true。ECMAScript的弱类型世界中,这是极其有用的工具,不过使用对象冒充时不能使用它。例如:

var b = new B();
document.write(b instanceof A);//输出:true
document.write(b instanceof B);//输出:true

使用原型链方式实现了继承,但是这种方式无法共享和子类型给超类型传递参数。我们可以借用构造函数方式(也就是对像冒充)的方式来解决这两个问题。
(2)对象冒充方式
      对象冒充方式的其原理如下:构造函数使用this关键字给所有属性和方法赋值(即采用对象声明的构造函数方式)。因为构造函数只是一个函数,所以可使A构造函数成为B的方法,然后调用它。B就会收到A的构造函数中定义的属性和方法。例如,用下面的方式改写上面的例子创建对象A和B:
call()方法

function A(Color) {//创建超类型A
 this.color = Color;
 this.showColor = function () {
   return this.color;
 };
};
function B(Color,Name) {//创建子类型B
 A.call(this, Color);//对象冒充,给超类型传参
 this.name = Name;//新添加的属性
 this.showName =
};
var a = new A("blue");
var b = new B("red", "John");
document.write(a.showColor());//输出:blue
document.write(b.showColor());//输出:red
document.write(b.showName());//输出:John

apply()方法
和上面call()方法唯一的区别就是在子类型B中的代码:
A.call(this,arguments);//对象冒充,给超类型传参 
      当然,只有超类型中的参数顺序与子类型中的参数顺序完全一致时才可以传递参数对象。如果不是,就必须创建一个单独的数组,按照正确的顺序放置参数。
      使用对象冒充方式虽然解决了共享和传参的问题,但是没有原型,复用就更不可能了,所以我们组合上述的两种方式,即原型链方式和对象冒充的方式实现JS的继承。
(3)混合方式
      这种继承方式使用构造函数定义类,并非使用任何原型。对象冒充的主要问题是必须使用构造函数方式,这不是最好的选择。不过如果使用原型链,就无法使用带参数的构造函数了。开发者如何选择呢?答案很简单,两者都用。由于这种混合方式使用了原型链,所以instanceof运算符仍能正确运行。
       在上一篇文章,创建对象的最好方式是用构造函数定义属性,用原型定义方法。这种方式同样适用于继承机制,用对象冒充继承构造函数的属性,用原型链继承prototype对象的方法。用这两种方式重写前面的例子,代码如下:

function A(Color) {
 this.color = Color;
};
A.prototype.showColor = function () {
 return this.color;
};
function B(Color, Name) {
 A.call(this, Color);//对象冒充
 this.name = Name;
};
B.prototype = new A();//使用原型链继承
B.prototype.showName = function () {
 return this.name;
};
var a = new A("blue");
var b = new B("red", "John");
document.write(a.showColor());//输出:blue
document.write(b.showColor());//输出:red
document.write(b.showName());//输出:John

继承的方式和创建对象的方式有一定的联系,推荐使用的继承方式还时原型链和对象冒充的混合方式。使用这种混合方式可以避免一些不必要的问题。
       看这篇文章的时候,必须看一下前面的创建对象的方式:详解JavaScript基于面向对象之创建对象(1)详解JavaScript基于面向对象之创建对象(2)

以上就是本文的全部内容,希望对大家的学习有所帮助。

(0)

相关推荐

  • Javascript面向对象之四 继承

    复制代码 代码如下: var JsObject = {} || new Object(); JsObject.extend = function(subClass, superClass){ //先判断子类subClass是否已经定义,如果未定义,则重新定义类. if(typeof subClass == "undefined")subClass = function(){}; //如果父类superClass是类,则转化成对象 if(typeof superClass == &quo

  • JS 面向对象之继承---多种组合继承详解

    这一次要讲 组合.原型式.寄生式.寄生组合式继承方式. 1. 组合继承:又叫伪经典继承,是指将原型链和借用构造函数技术组合在一块的一种继承方式. 下面来看一个例子: function SuperType(name) { this.name = name; this.colors = ["red", "blue", "green"]; } SuperType.prototype.sayName = function() { alert(this.n

  • Javascript简单实现面向对象编程继承实例代码

    本文讲述了Javascript简单实现面向对象编程继承实例代码.分享给大家供大家参考,具体如下: 面向对象的语言必须具备四个基本特征: 1.封装能力(即允许将基本数据类型的变量或函数放到一个类里,形成类的成员或方法) 2.聚合能力(即允许类里面再包含类,这样可以应付足够复杂的设计) 3.支持继承(父类可以派生出子类,子类拥有父母的属性或方法) 4.支持多态(允许同样的方法名,根据方法签名[即函数的参数]不同,有各自独立的处理方法) 这四个基本属性,javascript都可以支持,所以javasc

  • javaScript面向对象继承方法经典实现

    JavaScript的出现已经将近20多年了,但是对这个预言的褒贬还是众说纷纭.很多人都说JavaScript不能算是面向对象的变成语言.但是JavaScript的类型非常松散,也没有编译器.这样一来给了程序员很大的自由,也带来了一些缺陷. 虽然JavaScript不算是一门面向对象的语言.但是我们可以模仿着其他语言实现面向对象的方式来实现JavaScript的面向编程. 下面是JavaScript教程中非常经典的继承方法. 复制代码 代码如下: //定义一个Pet对象.通过这一个名称和数量的腿

  • javascript 面向对象封装与继承

    整理一下js面向对象中的封装和继承. 1.封装 js中封装有很多种实现方式,这里列出常用的几种. 1.1 原始模式生成对象 直接将我们的成员写入对象中,用函数返回. 缺点:很难看出是一个模式出来的实例. 代码: 复制代码 代码如下: function Stu(name, score) {             return {                 name: name,                 score: score             }         }    

  • 详解JavaScript基于面向对象之继承实例

    javascript面向对象继承的简单实例: 作为一门面向对象的语言,继承自然是它的一大特性,尽管javascript的面向对象的实现机制和和c#和java这样典型的面向对象不同,但是继承的基本特点还是具有的,简单的说就是获得父级的方法和属性,下面是一段简单的实例,大家有兴趣可以分析一下: window.onload = function(){ function parent(age,name){ this.age = age; this.name = name; } parent.protot

  • 详解JavaScript基于面向对象之继承

    一.面相对象继承机制       这个实例使用UML很好的解释了继承机制.       说明继承机制最简单的方式是,利用一个经典的例子就是几何形状.实际上,几何形状只有两种,即椭圆形(是圆形的)和多边形(具有一定数量的边).圆是椭圆的一种,它只有一个焦点.三角形.矩形和五边形都是多边形的一种,具有不同数量的边.正方形是矩形的一种,所有的边等长.这就构成了一种完美的继承关系,很好的解释了面向对象的继承机制.        在这个例子中,形状是椭圆形和多边形的基类(通常我们也可以叫它父类,所有类都由

  • 详解JavaScript基于面向对象之创建对象(2)

    接着上文<详解JavaScript基于面向对象之创建对象(1)>继续学习. 4.原型方式        我们创建的每个函数都有一个通过prototype(原型)属性,这个属性是一个对象,它的用途是包含可以由特定类型的所有实例共享的属性和方法.逻辑上可以这么理解:prototypt通过条用构造函数而创建的那个对象的原型对象.使用原型的好处就是可以让所有对象实例共享它所包含的属性和方法.也就是说,不必在构造函数中定义对象信息,而是直接将这些信息添加到原型中.        原型方式利用了对象的pr

  • 详解JavaScript基于面向对象之创建对象(1)

    这一次我们深入的学习一下JavaScript面向对象技术,在学习之前,必要的说明一下一些面向对象的一些术语.这也是所有面对对象语言所拥有的共同点.有这样几个面向对象术语: 一.对象        ECMA-262把对象(object)定义为"属性的无序集合,每个属性存放一个原始值.对象或函数".严格来说,这意味着对象是无特定顺序的值的数组.尽管ECMAScript如此定义对象,但它更通用的定义是基于代码的名词(人.地点或事物)的表示. 二.类        每个对象都由类定义,可以把类

  • 详解JavaScript之ES5的继承

    自从有了ES6的继承后,ES5的继承也退出了舞台,在实际开发也不会用得着,但在面试或许用的着: 先看看ES6的继承 class Father{ constructor(a){ console.log(a); } play(){ console.log("aaa"); } static run(){ console.log("static"); } } class Son extends Father{ constructor(){ super(); } } var

  • 详解Javascript 基于长连接的服务框架问题

    目录 背景 Webscoket 封装 FakeHttpServer Context Middleware 请求处理 Quick Start 小结 背景 经常使用 Node 进行服务端开发的同学,想必都知道 Koa 框架.Koa 是一种 http 服务框架,其基于洋葱模型作为基本架构,能够让用户方便快捷地添加中间件,进行业务开发.而 websocket 是一种长连接的服务通信协议,需要自定义通讯 api 进行数据通讯.一般情况下,基于 websocket 的通讯 api 也是遵循一问一答的交互模式

  • 详解JavaScript面向对象实战之封装拖拽对象

    目录 概述 1.如何让一个DOM元素动起来 2.如何获取当前浏览器支持的transform兼容写法 3.如何获取元素的初始位置 5.我们需要用到哪些事件? 6.拖拽的原理 7. 我又来推荐思维导图辅助写代码了 8.代码实现 part1.准备工作 part2.功能函数 part3.声明三个事件的回调函数 9.封装拖拽对象 概述 为了能够帮助大家了解更多的方式与进行对比,我会使用三种不同的方式来实现拖拽. 不封装对象直接实现: 利用原生JavaScript封装拖拽对象: 通过扩展jQuery来实现拖

  • 详解Javascript中prototype属性(推荐)

    在典型的面向对象的语言中,如java,都存在类(class)的概念,类就是对象的模板,对象就是类的实例.但是在Javascript语言体系中,是不存在类(Class)的概念的,javascript中不是基于'类的',而是通过构造函数(constructor)和原型链(prototype chains)实现的.但是在ES6中提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板.通过class关键字,可以定义类.基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能

  • js对象实例详解(JavaScript对象深度剖析,深度理解js对象)

    这算是酝酿很久的一篇文章了. JavaScript作为一个基于对象(没有类的概念)的语言,从入门到精通到放弃一直会被对象这个问题围绕. 平时发的文章基本都是开发中遇到的问题和对最佳解决方案的探讨,终于忍不住要写一篇基础概念类的文章了. 本文探讨以下问题,在座的朋友各取所需,欢迎批评指正: 1.创建对象 2.__proto__与prototype 3.继承与原型链 4.对象的深度克隆 5.一些Object的方法与需要注意的点 6.ES6新增特性 下面反复提到实例对象和原型对象,通过构造函数 new

  • 详解Javascript 中的 class、构造函数、工厂函数

    到了ES6时代,我们创建对象的手段又增加了,在不同的场景下我们可以选择不同的方法来建立.现在就主要有三种方法来构建对象,class关键字,构造函数,工厂函数.他们都是创建对象的手段,但是却又有不同的地方,平时开发时,也需要针对这不同来选择. 首先我们来看一下,这三种方法是怎样的 // class 关键字,ES6新特性 class ClassCar { drive () { console.log('Vroom!'); } } const car1 = new ClassCar(); consol

随机推荐