0

0

设计和构建你自己的JavaScript代码库:提示与技巧

黄舟

黄舟

发布时间:2017-02-22 13:48:53

|

1417人浏览过

|

来源于php中文网

原创

代码库:我们一直在使用它们。代码库是开发者把他们会在项目中使用到的代码打包起来形成的,这总能节省时间和避免重复造轮子。拥有一个可重复使用的包,不管是开源的还是闭源的,总比重复构建一样特性的包或者从过去的项目中手动复制粘贴要好。

来自作者的更多文章

  • stop maiming bodies: the perils of pixel font-size

  • ES2016: Should the Future of JavaScript Be Developer-Driven?

除了被打包的代码,还可以更精确的形容代码库吗?除了少数的例外,代码库通常只是一个文件,或者是在同一个文件夹里的几个文件。它的代码应该可以单 独保存和在你的项目中正常使用。库文件允许你根据项目的不同来调整结构或者行为。想象一下只能通过USB接口进行通讯的USB设备。一些设备,例如鼠标和 键盘,可以通过设备提供的接口来进行配置。

在这篇文章,我会解释如何构建库文件。尽管大部分的方法可以应用到其他语言,但这篇文章主要讲述的是构建JavaScript库文件。

为什么构建你自己的Javascript库?

首先和最重要的,库文件可以让现有的代码方便的重复利用。你不需要挖出陈旧的项目来复制文件,只需要引入库文件。这也可以让你的应用组件化,让应用的代码库更小更易维护。

设计和构建你自己的JavaScript代码库:提示与技巧

Christ Church Library (source)

任何可以让实现一个具体的功能更容易或者可以被重复利用的抽象的代码,都可以被打包进去库文件。jQuery是一个有趣的例子。尽管jQuery的API有大量的简化的DOM API,在跨浏览器DOM操作比较困难的过去有着相当重要的意义。

如果一个开源项目变得流行并且让许多开发者使用它,人们很有可能通过提出问题或者贡献代码来参加它的开发。不管怎样,都对库和依赖它的项目有所帮助。

一个流行的开源库也会带来很好的机会。公司可能会对你的工作质量表示认可并给你发offer。可能公司会要求你把你的项目整合进他们的应用。毕竟,没人可以比你更了解你的项目。

当然它可能只是一个习惯——享受敲码,帮助他人并在这个过程中学习和成长。你可以提升你的极限和尝试新的东西。

范围和目标

在写下第一行代码之前,你需要确定你的库的功能——你需要设置一个目标。通过这个目标,你可以专注于你想利用这个库来解决的问题。要牢记你的代码库的原本的形式在解决问题上要更容易使用和记忆。API越简单,使用者学习你的代码库就更容易。引入一个Unix的设计哲学:

只做一件事情并把它做好

问下你自己:你的代码库解决了什么问题?你打算怎么取解决它?你将会一个人完成全部工作,还是引入别人的代码库?

不管代码库体积有多大,尝试制作一个路线图。列出你想要的每一个特性,并将它们尽可能的打散,知道你有一个小巧但是能解决问题的代码库,就像 minimum viable product。这会成为你的第一个版本。从这里开始,你可以在每一个新特性建立里程碑。从本质上来说,你把你的项目变成了比特级的代码块,让每一个特性完成的更好和更有趣。相信我,这会让你保持状态良好。

API设计

在我看来,我想以使用者的角度来开发我的代码库。你可以称呼它为以用户为中心的设计。在本质上,你正在创造你的代码库的大纲,给予它更多的思考和让选择它的人使用起来更方便。在同时,你需要思考在什么地方需要可以定制,这会在这篇文章的后面讨论。

终极的API测试是尝试一下自己的技术,在你的项目使用你的代码库。试着用你的代码库替换之前的代码,看它是否满足了你想要的特性。试着让你的代码库尽可能的直观,让它可以更灵活的在边界条件下使用,还有定制化(在之后的文章会讲述)。

这是一个关于用户代理字符串的代码库的大纲的可能会有样子:

// Start with empty UserAgent string var userAgent = new UserAgent; 
// Create and add first product: EvilCorpBrowser/1.2 (X11; Linux; en-us) var application = new UserAgent.Product('EvilCorpBrowser', '1.2');
application.setComment('X11', 'Linux', 'en-us');
userAgent.addProduct(application); // Create and add second product: Blink/20420101 var engine = new UserAgent.Product('Blink', '20420101');
userAgent.addProduct(engine); // EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101 userAgent.toString(); 
// Make some more changes to engine product engine.setComment('Hello World'); // EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101 (Hello World) userAgent.toString();

根据你的代码的复杂度,你可能会在组织结构上花费一些时间。利用设计模式是组织你的代码库的好办法,甚至可以解决一些技术问题。这还能避免加入新特性带来的大面积重构。

灵活性和定制性

灵活性是让代码库变得强大的要素,但是确定可以定制与不能定制的界限是很困难的。 chart.js 和D3.js是很好的例子。这两个代码库都是用来进行数据可视化的。Chart.js可以很简单的创建不同形式的内置图表。但是如果你想对图像进行更多的掌控,D3.js才是你需要的。

有好几种方法可以把控制权交给用户:配置,暴露公共方法,通过回调和事件。

配置代码库通常在初始化之前完成。但是一些代码库允许尼在运行时对配置进行修改。配置通常被细小的部分限制,只有为了之后的使用而修改它们的数值才是被允许的。

// Configure at initialization var userAgent = new UserAgent({
  commentSeparator: ';' }); // Run-time configuration using a public method userAgent.setOption('commentSeparator', '-'); 
  // Run-time configuration using a public property userAgent.commentSeparator = '-';

方法通常是暴露给实例使用的,比如说从实例中获取数据,或者设置实例的数据和执行操作。

var userAgent = new UserAgent; // A getter to retrieve comments from all products userAgent.getComments(); 
// An action to shuffle the order of all products userAgent.shuffleProducts();

回调通常是在公共的方法中被传递的,通常在异步操作后执行用户的代码。

var userAgent = new UserAgent;

userAgent.doAsyncThing(function asyncThingDone() { // Run code after async thing is done });

事件有很多种可能。有点像回调,除了增加事件句柄是不应该触发操作的。事件通常用于监听,你可能会猜到,这可是事件!更像回调的是,你可以提供更多的信息和返回一个数值给代码库去进行操作。

var userAgent = new UserAgent; // Validate a product on addition userAgent.on('product.add', function onProductAdd(e, product) { 
var shouldAddProduct = product.toString().length < 5; // Tell the library to add the product or not return shouldAddProduct;
});

在一些例子中,你可能允许用户对你的代码库进行扩展。因此,你需要暴露一些公共方法或者属性来让用户填充,像Angular的模块 (angular.module('myModule'))和Jquery的 fn(jQuery.fn.myPlugin)或者什么都不做,只是简单的让用户获取你的代码库的命名空间:

// AngryUserAgent module // Has access to UserAgent namespace (function AngryUserAgent(UserAgent) { 
// Create new method .toAngryString() UserAgent.prototype.toAngryString = function() { return this.toString().toUpperCase();
  };

})(UserAgent); // Application code var userAgent = new UserAgent; // ... // EVILCORPBROWSER/1.2 (X11; LINUX; EN-US) BLINK/20420101 userAgent.toAngryString();

类似的,这允许你重写方法。

// AngryUserAgent module (function AngryUserAgent(UserAgent) { // Store old .toString() method for later use var _toString = UserAgent.prototype.toString; 
// Overwrite .toString() UserAgent.prototype.toString = function() { return _toString.call(this).toUpperCase();

  };

})(UserAgent); var userAgent = new UserAgent; // ... // EVILCORPBROWSER/1.2 (X11; LINUX; EN-US) BLINK/20420101 userAgent.toString();

在后面的例子中,允许你的用户获取代码库的命名空间,让你在对扩展和插件的定义方面上的控制变小了。为了让插件遵循一些约定,你可以(或者是应该)写下文档。

测试

