JavaScript 中有字串的 trim
方法,但却没有阵列的 trim
,现在就来尝试实作一个阵列的 trim
吧。
本文的範例不考虑型别错误等问题,聚焦于方法本身的说明。
字串的 trim
在实作前,我们先来了解一下 trim
这个方法的功用,在字串的 trim
中,会将前后的空白字元,包括行的结束字符从字串中去除,例如下面这字串:
` helloworld `
使用了 trim
回传的结果为:
大部分的情况下,由于字串前后的空白及换行字元多半是没有意义且容易造成 bug 产生,例如比对字串是否相等时:
'hi' === 'hi ' // false
这时候 trim
就很有用处:
'hi'.trim() === 'hi '.trim() // true
除了前后都作用的 trim
之外,也有只作用一边的方法:
' ya '.trimStart() // 'ya '' ya '.trimEnd() // ' ya'
特定字元的 trim
前面内建的 trim
很好用,但如果想要删去的是除了空白和换行字元以外的其他字元呢?例如:底线(_
)或是小老鼠(@
)。
这是就需要自製的方法来达成,首先设计介面:
function trimChar(string, chars) {...}
string
: String
型别,原字串chars
: String
型别,要删除的字元回传值是 trim
作用过的字串也可以直接写在
String
的prototype
上:String.prototype.trimChar = function(chars) {...}
。
接下来实作方法:
function trimChar(string, chars) { const strArr = string.split(''); // 找到第一个不排除的字元索引 const start = strArr.findIndex(ch => !chars.includes(ch)); if(start === -1) return ''; // 找到最后一个不排除的字元索引 let reverseStart = strArr.slice().reverse().findIndex(ch => !chars.includes(ch)); const end = string.length - reverseStart; // 去头去尾 return strArr.slice(start, end).join('');}
trimChar('!hello!@world@', '!@'); // "hello!@world"
因为要仰赖阵列处理,先将字串分割为字元阵列使用 findIndex
找到第一个不排除的字元索引如果找不到的话,代表整个字串都是想要排除的字元组成,因此回传空字串将原字串反转找出第一个不排除的字元,此为最后一个不排除的字元的索引由于取得的索引是反转后的,所以需要利用字串长度反转回正确的索引用 slice
删除前后想要排除的字元,并合併后回传这样 trim
特定字元的方法就建置完成了。
只 trim 开头/结尾特定字元
上面的是前后都 trim
的方法,想想如果只 trim
开头或结尾其一的方法怎么写呢?
function trimCharStart(string, chars) { const strArr = string.split(''); // 找到第一个不排除的字元索引 const start = strArr.findIndex(ch => !chars.includes(ch)); if(start === -1) return ''; // 直接取长度当作结尾索引 const end = string.length; // 去头去尾 return strArr.slice(start, end).join('');}function trimCharEnd(string, chars) { const strArr = string.split(''); // 直接取 0 为开头索引 const start = 0; // 找到最后一个不排除的字元索引 let reverseStart = strArr.slice().reverse().findIndex(ch => !chars.includes(ch)); const end = string.length - reverseStart; // 去头去尾 return strArr.slice(start, end).join('');}
trimCharStart('!hello!@world@', '!@'); // "hello!@world@"trimCharEnd('!hello!@world@', '!@'); // "!hello!@world"
只要将开头/结尾的索引设回原本的值就可以了。
阵列中的 trim
看了字串的 trim
实作后,对于阵列的 trim
有没有一点概念了呢?接着就来想一下改怎么处理阵列的部分吧。
阵列 trim 的定义
首先先来定义阵列 trim
介面:
function arrayTrim(array, exclude) {...}
array
: any[]
型别,原阵列exclude
: element => boolean
型别,要排除的元素传回 true
的回呼函数回传值是 trim
作用过的阵列同字串
trim
也可以写在Array.prototype
上。
可以先试着用上面字串的思维想想要怎么实作 arrayTrim
。
实作 arrayTrim
function arrayTrim(array, exclude) { // 找到第一个不排除的字元索引 const start = array.findIndex(ch => !exclude(ch)); if(start === -1) return ''; // 找到最后一个不排除的字元索引 let reverseStart = array.slice().reverse().findIndex(ch => !exclude(ch)); const end = array.length - reverseStart; // 去头去尾 return array.slice(start, end);}
可以发现跟字串的方法大同小异,这是因为在上面讲解字串 trim
时刻意使用阵列的思路来说明,要不然字串可以使用正规表达式写出更简洁的方法,详细可以参考 StackOverflow 上的解答。
// ex1arrayTrim(['!', 'hello', '!', '@', 'world', '@'], element => ['!', '@'].includes(element));// ["hello", "!", "@", "world"]// ex2arrayTrim([[0, '@'], [1, 'hello'], [2, '!'], [3, '@'], [4, 'world'], [5, '@']], element => ['!', '@'].includes(element[1]));// [[1, 'hello'], [2, '!'], [3, '@'], [4, 'world']]
阵列的第二个参数会需要是回呼函数,因为阵列中可能会是複杂结构,像是第二个例子一样。
只
trim
阵列的开头/结尾的方法就交给各位想想喽~
结论
会需要这个方法是由于最近处理到时间流的资料,他的资料会像下面这样:
const datapoints = [ [622,1450754160000], [587,1450754220000], [622,1450754280000], [123,1450754340000], [622,1450754400000], [851,1450754460000]];
待在某个时间点的资料有可能是 null
:
const datapoints = [ [null,1450754160000], [587,1450754220000], [null,1450754280000], [123,1450754340000], [622,1450754400000], [null,1450754460000]];
绘图时前后的资讯是不需要的,因为那个时间点本来就还没有资料或是已经没有资料了,但中间的资料如果是 null
的话就需要将图上的那个时间画为 0 值,否则前后的资料会相连使人误以为这是连续的数值。
参考资料
MDN: String.prototype.trim()MDN: Array.prototype.findIndex()Sonya Moisset: Reverse a String in JavaScriptstackoverflow: Trim specific character from a stringLodash: trim同步发表于 Limitless Ping