使用JavaScript的内置字符串函数

216 阅读9分钟

简介

在使用任何一种编程语言时,你可能会需要一些没有被原生集成到该语言中的功能。因此,你要么自己实现它们,要么转向使用各种模块或库。

这直接影响了你的应用程序的效率(更多的内存使用,更多的HTTP请求,等等)。为了避免这种情况,从事先进的编程语言的开发人员在语言中集成了一些功能,以帮助避免在常用任务中使用外部库。

熟悉这些内置函数被认为是一种语言的基本知识,而且仅靠内置函数你仍然可以走得很远。当然,你很可能最终会使用一些模块/库来完成某些任务。

在这个面向初学者的指南中,我们将看一下与字符串有关的JavaScript内置函数。

JavaScript的数据类型、结构和对象的内置函数

在JavaScript中,有八种数据类型

  1. 字符串
  2. 数字
  3. 布尔型
  4. 空值
  5. 未定义
  6. 符号
  7. 大英数
  8. 对象

然而,并不是每个数据类型都有一个内置函数。它们只被定义在字符串、数字和布尔

说到JavaScript中的数据结构最常用的七个结构是。

  1. 数组
  2. 堆栈
  3. 队列
  4. 链接列表
  5. 树状结构
  6. 哈希表

与数据类型类似,在数据结构中,内置函数只在数组中定义。最后,JavaScript中的对象也有内置函数,如Date、RegExp和Math

在本指南中,我们将特别关注字符串。

JavaScript中的内置字符串函数

如前所述,字符串是JavaScript中八种数据类型中的一种。它在本质上是一个字符数组(string)

此外,值得注意的是,字符串是不可改变的--一旦字符串对象被创建,它就不能被改变。任何改变字符串的函数都会创建一个新的字符串对象并返回,而不是修改原来的对象。

鉴于字符串只是数组的事实--你可以把它们当作数组,并通过array[index] 符号检索元素。

既然如此,让我们从与字符串有关的内置函数开始。

toString()

toString() 是与字符串有关的最常用的函数之一。它属于所有 Object,并返回对象的字符串表示,有效地将任何类型的对象转换为其字符串表示。

let x = 100;
console.log(x.toString()); // Output: 100

toString() 它对每个对象的表现都不同,取决于它对该函数的实现--将该对象表示为字符串的含义。此外,请注意,如果你把算术运算中的任何元素改为字符串--JavaScript会推断出这是一种连接的尝试。

let x = 100;
let y = 200;
   
let z1 = x+y;
let z2 = x.toString() + y;
   
console.log(z1); // Output: 300 
console.log(z2); // Output: 100200

在这里,z1Number类型的,因为我们要把Number类型的变量加在一起,而z2String类型的,因为第一个变量是String类型的,而y 在内部被转化为String并附加到x 。 如果你想把一个算术结果转化为字符串--请确保在最后执行转换。

concat()

concat() 将两个字符串加在一起并返回一个新的字符串。

let x = "some ";
let y = "string";
   
console.log(x.concat(y)); // Output: some string

它实质上执行的操作与:

let x = "some";
let y = "string";
   
console.log(x+y); // Output: some string

实际上,由于性能上的好处,建议首选concat() 函数,而不是操作数。然而,你不会从连接单个字符串中获得多少好处--对于大量的字符串,你会获得性能上的好处。让我们快速地进行基准测试。

console.time('Concatenating with Operator');
concatWithOperator();
console.timeEnd('Concatenating with Operator');

console.time('Concatenating with Function');
concatWithFunction();
console.timeEnd('Concatenating with Function');

function concatWithOperator() {
    let result = "";
    for (let i = 0; i < 10000; i++) {
      result = result += i;
    }
}

function concatWithFunction() {
    let result = "";
    for (let i = 0; i < 10000; i++) {
      result = result.concat(i);
    }
}

这样的结果是:

Concatenating with Operator: 3.232ms
Concatenating with Function: 1.509ms

在这段代码上,该函数的速度大约是2倍。还值得注意的是MDN的官方声明,关于性能的好处。