对测试驱动开发(test-driven development)来 说,写下大纲是良好的开始。简单来说,指的是在你写实际的代码库之前,在你写下测试准则的时候。如果测试检查的是你的代码特性是否跟期待的一样,以及你在 写代码库之前写测试,这就是行为驱动开发。不管怎样,如果你的测试覆盖了你的代码库的每一个特性,而且你的代码通过了所有的测试。你可以确定你的代码是可 以正常工作的。

Jani Hartikainen讲述了如何利用Mocha来进行单元测试 Unit Test Your JavaScript Using Mocha and Chai。在使用Jsmine,Travis,Karma测试JavaScript (Testing JavaScript with Jasmine, Travis, and Karma)这篇文章中,Tim Evko展示了怎么通过另一个叫做Jasmine的框架来设置良好的测试流程。这两个测试框架都是非常流行的,但还有适应别的需求的其他框架。

我在这篇文章前面撰写的大纲,已经讲述了它期待怎样的输出。这是一切测试的开始:从期望出发。关于我的代码库的一个Jasmine测试像是这样:

describe('Basic usage', function () {
  it('should generate a single product', function () { // Create a single product var product = new UserAgent.Product('EvilCorpBrowser', '1.2');
    product.setComment('X11', 'Linux', 'en-us');

    expect(product.toString())
      .toBe('EvilCorpBrowser/1.2 (X11; Linux; en-us)');
  });

  it('should combine several products', function () { var userAgent = new UserAgent; 
  // Create and add first product var application = new UserAgent.Product('EvilCorpBrowser', '1.2');
    application.setComment('X11', 'Linux', 'en-us');
    userAgent.addProduct(application); // Create and add second product var engine = new UserAgent.Product('Blink', '20420101');
    userAgent.addProduct(engine);

    expect(userAgent.toString())
      .toBe('EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101');
  });

  it('should update products correctly', function () { var userAgent = new UserAgent; 
  // Create and add first product var application = new UserAgent.Product('EvilCorpBrowser', '1.2');
    application.setComment('X11', 'Linux', 'en-us');
    userAgent.addProduct(application); // Update first product application.setComment('X11', 'Linux', 'nl-nl');

    expect(userAgent.toString())
      .toBe('EvilCorpBrowser/1.2 (X11; Linux; nl-nl)');
  });
});

一旦你对你的API设计的第一个版本完全满意,是时候开始思考结构和你的代码库应该如何被使用。

模块加载器兼容性

你或许使用过模块加载器。使用你的代码库的开发者有可能使用加载器,所以你会希望自己的代码库与模块加载器是兼容的。但兼容哪一个呢?应该怎么从CommonJS,RequireJS,AMD和其他加载器中挑选呢?

实际上,你不需要挑选!通用模块定义(UMD)是一个目标就是支持多种加载器的规则。你可以在网上找到不同风格的代码段,或者从这里 UMD GitHub repository学习并让它与你的代码库兼容。从其中的某个模板开始,或者使用你喜欢的构建工具add UMD with your favorite build tool,你就不必再担心模块加载器的问题了。

如果你希望用上ES2015的 import/export 语法,我建议使用Babel和Babel’s UMD plugin来将代码转换成ES5。通过这个方法你可以在你的项目中使用ES2015,同时生成兼容性良好的代码库。

文档

我完全赞成在每一个项目中使用文档。但这通常牵涉到大量的工作,导致编写文档被推迟和在最后被遗忘。

基本信息

文档的编写应当从项目的名字和描述之类基本的信息开始。这会对别人明白你的代码库做了什么和是否对他们有用有所帮助。

你可以提供像是适用范围和目标之类的信息来更好的给用户提供信息,而提供路线图可以让他们明白在未来可能会有什么新变化以及他们可以提供怎样的帮助。

API,教程和例子

当然,你需要确保用户知道如何去使用你的代码库。这从API文档开始。教程和例子是很好的补充,但编写他们会是一个庞大的工作。然而,内联文档Inline documentation不会这样。下面是一些利用JSDoc的,可以被解析和转换成文档页的注释

元任务

一些用户想对你的代码库作出改进。在大多数情况中,会是贡献代码,但有一些会创建一个私人使用的定制版本。对于这些用户,为类似构建代码库,运行测试,生成,转换和下载数据之类的元任务提供文档很有帮助的。

贡献

