单例模式

在 ES6 之前,单例模式在 JavaScript 中除了状态管理,其实更经常被用来做封装和命令空间。
而在 ES6 以后,JS 中已经加入了很多防止全局污染的手段;JavaScript 中的新加入的模块系统(modular system)使创建全局可访问的值更容易,而不会污染全局范围。
单例模式主要用于在应用程序中共享一个全局实例。
当你创建一个新对象的时候,就已经是单例对象了。
单例模式下的状态管理
单例的常见用例是在整个应用程序中拥有某种全局状态。这可能会导致代码库中依赖同一个可变对象的多个部分对它的修改产生冲突。
函数式编程的状态管理
在 React 中,我们经常通过 Redux 或 React Context 等状态管理工具来管理全局状态,而不是使用单例对象。
虽然 Redux 或 React Context 中也有全局状态,相关的行为可能看起来类似于单例,但这些工具提供了只读状态而不是单例的可变状态。比如在使用 Redux 时,只有纯函数reducer 才能在组件通过调度程序发送一个动作触发后的更新状态。使用这些工具不可能完全消除全局状态的缺点,但因为组件不能直接更新状态,这样做至少可以确保全局状态按照预期方式发生变化。
Redux 的意图可以概括为三个原则:
第一,全局的状态都在一个 store 里保存;
第二,这个 store 里的状态对于整个应用来说都是只读的;
第三,如果需要更新改变状态的话,则需要通过 reducer 来完成。
我们可以通过一个例子来看看。下图中 UI 界面有一个存款显示功能,显示目前的存款为 0;界面上还有两个按钮分别带有存入和取出的功能。在开始的时候,当有人点击存入 10 元的动作时,一个存储的事件会传到事件处理器。

这个时候,事件处理器会对相关行为的数据打包为动作对象(action object),里面包含了动作类型字段,你可以将动作对象视为描述应用程序中发生的事件的对象。在这个例子中,类型就是“存入”,相关 palyload 的记录为“10”。动作对象打包好后会派发到存储器。
这个时候存储器会先调用已有的状态,也就是说当前的存款数量是 0,加上 10 元,相加的合就是 10 元。reducer 是一个接收当前状态和行为对象的函数,如果需要,它会决定如何更新状态,并返回新状态 (state, action) => newState。 你可以将 reducer 视为事件监听器,它根据接收到的操作(事件)类型处理事件。
reducer 遵循一些特定规则,你也值得了解:
第一,reducer 只基于状态和行为动作这两个参数来计算新的状态值;
第二,它必须遵循不可变原则,不能更改已有的状态,而只能拷贝状态并在拷贝的版本上做修改;
第三,是 reducer 会避免任何副作用,比如异步操作。

Redux 存储有一个称为 dispatch 的方法。更新状态的唯一方法是调用 store.dispatch() 并传入一个动作对象。store 将运行 reducer 函数并将新的 state 值保存在里面,我们可以调用 getState() 来检索更新的状态值。
Redux 还有一个 Selector(选择器)知道如何从存储状态值中提取特定信息的函数。随着应用程序变得越来越大,这有助于避免重复逻辑,因为应用程序的不同部分需要读取相同的数据。最后,当存储器里的工作完成后,UI 获得了更新后的 10 元状态值。

Redux 使用“单向数据流”应用程序结构。也就是说,第一,状态描述应用程序在某个时间点的状态,UI 会根据该状态呈现。第二,当应用程序发生某些事件变化时,数据变更,UI 根据新状态重新渲染。
必单例模式更加有效

工厂模式

工厂模式,是使用工厂函数来创建对象的。它可以使我们调用工厂,而不是直接使用 new 运算符或 Object.create() 从类中创建新对象。在 JavaScript 中,工厂模式只不过是一个不使用 new 关键字就返回对象的函数。
工厂允许我们将对象的创建与其实现分开。
优势是,如果我们要创建相对复杂和可配置的对象,工厂模式会很有用
劣势是,它可能占用更多的内存。

var o = new Object(),
    n = new Object(1),
    s = Object('1'),
    b = Object(true);
// test
o.constructor === Object;  // true
n.constructor === Number;  // true
s.constructor === String;  // true
b.constructor === Boolean; // true

还有一个非常常见的例子就是我们说箭头函数(arrow function)就是工厂模式。之所以这么说是因为如果箭头函数体由单个表达式组成的话,在函数创建时会间接返回一个对象,所以是一个小型工厂函数。

var createUser = (userName) => ({ userName: userName });
createUser("bar"); // {userName: 'bar'}
createUser("foo"); // {userName: 'foo'}

原型模式

原型就是在许多相同类型的对象之间共享属性。
如果是从非 JavaScript 角度看,很多其他语言对原型模式的介绍中会使用到类(class)。而实际在 JavaScript 的情况下,原型继承可以避免用到类。这样做是利用它自身的优势,而不是试图模仿其他语言的特性。原型模式不仅让继承实现起来更简单,而且还可以提高性能,在对象中定义函数时,它们都是通过引用创建的(因此所有子对象都指向同一个函数),而不是创建单个副本。

此文章为2月Day1学习笔记,内容来源于极客时间《Jvascript进阶实战课》,大家共同进步💪💪

豪猪
4 声望4 粉丝

undefined