强烈建议使用赋值运算符(+,+=)而不是concat()方法。

这可能看起来很奇怪,因为在测试中concat() ,性能优于运算符。这是为什么呢?好吧,对这样的代码进行基准测试并不像简单地运行它和观察结果那么容易。

你的浏览器,它的版本,以及它使用的优化器可能因机器而异,像这样的属性确实会影响性能。例如,我们在连接中使用了不同的字符串,即迭代产生的字符串。如果我们使用相同的字符串,像谷歌的V8这样的优化器会进一步优化字符串的使用。

作为一个经验法则--测试和验证你自己的代码,而不是听信建议。

toLocaleUpperCase()toUpperCase()

toLocaleUpperCase() 将给定的字符串转换为大写字母,遵守编译代码的机器上使用的locale。此外,你可以通过一个字符串参数来指定语言。

let word = "Straße";

console.log(word.toUpperCase()) // STRASSE
console.log(word.toLocaleUpperCase('de-DE')) // STRASSE

在大多数情况下,toUpperCase()toLocaleUpperCase() 将返回相同的结果,即使你没有提供locale指定符。只有在非标准的unicode映射下,比如土耳其语,toLocaleUpperCase() ,才会产生不同的结果。

toLocaleLowerCase()toLowerCase()

toLocaleLowerCase() 的执行情况与 基本相同,但将字符串转换为小写。同样, 也是不分地域的。不过,要注意的是,在大写和小写之间转换时toLocaleUpperCase() toLowerCase() 某些信息会丢失

例如,如果我们将'Straße' 转换为大写字母,然后再转换为小写字母,你会失去某些信息。

let word = "Straße";

upperCase = word.toLocaleUpperCase('de-DE')

console.log(upperCase) // STRASSE
console.log(upperCase.toLocaleLowerCase('de-DE')) // Strasse

同样,这是因为在这个例子中,德语确实遵循标准的Unicode映射,所以toLocaleLowerCase() 产生的结果与toLowerCase() 相同--它只是将每个字符改为小写的对应字符。

substring()

substring(start, end) 返回一个字符串,包含从原始字符串的索引 开始直到原始字符串的索引 的字符。start end-1

let x = "this is some string";
   
console.log(x.substring(3, 7)); // Output: s is

正如你所看到的,end 的索引不包括在内,所以输出的字符串是从startend-1

此外,这当然会返回一个新的字符串,所以你可以通过把它分配给一个新的参考变量来捕获它,或者直接把它作为一个新函数的输入。原来的字符串保持不变。

let x = "this is some string";
let y = x.substring(3, 7);
   
console.log(x); // Output: this is some string
console.log(y); // Output: s is

substring() 如果你试图用一个end ,超过字符串的length - 你将简单地将所有现有的字符子串化,直到结束。

let x = "this is some string";
console.log(x.substring(10, 25)); // Output: me string

这个函数对截断输出或输入特别有用,甚至可以检查一个字符串是否给定的子串开始包含一个子串。

substr(start, length)

substring() 相似,substr() 函数是通过从一个原始字符串中抽取某些字符来生成的。这里我们指定start 索引和所需子串的大小,即length ,而不是具体的终点。

let x = "this is some string";
   
console.log(x.substr(3, 4)); // Output: s is

如果长度超出了一个字符串的范围,你只需简单地子串,直到结束。

let x = "hello";
console.log(x.substr(3, 10)); // Output: lo

split()

split(separator, limit) 函数使用提供的separator ,将一个字符串分割成一个字符串数组,并分割成一定数量的limit

let x = "this is some string";
   
console.log(x.split(" ", 4)); // Output: ['this', 'is', 'some', 'string']

如果你没有使用任何外部库,这对于解析CSV行是很有用的,因为它们是逗号分隔的值,通过split() 函数可以很容易地进行分割。然而,在处理CSV文件时,如果它们的格式不正确,你会想进行验证。

通常情况下,你会使用库来处理这个问题,因为它们使事情变得更加容易。

charAt()string[index]

charAt(index) 函数返回指定index 的字符。

let x = "abc123";
   
