深入理解javascript混合对象“类”(一)

前言

      javascript是一门面向对象语言,但是与传统面向对象语言不同,javascript原理上并没有类的说法,学习过传统面向对象语言的同学们可能知道,面向类的设计模式有三种:实例化(instantiation)、继承(inheritance)和(相对)多态(polymorphism)。但是这些设计模式无法对应到javascript的对象机制,所以在深入javascript的原理之前,这一章我们将先学习有关面向类的设计模式的相关知识

正文

      类 / 继承描述了一种代码的组织结构形式——一种在软件中对真实世界中问题领域的建模方法。面向对象编程强调的是数据和操作数据的行为本质上是互相关联的(当然,不同的数据有不同的行为),因此好的设计就是把数据以及和它相关的行为打包(或者说封装)起来。这在正式的计算机科学中有时被称为数据结构。

我们可以在软件中定义一个 Vehicle 类和一个 Car 类来对这种关系进行建模。Vehicle 的定义可能包含推进器(比如引擎)、载人能力等等,这些都是 Vehicle 的行为。我们在 Vehicle 中定义的是(几乎)所有类型的交通工具(飞机、火车和汽车)都包含的东西。在我们的软件中,对不同的交通工具重复定义“载人能力”是没有意义的。相反,我们只在 Vehicle 中定义一次,定义 Car 时,只要声明它继承(或者扩展)了 Vehicle 的这个基础定义就行。Car 的定义就是对通用 Vehicle 定义的特殊化。虽然 Vehicle 和 Car 会定义相同的方法,但是实例中的数据可能是不同的,比如每辆车独一无二的 VIN(Vehicle Identification Number,车辆识别号码),等等。这就是类、继承和实例化。 ----《你不知道的javascript》

      类的另一个核心概念是多态,这个概念是说父类的通用行为可以被子类用更特殊的行为重写。实际上,相对多态性允许我们从重写行为中引用基础行为。

“类”设计模式

      你可能从来没把类作为设计模式来看待,讨论得最多的是面向对象设计模式,比如迭代器模式、观察者模式、工厂模式、单例模式,等等。从这个角度来说,我们似乎是在(低级)面向对象类的基础上实现了所有(高级)设计模式,似乎面向对象是优秀代码的基础。
      其实除了面向类编程还有过程化编程,这种代码只包含过程(函数)调用,没有高层的抽象。所以其实类并不是必须的编程基础,而是一种可选的代码抽象。

javascript中的类

      在相当长的一段时间里,JavaScript 只有一些近似类的语法元素(比如 new 和 instanceof),不过在后来的 ES6 中新增了一些元素,比如 class 关键字。但是javascript实际上并没有类,看过之前我写的设计模式系列的同学们可能知道,javascript是一门基于原型继承的语言,类(class)只是一种语法糖,给习惯面向类的软件设计的开发者们多一种选择

类的机制

      因为这一小结并没有在javascript中有所体现,写的原因只是为了帮助大家熟悉传统面向类的设计模式,所以下面的相关例子会采用伪代码形式展示

构造函数

      类实例是由一个特殊的类方法构造的,这个方法名通常和类名相同,被称为构造函数。这个方法的任务就是初始化实例需要的所有信息(状态)。

class CoolGuy {
	specialTrick = nothing
	CoolGuy( trick ) {
		specialTrick = trick
	}
	showOff() {
		output( "Here's my trick: ", specialTrick )
	}
}

      我们可以调用类构造函数来生成一个 CoolGuy 实例:

Joe = new CoolGuy( "jumping rope" )
Joe.showOff()

      类构造函数属于类,而且通常和类同名。此外,构造函数大多需要用 new 来调,这样语言引擎才知道你想要构造一个新的类实例。

类的继承

      在面向类的语言中,你可以先定义一个类,然后定义一个继承前者的类。后者通常被称为“子类”,前者通常被称为“父类”。这里我们举一个例子来进一步说明,假设有一个Vehicle类,这是引擎类,提供一个推进能力,比如飞机火车上都有,然后我们定义一个Car类,很明显对于不同的交通工具再额外定义推进能力是没必要的,这时候就需要让Car类继承Vehicle类。可以给出如下伪代码:

class Vehicle {
	engines = 1
	ignition() {
		output( "Turning on my engine." );
	}
	drive() {
		ignition();
		output( "Steering and moving forward!" )
	}
}
class Car inherits Vehicle {
	wheels = 4
	drive() {
		inherited:drive()
		output( "Rolling on all ", wheels, " wheels!" )
	}
}
class SpeedBoat inherits Vehicle {
	engines = 2
	ignition() {
		output( "Turning on my ", engines, " engines." )
	}
	pilot() {
		inherited:drive()
		output( "Speeding through the water with ease!" )
	}
}

多态

      Car 重写了继承自父类的 drive() 方法,但是之后 Car 调用了 inherited:drive() 方法,这表明 Car 可以引用继承来的原始 drive() 方法。快艇的 pilot() 方法同样引用了原始drive() 方法。这个技术被称为多态或者虚拟多态。多态的另一个方面是,在继承链的不同层次中一个方法名可以被多次定义,当调用方法时会自动选择合适的定义。

多重继承

      从表面上来,对于类来说这似乎是一个非常有用的功能,可以把许多功能组合在一起。然而,这个机制同时也会带来很多复杂的问题。如果两个父类中都定义了 drive() 方法的话,子类引用的是哪个呢?难道每次都需要手动指定具体父类的 drive() 方法吗?
      JavaScript 要简单得多:它本身并不提供“多重继承”功能。许多人认为这是件好事,因为使用多重继承的代价太高。

小结

      这一章我们介绍了有关传统面向类的设计模式,了解到了类的构造函数,多态和继承,下一章我们将继续介绍javascript在其中的解决方式
      小伙伴们今天的学习就到这里了,如果觉得本文对你有帮助的话,欢迎转发,评论,收藏,点赞!!!
      每天学习进步一点点,就是领先的开始。如果想继续提高,欢迎关注我,或者关注公众号”祯民讲前端“。大量前端技术文章,面试资料,技巧等助你更进一步!
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值