挑战看200 个npm模块源码:第2个
目录:
一、介绍
二、个人手写
1、个人未看源码思路
2、个人手写代码
三、源码分析
1、源码思路
四、总结
字数:大约1000字
一、介绍
名称:to-camel-case
地址:https://github.com/ianstormtaylor/to-camel-case.git。
示例:
const toCamelCase = require('to-camel-case')
const strings = {
camel: 'thisIsAString',
constant: 'THIS_IS_A_STRING',
dot: 'this.is.a.string',
pascal: 'ThisIsAString',
sentence: 'This is a string.',
snake: 'this_is_a_string',
space: 'this is a string',
title: 'This Is a String',
junk: '-this__is$%a-string...'
}
for (var key in strings){
// thisIsAString
toCamelCase(strings[key]);
}
二、个人手写
同样的,如果是我们自己手写,你应该怎样写,请思考1分钟继续往下面看。或者你看看我没有看过这个源码之前我的写法是怎样的。10分你能给我几分?
1、个人未看源码思路
1、将特殊字符分割(split)得到数组['THIS','IS','STRING']
2、将字符串都转为小写
3、数组第一位转为小写,其他位首字符转为大写
4、拼接即可...['THIS','IS','STRING']
按照这个思路,我们实现的代码是这样的:
2、个人手写代码
// 单词首字符大写
const capitalize = (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
};
// 单词首字符小写
const capitalizeLow = (str) => {
return str.charAt(0).toLowerCase() + str.slice(1);
};
const toCamelCase = (str) => {
// 将参数转为字符串
const _str = str + "";
// 正则分割字符串
const camelList = _str.split(/[,_, ,%,$,.,-]/);
// 过滤单词数组
let chartC = camelList.filter((item) => item);
// 第一个单词不需要小写
let chartT = chartC.map((item,index) => camelList.length === 1 ? item : item.toLowerCase());
// 第一个单词首字母需要小写
// 其他单词首字母需要大写
let chartFT = chartT.map((item, index) => index === 0 ? capitalizeLow(item) : capitalize(item));
// 拼接字符串
return chartFT.join("");
};
测试
const strings = {
camel: "thisIsAString",
constant: "THIS_IS_A_STRING",
dot: "this.is.a.string",
pascal: "ThisIsAString",
sentence: "This is a string.",
snake: "this_is_a_string",
space: "this is a string",
title: "This Is a String",
junk: "-this__is$%a-string...",
};
for (var key in strings) {
// thisIsAString
toCamelCase(strings[key]);
}
这样,我们的代码就写出来了,这个模块不会存在大量重复的动作,所以就不讲究性能了。接下来看看源码。一起学习。
三、源码分析
那我们就要看看人家写的源码。
function toCamelCase(string) {
return toSpaceCase(string).replace(/\s(\w)/g, function (matches, letter) {
return letter.toUpperCase()
})
}
function toSpaceCase(string) {
return toNoCase(string).replace(/[\W_]+(.|$)/g, function (matches, match) {
return match ? ' ' + match : ''
}).trim()
}
var hasSpace = /\s/
var hasSeparator = /(_|-|\.|:)/
var hasCamel = /([a-z][A-Z]|[A-Z][a-z])/
function toNoCase(string) {
if (hasSpace.test(string)) return string.toLowerCase()
if (hasSeparator.test(string)) return (unseparate(string) || string).toLowerCase()
if (hasCamel.test(string)) return uncamelize(string).toLowerCase()
return string.toLowerCase()
}
/**
* Separator splitter.
*/
var separatorSplitter = /[\W_]+(.|$)/g
/**
* Un-separate a `string`.
*
* @param {String} string
* @return {String}
*/
function unseparate(string) {
return string.replace(separatorSplitter, function (m, next) {
return next ? ' ' + next : ''
})
}
/**
* Camelcase splitter.
*/
var camelSplitter = /(.)([A-Z]+)/g
/**
* Un-camelcase a `string`.
*
* @param {String} string
* @return {String}
*/
function uncamelize(string) {
return string.replace(camelSplitter, function (m, previous, uppers) {
return previous + ' ' + uppers.toLowerCase().split('').join(' ')
})
}
1、源码思路
他的思路是不同情况,去不同处理法:
var hasSpace = /\s/
var hasSeparator = /(_|-|\.|:)/
var hasCamel = /([a-z][A-Z]|[A-Z][a-z])/
function toNoCase(string) {
if (hasSpace.test(string)) return string.toLowerCase()
if (hasSeparator.test(string)) return (unseparate(string) || string).toLowerCase()
if (hasCamel.test(string)) return uncamelize(string).toLowerCase()
return string.toLowerCase()
}
如果是没有特殊字符,就执行uncamelize(string)
var camelSplitter = /(.)([A-Z]+)/g
function uncamelize(string) {
return string.replace(camelSplitter, function (m, previous, uppers) {
return previous + ' ' + uppers.toLowerCase().split('').join(' ')
})
}
string.replace这里发挥着重要作用,replace是有2个参数的,第二个参数是回调函数,每次匹配都要调用回调函数。上面这里就是他会自动找到字符串中大写的字母的位置,拿thisIsAString举例,第一次进入replace,回调的参数是m: "sI",previous: "s",uppers: "I",然后将小写加上空格,大写变小写。这样就可以得到“this is a string"。
然后返回之后,
function toCamelCase(string) {
return toSpaceCase(string).replace(/\s(\w)/g, function (matches, letter) {
return letter.toUpperCase()
})
}
/\s(\w)/g正则匹配空格后的第一个单词首字母,转为大写。
同理,有特殊字符的也是按照这个逻辑。再细的细节就不纠结了。
四、总结
1、replace可以匹配字符串和正则。还有第二个参数,可以是字符串也可以是回调函数。
2、功能模块尽量写得便于拓展。我自己的那个方法很难拓展。他写的你如果想要拓展是很容易的。