前言
-
本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
-
这是源码共读的第26期,链接:juejin.cn/post/708743… 。
学习目标
-
学习classnames用法
-
classnames的原理
-
了解package.json中的files和types字段
classnames用法
通过代码和测试用例了解到,该库可以string、number、Boolean、undefined、null、Object、Array等类型进行处理,在react框架中会常用到这个库
npm install classnames // 安装包
const classNames = require('classnames');
classNames('foo', 'bar'); // => 'foo bar'
classNames(null, false, 'bar', undefined, 0, 1, { baz: null }, ''); // => 'bar 1'
classnames原理
- git clone github.com/JedWatson/c… 下载项目
- 打开package.json文件,可以看到
tests/
目录下存放着相关文件的测试用例 - index.js文件为入口文件,代码里面主要做了两件事:
- classNams函数主要处理非真、字符串和数字、Array、Object这几个类型;
- 对classNames导出方法的处理兼容三种方式:commonjs、amd、浏览器全局挂载;
- 对象处理的一个巧妙之处
// 这里是对于如何判断toString方法是否被重写的判断
arg.toString !== Object.prototype.toString && !arg.toString.toString().includes('[native code]')
//测试用例是对上述判断的测试
it('handles toString() method defined on object', function () {
assert.equal(classNames({
toString: function () { return 'classFromMethod'; }
}), 'classFromMethod');
});
- 数组处理(递归)
// classnames函数中对基本类型和引用类型都做了判断处理,数组处理过程中,通过调用classNames方法逐个判断每个字段的类型处理,巧妙的运用了递归思想
if (Array.isArray(arg)) { // 处理Array类型
if (arg.length) {
var inner = classNames.apply(null, arg);
if (inner) { classes.push(inner); }
}
}
CMD、AMD、UMD 、commonjs和 ES Modules之间的区别
- AMD:主要是浏览器上使用,异步加载模块,使用define定义,require加载模块,模块定义时加载
- CMD:在模块使用时加载,适用于服务器端的模块化开发,其中模块加载是同步的,
define(function(require, exports, module) { ... })
- UMD:是AMD和Commonjs的兼容写法
- commonjs:主要服务器上使用,module.export 和 require,模块在被加载后会立即执行;
- es modules:es6规范,可以用在浏览器和nodejs中,export和import方式
package.json中的types和files作用
- types:
- 指定模块的类型定义文件的位置
- 可以一个或多个文件指定
- 当其他开发人员使用你的模块时,他们可以使用 TypeScript 编写代码,并使用你的类型定义文件来获得代码补全和类型检查等功能
- files
- 用于指定哪些文件或目录应该包括在你的包中,以便在发布时将它们打包
- 若没有指定,npm 会打包你的项目根目录中的所有文件和文件夹,包括一些不必要的文件如测试文件、文档等
- files的优先级会高于.npmignore
- 通常情况下需要指定下,以便减少打包体积
总结
- classNames库归根到底还是对不同类型的处理,考察的是基础知识;
- package.json包中的files和types配置对于库的优化比较有益;
- 通过这个库也了解到了对于不同规范的兼容处理写法