console.log(x.charAt(2)); // Output: c

你可以用它来遍历一个字符串并检索其内容,例如。

let x = "some string";

for (let i = 0; i < x.length; i++) {
    console.log(x.charAt(i));
}

这就导致了:

s
o
m
e
 
s
t
r
i
n
g

x.charAt(y)x[y] 之间有什么区别?

有几个原因可以说明为什么你会喜欢charAt() 而不是数组符号。

let x = "some string";

// There is no element 5.7
console.log(x[5.7]);

// 5.7 gets rounded down to 5
console.log(x.charAt(5.7));

// The array notation makes it appear as if we can just assign
// new values to elements, even though strings are immutable
x[5] = 'g';
console.log(x);

// With charAt(), it's much more obvious that
// this line doesn't make sense and will throw an exception
x.charAt(5) = 'g';

然而,在charAt() 函数的实现中隐藏着一把双刃剑--它评估给定的索引并处理它。

这就是为什么5.7 被四舍五入为5 。它也会对实际上可能无效的输入做这个处理步骤,但会给人一种代码运行正常的假象。

let x = "some string";

console.log(x.charAt(true));
console.log(x.charAt(NaN));
console.log(x.charAt(undefined));
console.log(x.charAt([]))
console.log(x.charAt(""))

true 被转换为 ,而 将被转换为 。 , ,一个空数组和一个空字符串也被转换为 ,所以这运行得很好,尽管直觉上它不应该。1 false 0 NaN undefined 0

o
s
s
s
s

另一方面,使用更现代的数组符号。

console.log(x[true]);
console.log(x[NaN]);
console.log(x[undefined]);
console.log(x[[]]);
console.log(x[""]);

这些产生一个更直观的结果,表示输入失败。

undefined
undefined
undefined
undefined
undefined

indexOf()

indexOf(character) 返回指定的 的character第一次出现的索引值。

let x = "aaabbb";
   
console.log(x.indexOf("b")); // Output: 3

如果该字符不存在,则返回-1

let x = "some string";

console.log(x.indexOf('h')); // Output: -1

你也可以通过指定一个fromIndex 作为第二个参数,选择性地跳过第一个n 字符。

let x = "aaabbb";
   
console.log(x.indexOf("b", 4)); // Output: 4

这里,我们跳过前3个字符(基于0的索引),从第4个字符开始计数。顺便说一下,第4个字符我们要搜索的'b' ,所以会返回索引。

lastIndexOf()

lastIndexOf(character) 返回指定的 的character最后出现的索引值。

let x = "aaabbb";
    
conosle.log(x.lastIndexOf("b")); // Output: 5

indexOf() 函数适用的规则基本相同。

let x = "aaabbb";
   
console.log(x.lastIndexOf("b")); // Output: 5
console.log(x.lastIndexOf("b", 3)); // Output: 3
console.log(x.lastIndexOf("g")); // Output: -1

该方法从字符串的末尾开始向后计算,但是如果我们在这里提供一个fromIndex 参数,那么索引就从左边开始计算。在我们的例子中。

//       012345
let x = "aaabbb";
//          ↑ lastIndexOf() start

lastIndexOf()3 计到0 ,因为我们已经把fromIndex 设为3

search()

search(string) 函数搜索一个string ,如果找到,则返回找到的字符串的开头的索引。

let x = "JavaScript, often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled, and multi-paradigm.";
    
console.log(x.search("programming")); // Output: 42

如果有多个符合搜索关键词的字符串,如'JavaScript' ,则只返回第一个匹配情况的起始索引。

let x = "JavaScript, often abbreviated as JS, is a programming language that conforms to the ECMAScript specification. JavaScript is high-level, often just-in-time compiled, and multi-paradigm.";
    
console.log(x.search("JavaScript")); // Output: 0

结论

JavaScript是一种广泛使用的语言,在网络上很流行,熟悉基本的内置函数将帮助你避免使用不必要的外部库,因为你可以在vanilla JS中实现一个结果。

在本指南中,我们看了一下字符串的内置函数,这是JavaScript中最常见的数据类型之一。