PS:上一篇文章发表之后,很多朋友关注了本人的思否和掘金的博客,虽然关注的朋友还有有限,但足够让我把自己在技术上的问题积累分享给大家,也希望大家能够喜欢,同时能动一动手指,给一颗心(赞),博主会持续更新下去
多态
本文是《javascript设计模式与开发实践》一书学习笔记,因书中所表述的概念简单明了,故将整本书的笔记奉上,全部文章大概在20篇左右,还请朋友们持续关注
动态语言类型
编程语言按照数据类型大体可以分为两类,一类是静态类型语言,另一类是动态类型语言
静态类型语言,声明任何变量或者形参都需要指定类型,例如java语言。
动态类型语言,声明任何变量或者形参都不需要指定类型,javascript就是动态类型语言。
所谓动态,可以多层面的理解,首先,声明变量不需要指定类型,其次,在多态思想下,java中需要利用父类实现多态,而javascript就不需要,本身自带多态属性。
多态
熟悉java的朋友知道,java三大特征之一就有多态,多态给java带来了很大的灵活性,很多设计模式也是通过多态来实现,java中的多态涉及到向上转型和向下转型,而javascript(以下简称js)的”多态”就相对来说容易实现
我们来看一段“多态”的js代码
var makeSound = function(an) {
if(an instanceof Duck) {
console.log("嘎嘎嘎");
} else if(an instanceof Dog) {
console.log("汪汪汪");
}
}
var Dog = function(){};
var Duck = function(){};
makeSound(new Dog());
makeSound(new Duck());
这段代码确实体现了“多态性”,当我们分别向鸭和鸡发出“叫唤”的消息时,它们根据此 消息作出了各自不同的反应,但是这样写会有一个弊端,当更多的类型出现时,我们要不断的修改makeSound函数,后期makeSound函数也会变得十分巨大,这不符合良好代码设计的规范,多态背后的思想是将“做什么”和“谁去做以及怎样去做”分离开来,也就是将“不变的事 物”与 “可能改变的事物”分离开来。在这个故事中,动物都会叫,这是不变的,但是不同类 型的动物具体怎么叫是可变的。把不变的部分隔离出来,把可变的部分封装起来,这给予了我们 扩展程序的能力,程序看起来是可生长的,也是符合开放—封闭原则的,相对于修改代码来说, 仅仅增加代码就能完成同样的功能,这显然优雅和安全得多
首先,我们把makeSound函数修改一下:
var makeSound = function(an) {
an.speak();
}
这段代码传入一个对象,然后调用对象的speak函数
var Duck = function(){}
Duck.prototype.sound = function(){
console.log( '嘎嘎嘎' );
};
var Chicken = function(){}
Chicken.prototype.sound = function(){
console.log( '咯咯咯' );
};
makeSound( new Duck() ); // 嘎嘎嘎
makeSound( new Chicken() );
现在我们向鸭和鸡都发出“叫唤”的消息,它们接到消息后分别作出了不同的反应。如果有 一天动物世界里又增加了一只狗,这时候只要简单地追加一些代码就可以了,而不用改动以前的 makeSound 函数
类型检查和多态
现在,我们来进一步了解多态,之前说到,java的多态需要利用继承来实现,我们现在把动物的例子换成java代码
public class Duck {
public void speak(){
System.out.println( "嘎嘎嘎" );
}
}
public class Dog {
public void speak(){
System.out.println( "汪汪汪" );
}
}
public class AnimalSpeak{
public void makeSound(Duck duck){
duck.speak();
}
}
public static void main(String args[]){
AnimalSpeak an = new AnimalSpeak();
Duck duck = new Duck();
an.makeSound(duck); // 输出:嘎嘎嘎
}
现在鸭子已经顺利叫出来了,但是我们想让狗也叫,发现不太容易实现,因为makeSound函数中,形参是Duck类型,传入Dog类型一定会报错,这个时候继承就出现了,java设计思路是我先创建一个父类,具体传入的类型由子类决定,但是makeSound函数中的形参确是父类类型,实现如下:
public abstract class Animal{
abstract void speak(); // 抽象方法
}
public class Duck extends Animal {
public void speak(){ // 覆写父类中的抽象方法
System.out.println( "嘎嘎嘎" );
}
}
public class Dog extends Animal {
public void speak(){ // 覆写父类中的抽象方法
System.out.println( "汪汪汪" );
}
}
public class AnimalSpeak{
public void makeSound(Animal an){
an.speak();
}
}
public static void main(String args[]){
AnimalSpeak an = new AnimalSpeak();
Animal duck = new Duck();
Animal dog = new Dog();
an.makeSound(duck); // 输出:嘎嘎嘎
an.makeSound(dog); // 输出:汪汪汪
}
js中的多态
JavaScript 对象的多态性是与生俱来的,为什么这么说? 仔细看看这两个函数:
public void makeSound(Animal an){
an.speak();
}
function(an) {
an.speak();
}
js和java中的函数的形参是不同的,java定死了传入的类型,而js是动态的,js随便可以传入任何类型,所以,我们之前说js是动态类型语言,在 JavaScript 这种将函数作为一等对象的语言中,函数本身也是对象,函数用来封装行为并 且能够被四处传递。当我们对一些函数发出“调用”的消息时,这些函数会返回不同的执行结 果,这是“多态性”的一种体现,也是很多设计模式在 JavaScript 中可以用高阶函数来代替实现的原因。