当你对你的代码库进行开源,得到代码贡献是很有帮助的。为了引导贡献者,你可以增加一些关于贡献代码的步骤和需要满足的标准的文档。这会对你审阅和接纳贡献的代码和他们正确的贡献代码有所帮助。

授权许可

最后一点,使用授权许可。从技术上讲,即时你没有选择任何一种技术许可,你的代码库依然是拥有版权的,但不是每一个人都知道这一点。

我发现 ChooseALicense.com这个网站可以让你一个不需要成为法律专家也能挑选授权许可。在挑选授权许可之后,只需要在项目的根目录下添加 LICENSE.txt 文件。

将它打包和发布到包管理器

对一个好的代码库来说,版本是很重要的。如果你想要加入重大的变化,用户可能需要保留他们现在正在使用的版本。

Semantic Versioning是流行的版本命名标准,或者叫它SemVer。SemVer版本包括三个数字,每一个代表不同程度的改变:重大改变,微小的改变和补丁

在你的Git仓库加入版本和发布

如果你有一个git仓库,你可以在你的仓库添加版本数字。你可以把它想象成你的仓库的快照。我们也叫它标签 Tags。可以通过开启终端和输入下面的文字来创造标签:

# git tag -a [version] -m [version message]
git tag -a v1.2.0 -m "Awesome Library v1.2.0"

很多类似GitHub的服务会提供关于所有版本的概览和提供它们的下载链接。

发布一个通用仓库

npm

许多编程语言自带有包管理器,或者是第三方包管理器。这可以允许我们下载关于这些语言的特定代码库。比如PHP的Composer 和Ruby的RubyGems

Node.js,一种独立的JavaScript引擎,拥有 npm,如果你对npm不熟悉,我们有一个很好的教程beginner’s guide。

默认情况下,你的npm包会发布为公共包。不要害怕,你也可以发布私有包 private packages, 设置一个私有的注册private registry, 或者根本不发布avoid publishing.

为了发布你的包,你的项目需要有一个 package.json 文件。你可以手动或者交互问答的方式来创建。通过输入下面的代码来开始问答:

`npm init`

这个版本属性需要跟你的git标签吻合。另外,请确定有README.md 文件。像是GitHub,npm在你的包的展示页使用它。

之后,你可以通过输入下面的代码来发布你的包:

`npm publish`

就是这样!你已经成功发布了你的npm包。

Bower

几年前,有另一个叫做Bower的包管理器。这个包管理器,实际上不是为了特定的语言准备的,而是为了互联网准备的。你可以发现大部分是前端资源。在Bower发布你的包的关键一点是你的代码库是否跟它兼容。

如果你对Bower不熟悉,我们也有一个教程beginner’s guide 。

跟npm一样,你也可以设置一个私有仓库private repository。你可以通过问答的方式避免发布。

有趣的是,在最近的一两年,很多人转为使用npm管理前端资源。近段npm包主要是跟JavaScript相关,大部分的前端资源也发布在了npm上。不管怎样,Bower仍然流行。我明确的推荐你在Bower上发布你的包。

我有提到Bower实际上是npm的一种模块,并最初是得到它的启发吗?它们的命令是很相似的,通过输入下面的代码产生bower.json文件:

`bower init`

跟npm init类似,指令是很直白的,最后,发布你的包:

`bower register awesomelib http://www.php.cn/`

像是把你的代码库放到了野外,任何人可以在他们的Node项目或者网络上使用它!

总结

核心的产品是库文件。确定它解决了问题,容易和适合使用,你会使得你的团队或者许多开发者变得高兴。

我提到的很多任务都是自动化的,比如:运行测试,创建标签,在package.json升级版本或者在npm或者bower重发布你的包。 这是你像Travis CI 或 Jenkins一样踏入持续集成和使用工具的开始。我之前提到的文章 article by Tim Evko 也讲述到了这点。

你构建和发布代码库了吗?请在下面的评论区分享!

 

以上就是设计和构建你自己的JavaScript代码库:提示与技巧的内容,更多相关内容请关注PHP中文网(www.php.cn)!

MvMmall 网店系统
MvMmall 网店系统

