读《JavaScript设计模式与开发实践》(一)

前言

目前我在开发中也接触了一些js的设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。正好手头有一本书 《JavaScript设计模式与开发实践》 ,所以打算好好研读一下,改变一下面向过程的编码方式。

这本书是由曾探大佬撰写(图灵社区主页)。该系列文章我会根据自己的理解结合最新的相关规范来写,有错误的地方还望社区大佬指正。

前置知识

在开始设计模式学习之前,本书的第一章节主要讲了需要了解的关于js的一些知识。

动态类型语言

编程语言按照数据类型可以分为 静态类型语言动态类型语言

静态类型语言在编译时就已经确定了变量的类型,例如C语言在声明变量时需要指定变量的数据类型,如 int a = 1 ;而动态类型语言则是在程序运行时,通过判断被赋予的值来确定类型,js就是一门典型的动态语言。

js 复制代码
let a;
console.log(typeof a) // undefined
a = 10;
console.log(typeof a) // number
a = 'abc'
console.log(typeof a) // string

相比于静态类型语言,动态类型语言虽然可能会在程序运行时发生类型相关的错误,但是编写的代码更加简洁易懂,同时具有很强的灵活性,这一切建立在 鸭子类型 的概念上。

鸭子类型:如果它走起路来像鸭子,叫起来也是鸭子,那么它就是鸭子。

鸭子类型指导我们只关注对象的行为,而不需要关注对象本身。在动态类型语言的面向对象设计中,鸭子类型的概念至关重要,根据鸭子类型,可以总结出一条原则:面向接口编程,而不是面向实现编程。例如如果一个对象拥有push和pop方法与length属性,并可以通过下标存取属性,在某些情况下,就可以当作一个数组来进行使用。

多态

多态的实际含义是同一操作作用于不同的对象上面,可以产生不同的解释与不同的执行结果,通俗来讲就是给不同的对象发送同一个消息得到不同的反馈,多态的核心思想就是将"不变的"和"可变的"分离开。

举个例子:我养了一只猫和一只狗,我对他们下发"叫"的命令,猫会喵喵喵,狗会汪汪汪,在这个例子中,"叫"的命令是不变的,而具体每一只动物的叫声则是可变的,用js代码实现如下:

js 复制代码
const makeSound = function (animal) {
  if (animal instanceof Cat) {
    console.log("喵喵喵");
  } else if (animal instanceof Dog) {
    console.log("汪汪汪");
  }
};

class Cat {}
class Dog {}

makeSound(new Cat()); // 喵喵喵
makeSound(new Dog()); // 汪汪汪

在上述代码中,给CatDog两个类发送了相同的makeSound命令,得到了不同的反馈,但是这一段代码存在一个缺点,就是当我继续增加养的动物时,我需要同步增加makeSound函数中的内容,当动物种类越来越多时,函数也变得越来越臃肿,所以我们需要把不变的部分单独提取出来,以下是优化后的代码:

js 复制代码
const makeSound = function (animal) {
  if (animal.sound instanceof Function) {
    animal.sound(); // "叫"的命令是不变的
  }
};

class Cat {
  sound() {
    console.log("喵喵喵");
  }
}
class Dog {
  sound() {
    console.log("汪汪汪");
  }
}

makeSound(new Cat()); // 喵喵喵
makeSound(new Dog()); // 汪汪汪

这一段代码通俗来讲就是给所有能叫的动物发送"叫"的命令,所以当继续增加动物时,只需要在动物这个类中声明"叫"的动作即可。由此可见,某一动物是否能发出叫声,只取决于动物有没有sound方法,这就是在js这门动态类型语言中,类或者说对象的多态性是与生俱来的。将行为分布在各个对象中,并让这些对象各自负责自己的行为,这正是面向对象设计的优点。

封装

封装的目的主要是为了将一些属性或方法隐藏起来,然后向外提供一些公有方法。通过对对象的封装,对象内部的一些变化对于其他对象而言是透明的,只通过公有方法进行通信,符合"低耦合"原则。

在Java等语言中,提供了public、private等关键字来控制属性的访问权限,但是在js(ES6之前 )中并没有提供这样的关键字,所以我们需要利用到js的一个特性------ 闭包

在红宝书上,闭包的定义如下:闭包是指有权访问另外一个函数作用域中的变量的函数。

所以当我们返回一个函数调用了函数内部变量的时候,此时就产生了闭包,而这个变量也就成为了外部无法访问的私有变量:

js 复制代码
var Obj = function() {
  var _name = "张三"

  return {
    getName: function() {
      return _name
    },
    setName: function(val) {
      _name = val
    }
  }
}

var obj1 = new Obj()

console.log(obj1.getName()); // 张三
obj1.setName("李四")
console.log(obj1.getName()) // 李四
console.log(obj1._name) // undefined

而在ES6中,我们拥有了更多的方法来实现私有属性,我将在另一篇文章中展开细说。

相关推荐
腾讯TNTWeb前端团队6 小时前
helux v5 发布了,像pinia一样优雅地管理你的react状态吧
前端·javascript·react.js
范文杰9 小时前
AI 时代如何更高效开发前端组件?21st.dev 给了一种答案
前端·ai编程
拉不动的猪9 小时前
刷刷题50(常见的js数据通信与渲染问题)
前端·javascript·面试
拉不动的猪9 小时前
JS多线程Webworks中的几种实战场景演示
前端·javascript·面试
FreeCultureBoy10 小时前
macOS 命令行 原生挂载 webdav 方法
前端
uhakadotcom11 小时前
Astro 框架:快速构建内容驱动型网站的利器
前端·javascript·面试
uhakadotcom11 小时前
了解Nest.js和Next.js:如何选择合适的框架
前端·javascript·面试
uhakadotcom11 小时前
React与Next.js:基础知识及应用场景
前端·面试·github
uhakadotcom11 小时前
Remix 框架:性能与易用性的完美结合
前端·javascript·面试
uhakadotcom11 小时前
Node.js 包管理器:npm vs pnpm
前端·javascript·面试