JavaScript 库与框架之间的区别

Umar Hansa
Umar Hansa

本文将介绍在客户端 JavaScript 环境(即在网络浏览器中运行的代码)中框架和库之间的区别。不过,本文中提出的某些观点也适用于其他环境,因为库和框架是许多软件工程领域(如原生移动应用开发)的一部分。

本文讨论的重点在于库和框架之间的定性差异,而非数量差异。例如:

  • 定量:框架通常遵循控制反转原则。
  • 定性:在求职时,框架经验可以让未来的雇主更为青睐。

为何需要了解库和框架?

整个网络中的 JavaScript 库和框架很多。其他所有网站似乎都使用一些第三方代码作为其 JavaScript 资源的一部分。网页重量随着时间推移越来越差,这影响到了用户JavaScript 是影响整体网页大小的重要因素,而第三方库和框架通常就是由 JavaScript 组成。

仅仅说“停止使用 JavaScript 框架”是不够的,因为框架为开发者带来了巨大的好处。框架可以帮助您高效编码、快速交付功能,还能带来其他好处。相反,您应该自行学习,以便在需要时做出明智的决定。

您不妨问自己一个不常见的问题:“我今天应该使用库还是框架?”库和框架是两码事。不过,库和框架经常被混为一谈,因此您对这两者的了解越多,就越有可能做出明智的使用决策。

库和框架示例

您可能会注意到第三方代码用其他名称表示,例如微件、插件、polyfill 或软件包。不过,它们通常都属于库或框架类别。基本上,这两者的区别可以总结如下:

库通常比框架更简单,提供的功能范围也较窄。如果您将输入传递给方法并收到输出,那么您可能使用了库。

请查看以下 lodash 库示例:

import lodash from 'lodash'; // [1]
const result = lodash.capitalize('hello'); // [2]
console.log(result); // Hello

与许多库一样,仔细阅读此代码并了解其功能是非常实际的。其中的魔法很少

  1. import 语句会将 lodash 库导入 JavaScript 程序。
  2. 系统会调用 capitalize() 方法。
  3. 系统会将一个参数传递给该方法。
  4. 返回值会捕获在变量中。

框架

框架通常比库大,对整体网页大小的影响也更大。事实上,框架可以包含库。

此示例展示了一个不含库的简单框架,并使用了 Vue(一种热门 JavaScript 框架):

<!-- index.html -->
<div id="main">
  {{ message }}
</div>

<script type="module">
import Vue from './node_modules/vue/dist/vue.esm.browser.js';

new Vue({
  el: '#main',
  data: {
    message: 'Hello, world'
  }
});
</script>

如果您将此框架示例与前面的库示例进行比较,可能会发现以下差异:

  • 框架代码涵盖多种技术,并将这些技术抽象到自己的 API 中。
  • 开发者无法完全控制操作的发生方式和时间。例如,Vue 如何以及何时将 'Hello, world' 字符串写入页面,这些都已被抽象化,您无需了解。
  • Vue 类的实例化会产生一些副作用,这在使用框架时很常见,而库可能会提供纯函数
  • 该框架规定了特定的 HTML 模板系统,而不是使用您自己的模板系统。
  • 如果您深入阅读 Vue 框架文档或大多数其他框架文档,将会了解到框架如何规定您可以使用的架构模式。JavaScript 框架可以为您减轻一些认知负担,因为您不必自己解决这个问题。

何时使用库而非框架

阅读完库和框架之间的比较之后,您可能会开始了解何时使用其中一种:

  • 框架可以为开发者降低复杂性。如前所述,框架可以对逻辑、行为甚至架构模式进行抽象化处理。在开始新项目时,此功能特别有用。库可以帮助解决复杂性问题,但通常侧重于代码重用。
  • 框架作者希望提高您的工作效率,并且通常会开发额外的工具、调试软件和全面的指南以及其他资源来帮助您有效地使用框架。库作者也希望您能够高效工作,但库中很少有专用工具。
  • 大多数框架都会提供一个功能性起点(例如框架或样板),以帮助您快速构建网络应用。库会成为您已建立的代码库的一部分。
  • 通常,框架会给代码库带来一些复杂性。最初的复杂性并不总是很明显,但可能会随着时间推移逐渐显现。