免费的开源程序长期以来,为中国的网上交易提供免费开源的网上商店系统一直是我们的初衷和努力奋斗的目标,希望大家一起把MvMmall网上商店系统的免费开源进行到底。2高效的执行效率由资深的开发团队设计,从系统架构,数据库优化,配以通过W3C验证的面页模板,全面提升页面显示速度和提高程序负载能力。3灵活的模板系统MvMmall网店系统程序代码与网页界面分离,灵活的模板方案,完全自定义模板,官方提供免费模

下载


相关文章

java速学教程(入门到精通)
java速学教程(入门到精通)

java怎么学习?java怎么入门?java在哪学?java怎么学才快?不用担心,这里为大家提供了java速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
Golang gRPC 服务开发与Protobuf实战
Golang gRPC 服务开发与Protobuf实战

本专题系统讲解 Golang 在 gRPC 服务开发中的完整实践,涵盖 Protobuf 定义与代码生成、gRPC 服务端与客户端实现、流式 RPC(Unary/Server/Client/Bidirectional)、错误处理、拦截器、中间件以及与 HTTP/REST 的对接方案。通过实际案例,帮助学习者掌握 使用 Go 构建高性能、强类型、可扩展的 RPC 服务体系,适用于微服务与内部系统通信场景。

8

2026.01.15

公务员递补名单公布时间 公务员递补要求
公务员递补名单公布时间 公务员递补要求

公务员递补名单公布时间不固定,通常在面试前,由招录单位(如国家知识产权局、海关等)发布,依据是原入围考生放弃资格,会按笔试成绩从高到低递补,递补考生需按公告要求限时确认并提交材料,及时参加面试/体检等后续环节。要求核心是按招录单位公告及时响应、提交材料(确认书、资格复审材料)并准时参加面试。

44

2026.01.15

公务员调剂条件 2026调剂公告时间
公务员调剂条件 2026调剂公告时间

(一)符合拟调剂职位所要求的资格条件。 (二)公共科目笔试成绩同时达到拟调剂职位和原报考职位的合格分数线,且考试类别相同。 拟调剂职位设置了专业科目笔试条件的,专业科目笔试成绩还须同时达到合格分数线,且考试类别相同。 (三)未进入原报考职位面试人员名单。

58

2026.01.15

国考成绩查询入口 国考分数公布时间2026
国考成绩查询入口 国考分数公布时间2026

笔试成绩查询入口已开通,考生可登录国家公务员局中央机关及其直属机构2026年度考试录用公务员专题网站http://bm.scs.gov.cn/pp/gkweb/core/web/ui/business/examResult/written_result.html,查询笔试成绩和合格分数线,点击“笔试成绩查询”按钮,凭借身份证及准考证进行查询。

11

2026.01.15

Java 桌面应用开发(JavaFX 实战)
Java 桌面应用开发(JavaFX 实战)

本专题系统讲解 Java 在桌面应用开发领域的实战应用,重点围绕 JavaFX 框架,涵盖界面布局、控件使用、事件处理、FXML、样式美化(CSS)、多线程与UI响应优化,以及桌面应用的打包与发布。通过完整示例项目,帮助学习者掌握 使用 Java 构建现代化、跨平台桌面应用程序的核心能力。

65

2026.01.14

php与html混编教程大全
php与html混编教程大全

本专题整合了php和html混编相关教程,阅读专题下面的文章了解更多详细内容。

36

2026.01.13

PHP 高性能
PHP 高性能

本专题整合了PHP高性能相关教程大全,阅读专题下面的文章了解更多详细内容。

75

2026.01.13

MySQL数据库报错常见问题及解决方法大全
MySQL数据库报错常见问题及解决方法大全

本专题整合了MySQL数据库报错常见问题及解决方法,阅读专题下面的文章了解更多详细内容。

21

2026.01.13

PHP 文件上传
PHP 文件上传

本专题整合了PHP实现文件上传相关教程,阅读专题下面的文章了解更多详细内容。

35

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
CSS3 教程
CSS3 教程

共18课时 | 4.6万人学习

Git 教程
Git 教程

共21课时 | 2.7万人学习

Django 教程
Django 教程

共28课时 | 3.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号