读《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()); // 汪汪汪

在上述代码中,给Cat和Dog两个类发送了相同的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中,我们拥有了更多的方法来实现私有属性,我将在另一篇文章中展开细说。

相关推荐
lpfasd1236 小时前
node-sass 停止维护!老项目迁移 Dart Sass 完整教程
前端·rust·sass
Data analyse4568 小时前
rnweb 回放数据量太大怎么办?分片存储与断点续传的实现思路
前端·网络·算法·数据分析
xiaogai_gai8 小时前
金蝶收料通知单查询策略实战教程:从源系统拉取到中间层落地的完整路径
java·前端·数据库
环境栈笔记9 小时前
指纹浏览器 WebRTC 怎么设置?从 ICE 候选、代理出口到功能验证
前端·人工智能·后端·自动化
赵大仁9 小时前
官网性能优化实战:LCP 3.2s → 2.1s、CLS 0.107 → 0,以及被我推翻的 6 个判断
前端·性能优化·cls·lcp·core web vitals
xiancai_xianyu9 小时前
Text2SQL落地生产库前,SQL要过哪三道闸
前端·数据库·sql·sql注入·text2sql·ai agent开发·企业级ai框架
小羊没烦恼!10 小时前
T-SQL查询进阶--理解SQL SERVER中的分区表
服务器·开发语言·前端·javascript·html
史瓦辛格10 小时前
给 DeepSeek Harness 写费用插件:把「这次会话花了多少钱」算准
前端·deepseek
星光不问赶路人10 小时前
Vue 3 + TypeScript 中 enum 的使用实践
前端·vue.js
鸥梨菌Honevid10 小时前
UVM 中 REQ 和 RSP 类型详解:从通信模型到 item_done 与 put_response
java·前端·servlet