Skip to content

挑战看200 个npm模块源码:第2个

目录:

一、介绍

二、个人手写

1、个人未看源码思路

2、个人手写代码

三、源码分析

1、源码思路

四、总结

字数:大约1000字

一、介绍

名称:to-camel-case

地址:https://github.com/ianstormtaylor/to-camel-case.git。

示例:

js
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、个人手写代码

js
// 单词首字符大写
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("");
};

测试

js
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]);
}

这样,我们的代码就写出来了,这个模块不会存在大量重复的动作,所以就不讲究性能了。接下来看看源码。一起学习。

三、源码分析

那我们就要看看人家写的源码。

js
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、源码思路

他的思路是不同情况,去不同处理法:

js
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)

js
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"。

然后返回之后,

js
function toCamelCase(string) {
  return toSpaceCase(string).replace(/\s(\w)/g, function (matches, letter) {
    return letter.toUpperCase()
  })
}

/\s(\w)/g正则匹配空格后的第一个单词首字母,转为大写。

同理,有特殊字符的也是按照这个逻辑。再细的细节就不纠结了。

四、总结

1、replace可以匹配字符串和正则。还有第二个参数,可以是字符串也可以是回调函数。

2、功能模块尽量写得便于拓展。我自己的那个方法很难拓展。他写的你如果想要拓展是很容易的。