谨此提醒,您通常不会将库与框架进行比较,因为它们是用于完成不同任务的不同内容。不过,您对这两种广告形式了解得越多,就越能做出最适合您的选择。使用框架或库最终取决于您的需求。

可切换性

您不会每周更改库或框架。不过,最好了解将您锁定在其生态系统中的软件包的缺点。此外,我们还建议您了解,决定使用第三方软件包的开发者在一定程度上负责在软件包和应用源代码之间创建松散耦合。

与源代码关联的软件包更难移除和交换为其他软件包。在以下情况下,您可能需要更换软件包:

  • 您必须更新不再受维护的软件包。
  • 您发现该软件包出现漏洞,无法使用。
  • 您可以了解更符合您需求的新套餐。
  • 您的产品要求发生了变化,您不再需要此套餐。

请参考下面的示例:

// header.js file
import color from '@package/set-color';
color('header', 'dark');

// article.js file
import color from '@package/set-color';
color('.article-post', 'dark');

// footer.js file
import color from '@package/set-color';
color('.footer-container', 'dark');

前面的示例在三个单独的文件中使用了第三方 @package/set-color 软件包。如果您在处理此代码并需要替换第三方软件包,则必须在三个位置更新此代码。

或者,您也可以简化维护工作,并将库使用情况提取到一个位置,如以下示例所示:

// lib/set-color.js file
import color from '@package/set-color';

export default function color(element, theme = 'dark') {
  color(element, theme);
}

// header.js file
import color from './lib/set-color.js';
color('header');

// article.js file
import color from './lib/set-color.js';
color('.article-post');

// footer.js file
import color from './lib/set-color.js';
color('.footer-container');

在上一个示例中,我们抽象化了对库的直接使用。因此,如果您必须替换第三方软件包,只需更新一个文件即可。此外,由于内部 set-color.js 文件设置了要使用的默认配色主题,因此代码现在更易于使用。

易用性

框架可能具有复杂的 API,但可以提供开发者工具,从而让整体使用变得更简单。易用性取决于多种因素,并且可能具有高度主观性。框架可能难以使用,原因如下:

  • 该框架具有本身复杂的 API。
  • 该框架记录不充分,需要大量试错才能解决问题。
  • 该框架使用了您和您的团队不熟悉的技术。

框架可以通过遵循以下常见的最佳做法来缓解这些挑战:

  • 该框架提供了开发者和诊断工具,以简化调试。
  • 该框架拥有一个活跃的开发者社区,他们会共同协作,制作免费的文档、指南、教程和视频。了解这些内容后,您就可以高效地使用该框架了。
  • 该框架提供了一个遵循通用编码规范的 API。由于您以前学习过这些规范,并且对编码样式有更深入的了解,因此可以高效地使用框架。

虽然这些问题通常归因于框架,但也可能归因于库。例如,D3.js JavaScript 库功能强大,拥有一个庞大的生态系统,提供研讨会、指南、文档以及其他资源,所有这些都影响了它的易用性。

此外,框架通常会为您的 Web 应用规定架构,而库通常与您现有的架构(无论是哪种架构)兼容。

性能

一般来说,框架对性能的影响比库更大,但也有例外情况。网页性能是一个涉及众多主题的巨大领域,因此这些部分涉及两个值得注意的主题:摇树优化和软件更新。

摇树

捆绑只是 Web 性能的一个方面,但对性能有很大影响,尤其是对于较大的库。在导入和导出期间使用树摇动有助于提升性能,因为它会查找并修剪应用不需要的代码。

在打包 JavaScript 代码时,有一个称为“树摇动”的实用步骤,这是一个对代码进行的非常有价值的性能优化,不过,与框架相比,使用库更容易执行此操作。

将第三方代码导入源代码时,您通常会将代码打包到一个或多个输出文件中。例如,header.jsfooter.jssidebar.js 文件会合并到 output.js 文件中,即您在 Web 应用中加载的输出文件。

如需更好地了解树摇动,请参考以下代码示例:

// library.js file
export function add(a, b) {
  return a + b;
}

export function subtract(a, b) {
  return a - b;
}

// main.js file
import {add} from './library.js';

console.log(add(7, 10));

为便于演示,我们特意将 library.js 代码示例保持为比您在现实世界中可能见到的规模小一些,而现实世界中的库可能有数千行。

简单的软件包流程可能会使用以下输出导出代码:

// output.js file
function add(a, b) {
  return a + b;
}

function subtract(a, b) {
  return a - b;
}

console.log(add(7, 10));

尽管此应用中不需要 subtract() 函数,但它仍包含在最终 bundle 中。此类不必要的代码会增加下载大小、解析和编译时间,以及用户必须支付的执行费用。基本树摇方法会移除死代码并生成以下输出:

// output.js file
function add(a, b) {
  return a + b;
}

console.log(add(7, 10));

请注意,代码更短、更简洁。在此示例中,性能提升可以忽略不计,但在库长达数千行的实际应用中,性能影响可能会更为显著。有趣的是,Parcel、Webpack 和 Rollup 等现代软件包工具更进一步,因为它们结合了缩减和树摇动来创建高度优化的软件包。为了演示软件包工具的有效性,我们使用 Parcel 创建了包含之前的代码示例的软件包文件。Parcel 移除了所有未使用的代码并导出了以下单个模块:

console.log(7+10);

Parcel 足够智能,可以移除导入语句、函数定义和行为等内容,以创建高度优化的代码。

捆绑只是 Web 性能的一个方面,但对性能有很大影响,尤其是对于较大的库。通常,使用库进行树摇动比使用框架更简单。

软件更新

对于许多库和框架,软件更新会添加功能、修复 bug,并最终随着时间的推移而变大。下载更新并不总是必要的,但如果更新包含 bug 修复、所需的功能增强或安全修复,则您可能应该进行更新。不过,您通过网络发送的数据越多,应用的性能就越低,对用户体验的影响就越大。

如果库变大,您可以使用摇树优化来减缓增长。或者,您也可以使用体积较小的 JavaScript 库替代方案。如需了解详情,请参阅可切换性

如果框架变大,不仅会增加树摇动方面的挑战,还会增加将一个框架换成另一个框架的难度。如需了解详情,请参阅可切换性

就业率

众所周知,许多公司对熟悉特定框架的开发者都有硬性要求。他们可能会忽略您对 Web 基础知识的了解,而只关注您对某个 JavaScript 框架的具体知识!无论对错与否,这都是许多工作的现实。

了解一些 JavaScript 库对您的求职申请没有坏处,但也无法保证能让您脱颖而出。如果您对一些热门的 JavaScript 框架非常熟悉,那么雇主很可能会认为这些知识在当前的工作市场中对网络开发者有利。有些大型企业组织仍在使用非常陈旧的 JavaScript 框架,甚至可能非常迫切地需要熟悉此类框架的候选人。

您可以利用以下公开的秘密为自己谋取利益。不过,在进入职场时,请谨慎行事,并注意以下事项:

  • 请注意,如果您在职业生涯中花费大量时间只使用一种框架,就可能会错过学习其他更现代框架的机会。
  • 假设开发者不能充分了解软件开发或 Web 开发的基础知识,但却被聘为了框架开发者。此开发者编写的代码不高效,您可能会发现处理这样的代码库令人畏惧或不知所措。在某些情况下,这种情况可能会导致倦怠。例如,由于速度缓慢,您可能必须重构代码或优化代码。
  • 学习 Web 开发时,最佳途径是先重点学习 Web 开发、软件开发和软件工程的基础知识。如此扎实的基础有助于您快速有效地掌握任何 JavaScript 框架。

总结

您好!您已努力学习,了解了 JavaScript 框架和库的比较情况,非常棒!除非您从事全新项目或担任顾问,否则不必经常选择框架或库。不过,当出现此类决策时,您对相关主题的了解越多,做出的决策就越明智。

正如您所学,您选择的框架(在某些情况下,还包括库)可能会对您的开发体验和最终用户(例如性能)产生重大影响。