前言曾经对Javascript的面向对象相关知识也有过了解,从各种博客、书籍上也学到了很多。但是最近在看《Javascript设计模式与开发实战》这本书时发现该书对这方面的知识点介绍的很易于理解,因此总结出该文章分享给大家,同时也作为自己日后复习的笔记。动态类型语言和鸭子类型编程语言按照数据类型大体可分为静态类型语言和动态类型语言。静态类型语言就是指在编译时就已经确定了变量的类型,比如C++在声明变量时的int关键字。动态类型语言的变量类型要在程序运行时被赋值后才能确定。在Javascript中,我们在对一个变量赋值时,显然不需要考虑它的类型。因此,Javascript是一门经典的动态类型语言。动态类型语言在实际编码时带来了很大的灵活性,我们可以尝试调用任意对象的任意方法,而不需要考虑它原本是否被设计拥有该方法。这些都建立在鸭子类型的概念上,通俗的说法是“如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。”好吧我知道你可能不太理解,我们可以通过一个故事来深入理解:从前在Javascript王国里,有一个国王,他觉得世界上最美妙的声音就是鸭子的叫声,于是国王召集大臣,要组建一个100只鸭子组成的合唱团。但是大臣们找遍了全国,只找到了999只鸭子,最后大臣发现有一只非常特别的鸡,它的叫声跟鸭子一模一样,于是这只鸡就成为了合唱团的最后一员。这个故事说明,国王只是想要鸭子的叫声,但它的主人是鸡还是鸭都不重要。我们只关注对象的行为,而不关注对象本身。通过代码你可能能更好的的理解:let duck = { duckSay: function () { console.log(‘ga’) }}let chicken = { duckSay: function () { console.log(‘ga’) }}// 合唱团let choir = []let joinChoir = function (animal) { if (animal && typeof animal.duckSay === ‘function’) { choir.push(animal) console.log(‘加入合唱团成功’) }}joinChoir(duck) // 加入合唱团成功joinChoir(chicken) // 加入合唱团成功我们发现,只要动物拥有duckSay方法,它就可以加入合唱团,而并不关心它到底是谁。鸭子类型的概念至关重要,比如一个对象有了length属性,也可以依照下标来存取属性,这个对象就可以被当做数组来使用。(这里可以思考我们在处理函数传入的参数arguments时的一些操作)多态多态是指同一操作作用于不同的对象上面,可以产生不同的解释和不同的执行结果。也就是给不同对象发送同一消息,会有不同的反馈。这里我们依旧通过一个故事来讲解:主人家里养了两只动物,一只鸡和一只鸭,当主人发出叫的命令时,鸭会gagaga的叫,而鸡会gegege的叫。上面的故事用代码实现就是:let makeSound = function (animal) { if (animal instanceof Duck) { console.log(‘ga’) } else if (animal instanceof Chicken) { console.log(‘ge’) }}let Duck = function () {}let Chicken = function () {}makeSound(new Duck()) // gamakeSound(new Chicken()) // ge多态背后的思想是将“做什么”和“谁去做以及怎样去做”分离开,即将“不变的事情”和“可变的事情”分离开。这样的程序是可生长的,也是符合开放-封闭原则。因此我们可以将不变的部分隔离出来,也就是所有的动物都会叫let makeSound = function (animal) { animal.sound()}然后把可变的部分封装起来:let Duck = function () {}Duck.prototype.sound = function () { console.log(‘ga’)}let Chicken = function () {}Chicken.prototype.sound = function () { console.log(‘ge’)}makeSound(new Duck()) // gamakeSound(new Chicken()) // ge再比如我们要开发一个地图应用,现在有百度和谷歌两家地图提供了API,且均提供了show()方法,代码如下:let googleMap = { show: function () { console.log(‘开始渲染谷歌地图’) }}let baiduMap = { show: function () { console.log(‘开始渲染百度地图’) }}let renderMap = function (type) { if (type === ‘google’) { googleMap.show() } else if (type === ‘baidu’) { baiduMap.show() }}renderMap(‘google’) // 开始渲染谷歌地图renderMap(‘baidu’) // 开始渲染百度地图可以看到,虽然renderMap()函数保持了一定的弹性,但是这种弹性很脆弱,如果再换另一个地图,有需要修改renderMap函数,继续添加条件分支语句。我们可以把程序相同的部分抽象出来,即显示某个地图:let renderMap = function (map) { if (map.show instanceof Function) { map.show() }}结束语希望能为你带来一些启发。参考资料:《JavaScript 设计模式与开发实战》 第一章