【高级程序设计(第四版)】 - String

284 阅读15分钟

String是对应字符串的引用类型(原始值包装类型)。

string语法

转义字符

转义符 '\','\n', '\t','\b','\r','\f','\',''', '"', '`', '\xnn', '\unnn'这些字符字面量可以出现在字符串中的任何位置,且可以作为单个字符串解析。其中虽然这些字面量的字符长度不为1,但是在当做string计算的时候只能算成一个字符。

let text = "This is the letter sigma: \u03a3.";
console.log(text.length);

如果字符串中包含双字节字符,那么length属性返回的值可能不是准确的字符数。 第 5 章将具体讨论如何解决这个问题

字符串的特点

ECMAScript中的字符串是不可变的(immutable),意思是一旦创建,他们的值就不能改变了。如果想修改某个遍历中的字符串值,必须先销毁原始的字符串,然后将包含新值得另一个字符串保存到该变量。

 let lang = 'Java';
 lang += 'Script';
 console.log('lang', lang);

模板字面量

ECMAScript6新增了使用模板字面量定义字符串的能力,模板字面量不是字符串,而是一种页数的JavaScript句法表达式,只是求值后得到的是字符串。相较于单引号和双引号,模板字面量能够保留换行字符,可以跨行定义字符串。值得注意的是,模板字面量会保持反引号**``**内部的空格。注意字符串之间的缩进

let multilineString = 'multilineString first line\nsecond line';
//  此字符串的第二行前有空格
let multilineTemplateString = `multilineTemplateString first line
 second line
`;
console.log(multilineString);
console.log(multilineTemplateString);

字符串插值

模板字符串字面量最常用的一个特性就是支持 字符串插值,也就是可以在一个连续定义中插入一个或多个值。模板字面量在定义时立即求值并转化为字符串实例,任何插入的变量会从它们最近的作用域中取值。

所有插入的值都会使用 **toString()**强制转型为字符串,而且任何 JavaScript 表达式都可以用于插值

let stringInsertObj = { name: '焦糖瓜子' };
let stringInsertArray = ['数组', '焦糖瓜子'];
let stringInsertPrimitive = 18;
let stringInsertBoolean = true;
// * 模板字符串中被插入的值,都会通过toString强制转换为字符串
let stringInsertTemplate = `对象类字符串插值: ${stringInsertObj}
数组类字符串插值: ${stringInsertArray}
原始值字符串插值: ${stringInsertPrimitive}
布尔值字符串插值: ${stringInsertBoolean}`;
console.log(stringInsertTemplate);

查找方法

字符方法

charAt(index)

  • 参数: index介于(0-length-1),默认为0
  • 功能charAt(index)方法从一个字符串中返回指定的字符。传入超出范围的数值(默认会将传入值使用Number()转换),则会返回空字符串,若输入参数为其他类型,则使用默认index0
  • 返回值:返回字符串中指定的字符
let str = 'string';
console.log(str.charAt(3)); // i
console.log(str.charAt(true)); // t
console.log(str.charAt(10)); // ''

charCodeAt(index)

  • 参数index: 一个大于等于 0,小于字符串长度的整数
  • 功能: charCodeAt()方法返回0到65535之间的整数,表示给定索引处的 UTF-16 代码单元。 如果指定的index小于0 、等于或大于字符串的长度,则返回NaN
  • 返回值:指定index处字符的 UTF-16 代码单元值的一个数字

缺点: 如果指定位置字符串为Unicode字符,超出了 65525的范围,会返回错误的代码单元, codePointAt就是为了解决这个问题

let charCodeAtStr = 'charCodeAtStr🀄️';
console.log(` charCodeAt方法列表:
  合法index和字符【99】:${charCodeAtStr.charCodeAt(0)}
  非数字index【97】:${charCodeAtStr.charCodeAt([2])}
  非法数字类型【NaN】:${charCodeAtStr.charCodeAt(20)}
  会出错 - 超出65525的字符【55356】:${charCodeAtStr.charCodeAt(13)}
  codePointAt-65525的字符【126980】:${charCodeAtStr.codePointAt(13)}
`);

codePointAt(pos)

  • 入参: pos表示字符串中需要转码的元素的位置,范围为[0, length - 1]
  • 功能: codePointAt()方法返回一个Unicode编码点集的非负整数
  • 返回值: 字符串中给定索引的 编码单位对应的数字; 如果index不符合范围要求(index的转换问题与 charAt一致), 则返回 undefined`
let codePointAtStr = 'codePointAt🀄️';
console.log(`codePointAt方法列表:
  合法的index【111】: ${codePointAtStr.codePointAt(1)}
  非数字合法index【111】:${codePointAtStr.codePointAt([5])}
  非法数字【undefined】:${codePointAtStr.codePointAt(20)}
  超出65535字符串-对比【126980】: ${codePointAtStr.codePointAt(11)}
`);

String.fromCharCode(num1[, ...[, numN]])

  • 参数:一系列 UTF-16 代码单元的数字。范围介于 0 到 65535(0xFFFF)之间。大于 0xFFFF 的数字将被截断。不进行有效性检查
  • 功能String.fromCharCode() 方法返回由指定的 UTF-16 代码单元序列创建的字符串
  • 返回值:一个长度为 N 的字符串,由 N 个指定的 UTF-16 代码单元组成

由于 fromCharCode() 是 String 的静态方法,所以应该像这样使用:String.fromCharCode(),而不是作为你创建的 String 对象的方法

String.fromCodePoint(num1[, ...[, numN]])

  • 入参: num1, ..., numN一系列 Unicode 代码单元的数字(十六进制),范围是[0 - 65535](0xFFFF), 大于0xFFFF的数字将被截取。不进行有效性检查。
  • 功能: 静态String.formCharCode()静态方法返回使用指定的代码点序列创建的字符串
  • 返回值: 返回一个长度为N的字符串,由N个指定的Unicode代码单元组成。如果传入无效的 Unicode 编码,将会抛出一个 RangeError

因为 fromCharCode() 只作用于 16 位的值 (跟 \u 转义序列一样),为了返回一个补充字符,一个代理对是必须的。ES2015因此添加了当前方法去获取真实的码点返回补充字符

console.log(`fromCodePoint方法列表:
  返回65525范围合法值【ABC】: ${String.fromCodePoint(65, 66, 67)}
  合法的十六进制的值【꿿】:${String.fromCodePoint(0xAFFF)} 
  非十六进制【"内"】: ${String.fromCodePoint(0x2F814)}
`);

位置方法

indexOf(searchValue [, fromIndex])

  • 参数:
    • searchValue: 要被查找的字符串值。
    • fromIndex:数字表示开始查找的位置。可以是任意整数,默认值为 0
  • 功能indexof()方法返回调用String 对象的指定值最后一次出现的索引,在一个字符串中的指定位置 fromIndex处从后向前搜索。如果没找到这个特定值则返回-1
  • 返回值:查找的字符串 searchValue 的第一次出现的索引,如果没有找到,则返回 -1
let str = 'hello World';
console.log('o第一次出现的位置:', str.indexOf('o')); // 4
console.log('检测o是否出现在字符串中', str.indexOf('o') > -1); // true
// 检测o在该字符串中出现的次数
function countTimes(str, searchValue) {
  let count = 0;
  let pos = str.indexOf(searchValue);

  while (pos !== -1) {
    count++;
    pos = str.indexOf(searchValue, pos + 1);
  }
  return count;
}
console.log('o在字符串中出现的次数:', countTimes(str, 'o')); // 2

lastIndexOf(searchValue[, fromIndex])

  • 参数:
    • searchValue: 要被查找的字符串值。
    • fromIndex:待匹配字符串searchValue的开头一位字符从 str的第fromIndex位开始向左回向查找
  • 功能indexof()方法返回调用它的 String 对象中第一次出现的指定值的索引,从 fromIndex 处进行搜索。如果未找到该值,则返回 -1
  • 返回值:返回searchValue最后一次出现的索引(该索引仍是以从左至右0开始记数的),如果没找到则返回-1
let str = 'hello World';
console.log('o最末尾出现的位置:', str.lastIndexOf('o')); // 7
console.log('检测o是否出现在字符串中', str.lastIndexOf('o') > -1); // true
// 检测o在该字符串中出现的次数
function countTimes(str, searchValue) {
  let count = 0;
  let pos = str.lastIndexOf(searchValue);

  while (pos !== -1) {
    count++;
    pos = str.lastIndexOf(searchValue, pos - 1);
  }
  return count;
}
console.log('l在字符串中出现的次数:', countTimes(str, 'l')); // 3

匹配方法

match(regexp)

  • 参数regexp: 一个正则表达式对象。如果传入一个非正则表达式对象,则会隐式地使用new RegExp(obj)将其转换为一个RegExp
  • 功能match()方法检索返回一个字符串匹配正则表达式的结果
  • 返回值:(1)、如果使用g标志,则将返回与完整正则表达式匹配的所有结果,但不会返回捕获组;      (2)、如果未使用g标志,则仅返回第一个完整匹配及其相关的捕获组(Array)MDN详解

不常使用?感觉RegExp中的test等方法会更加方便

var str = 'For more information, see Chapter 3.4.5.1';
var re = /see (chapter \d+(\.\d)*)/i;
var found = str.match(re);

console.log(found);
// logs [ 'see Chapter 3.4.5.1',
//        'Chapter 3.4.5.1',
//        '.1',
//        index: 22,
//        input: 'For more information, see Chapter 3.4.5.1' ]

search(regexp)

  • 参数regexp: 一个正则表达式对象
  • 功能search()方法执行正则表达式和 String 对象之间的一个搜索匹配
  • 返回值:如果匹配成功,则 search() 返回正则表达式在字符串中首次匹配项的索引;否则,返回 -1
var str = "hey JudE";
var re = /[A-Z]/g;
var re2 = /[.]/g;
console.log(str.search(re)); // 4 (匹配到J)
console.log(str.search(re2)) // -1

replace(regexp|substr, newSubStr|function)

  • 参数regexp(pattern): 一个RegExp 对象或者其字面量。该正则所匹配的内容会被第二个参数的返回值替换掉

      substr(pattern): 一个将被 newSubStr替换的字符串。其被视为一整个字符串,而不是一个正则表达式。仅第一个匹配项会被替换

      newSubStr: 用于替换掉第一个参数在原字符串中的匹配部分的字符串

      function: 一个用来创建新子字符串的函数,该函数的返回值将替换掉第一个参数匹配到的结果 项后的新字符串。模式可以是一个字符串或者一个正则表达式,替换值可以是一个字符串或者一个每次匹配都要调用的回调函数。如果pattern是字符串,则仅替换第一个匹配项

  • 返回值:一个部分或全部匹配由替代模式所取代的新的字符串。

var re = /apples/gi;
var str = "Apples are round, and apples are juicy.";
var newStr = str.replace(re, "oranges"); // oranges are round, and oranges are juicy.
console.log(newStr);
// 交换字符串的两个单词
var reg = /(\w+)\s(\w+)/;
var string1 = "John Smith";
var replaceStr = string1.replace(reg, "$2, $1"); // Smith, John
console.log(replaceStr);

split([separator[, limit]])

  • 参数
    • separator: 指定表示每个拆分应发生的点的字符串。separator 可以是一个字符串正则表达式      
    • limit: 一个整数,限定返回的分割片段数量
  • 功能split()方法使用指定的分隔符字符串将一个String对象分割成子字符串数组,以一个指定的分割字串来决定每个拆分的位置(找到分隔符后,将其从字符串中删除,若是分隔符为正则表达式且为捕获括号,则其匹配结果将会包含在返回的数组中)
  • 返回值:返回源字符串以分隔符出现位置分隔而成的一个数组
let names = "Harry Trump ;Fred Barney ; Helen Rigby ; Bill Abel ;Chris Hand ";
console.log('不传参数', names.split()); // [Harry Trump ;Fred Barney; Helen Rigby ; Bill Abel ;Chris Hand 
console.log(`以分号分隔`, names.split(';')); // ["Harry Trump ", "Fred Barney", " Helen Rigby ", " Bill Abel ", "Chris Hand "]
// 使用一个数组来作为分隔符 数组会默认被String进行转换
const myString = 'ca,bc,a,bca,bca,bc';
// ['a','b'] 相当于'a,b'
console.log('使用数组进行分隔', myString.split(['a','b'])); // ["c", "c,", "c", "c", "c"]
// 使用正则表达式进行分隔 ?:非捕获分组 匹配空格;空格形式
let reg = /\s(?:;|$)\s/;
console.log('以正则表达式进行分隔(非捕获分组)', names.split(reg)); // ["Harry Trump ;Fred Barney", "Helen Rigby", "Bill Abel ;Chris Hand "]
// 使用正则表达式(捕获分组)匹配 会将捕获分组中的;也嵌入分隔的数据中
let reg1 = /\s(;|$)\s/;
console.log('以正则表达式进行分隔(捕获分组)', names.split(reg1)); // ["Harry Trump ;Fred Barney", ";", "Helen Rigby", ";", "Bill Abel ;Chris Hand "]

包含方法

includes(searchString[, position])

  • 参数
    • searchString: 要在此字符串中搜索的字符串。
    • position:从当前字符串的哪个索引位置开始搜寻子字符串,默认值为 0
  • 功能includes() 方法用于判断一个字符串是否包含在另一个字符串中,根据情况返回 true 或 false。严格区分大小写
  • 返回值:如果当前字符串包含被搜寻的字符串,就返回 true;否则返回 false
let str = 'To be, or not to be, that is the question.';
console.log(`字符串是否包含'To be':`, str.includes('To be')); // true
console.log(`字符串是否包含'To Be':`, str.includes('To Be')); // false
console.log(`从5号位置开始, 字符串是否包含'To be':`, str.includes('To be', 5)); // false

startsWith(searchString[, position])

  • 参数
    • searchString:要搜索的子字符串
    • position: 在 str 中搜索 searchString 的开始位置,默认值为 0
  • 功能startsWith()方法能确定一个字符串是否以另一个字符串开头。这个方法区分大小写
  • 返回值:如果在字符串的开头找到了给定的字符则返回true;否则返回false
let str = 'To be, or not to be, that is the question.';
console.log('判断字符串是否以To开头:', str.startsWith('To')); // true
console.log(`从5号位置开始, 字符串是否以'To'开头:`, str.startsWith('To', 5)); // false

endsWith(searchString[, length])

  • 参数
    • searchString:要搜索的子字符串
    • length:作为 str 的长度。默认值为 str.length(默认截取字符串)
  • 功能endsWith()方法用来判断当前字符串是否是以另外一个给定的子字符串“结尾”的,根据判断结果返回 true 或 false
  • 返回值:如果传入的子字符串在搜索字符串的末尾则返回true;否则将返回 false
let str = 'To be, or not to be, that is the question.';
console.log('判断字符串是否以.结尾:', str.endsWith('.')); // true
console.log('截取字符串前8位,判断字符串是否以.结尾:', str.endsWith('.', 8)); // false

操作方法

拼接方法

concat(str2 [, ...strN])

  • 参数str2 [, ...strN]: 需要连接到 str 的字符串
  • 功能concat()方法将一个或多个字符串与原字符串连接合并,形成一个新的字符串并返回
  • 返回值:一个新的字符串,包含参数所提供的连接字符串
let str = ' concat';
let hello = ' hello';
console.log('hh'.concat(str, hello)); // hh concat hello

不推荐使用,建议之间用 + += 进行替代

截取方法

slice(beginIndex[, endIndex])

  • 参数
    • beginIndex: 从该索引(以 0 为基数)处开始提取原字符串中的字符。如果值为负数,会被当做 strLength + beginIndex
    • endIndex:在该索引(以 0 为基数)处结束提取字符串,若不填写则默认为截取字符串末尾。
  • 功能slice()方法提取某个字符串的一部分,并返回一个新的字符串,且不会改动原字符串。
  • 返回值:返回一个从原字符串中提取出来的新字符串,包含beginIndex但不包含endIndex
var str = 'The morning is upon us.'
var sliceStr1 = str.slice(4);
console.log(`${str}|${sliceStr1}`); // The morning is upon us.|morning is upon us.
var sliceStr2 = str.slice(4, 11);
console.log(`${str}|${sliceStr2}`); // The morning is upon us.|morning
var sliceStr3 = str.slice(4, -3); 
console.log(`${str}|${sliceStr3}|`); // The morning is upon us.|morning is upon |

substr() 将废弃

避免使用,可能会被废弃,用`substring()`替代

substring(indexStart[, indexEnd])

  • 参数
    • indexStart:需要截取的第一个字符的索引(小于0或NaN被认为0,大于stringLength则被当做stringLength处理)
    • indexEnd: 一个 0 到字符串长度之间的整数,以该数字为索引的字符不包含在截取的字符串内。
  • 功能substring()方法返回一个字符串在开始索引到结束索引之间的一个子集, 或从开始索引直到字符串的末尾的一个子集
  • 返回值:包含给定字符串的指定部分的新字符串:indexStartindexEnd(不包括indexEnd)之间的字符

如果indexStart比indexEnd要大,substring会自动交换两者的位置,这也是substring和slice的主要区别

var str = 'The morning is upon us.'
var substring1 = str.substring(4);
console.log(`${str}|${substring1}`); // The morning is upon us.|morning is upon us.
var substring2 = str.substring(4, 11);
console.log(`${str}|${substring2}`); // The morning is upon us.|morning
var substring3 = str.substring(4, -3);
console.log(`${str}|${substring3}`); // String.js:133 The morning is upon us.|The

空格处理

trim()

  • 参数:无
  • 功能trim()方法会从一个字符串的两端删除空白字符。在这个上下文中的空白字符是所有的空白字符 (space, tab, no-break space 等) 以及所有行终止符字符(如 LF,CR等
  • 返回值:一个代表调用字符串两端去掉空白的新字符串
var orig = '   foo  ';
console.log(orig.trim()); // 'foo'

// 另一个 .trim() 例子,只从一边删除
var orig = 'foo    ';
console.log(orig.trim()); // 'foo'

trimLeft()

  • 参数
  • 功能trimStart()方法从字符串的开头删除空格。trimLeft()是此方法的别名
  • 返回值:一个新字符串,表示从其开头(左端)除去空格的调用字符串
var str = "   foo  ";

console.log(str.length); // 8

str = str.trimStart()    // 等同于 str = str.trimLeft();
console.log(str.length); // 5
console.log(str);        // "foo  "

trimRight()

  • 参数
  • 功能trimEnd()方法从一个字符串的末端移除空白字符。trimRight()是这个方法的别名
  • 返回值:一个新字符串,表示从调用字串的末(右)端除去空白
var str = "   foo  ";

alert(str.length); // 8

str = str.trimRight();  // 或写成str = str.trimEnd();
console.log(str.length); // 6
console.log(str);       // '   foo'

比较方法

localeCompare()

  • 参数
  • 功能
  • 返回值

转换方法

大写转换

toUpperCase()

  • 功能toUpperCase()方法将调用该方法的字符串转为大写形式并返回(如果调用该方法的值不是字符串类型会被强制转换
  • 返回值:一个新的字符串,表示转换为大写的调用字符串。
console.log('alphabet'.toUpperCase()); // 'ALPHABET'

toLocalUpperCase()

  • 功能toLocaleUpperCase() 方法根据本地主机语言环境把字符串转换为大写格式,并返回转换后的字符串
// 不怎么使用的 略略略
'alphabet'.toLocaleUpperCase(); // 'ALPHABET'

'Gesäß'.toLocaleUpperCase(); // 'GESÄSS'

'i\u0307'.toLocaleUpperCase('lt-LT'); // 'I'

let locales = ['lt', 'LT', 'lt-LT', 'lt-u-co-phonebk', 'lt-x-lietuva'];
'i\u0307'.toLocaleUpperCase(locales); // 'I'

小写转换

  • toLowerCase()
    • 功能toLowerCase()会将调用该方法的字符串值转为小写形式,并返回。
    • 返回值:一个新的字符串,表示转换为小写的调用字符串。
console.log('中文简体 zh-CN || zh-Hans'.toLowerCase());
// 中文简体 zh-cn || zh-hans

console.log( "ALPHABET".toLowerCase() );
// "alphabet"

toLocaleLowerCase()

  • 功能toLocaleLowerCase()方法根据任何指定区域语言环境设置的大小写映射,返回调用字符串被转换为小写的格式
// 不常使用 略略略
'ALPHABET'.toLocaleLowerCase(); // 'alphabet'

'\u0130'.toLocaleLowerCase('tr') === 'i';    // true
'\u0130'.toLocaleLowerCase('en-US') === 'i'; // false

let locales = ['tr', 'TR', 'tr-TR', 'tr-u-co-search', 'tr-x-turkish'];
'\u0130'.toLocaleLowerCase(locales) === 'i'; // true

字符串填充方法

padStart(targetLength [, padString])

  • 参数
    • targetLength: 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身
    • padString:填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断
  • 功能padStart()方法用另一个字符串填充当前字符串(如果需要的话,会重复多次),以便产生的字符串达到给定的长度。从当前字符串的左侧开始填充
  • 返回值:在原字符串开头填充指定的填充字符串直到目标长度所形成的新字符串
'abc'.padStart(10);         // "       abc"
'abc'.padStart(10, "foo");  // "foofoofabc"
'abc'.padStart(6,"123465"); // "123abc"
'abc'.padStart(8, "0");     // "00000abc"
'abc'.padStart(1);          // "abc"

padEnd(targetLength [, padString])

  • 参数
    • targetLength: 当前字符串需要填充到的目标长度。如果这个数值小于当前字符串的长度,则返回当前字符串本身
    • padString:填充字符串。如果字符串太长,使填充后的字符串长度超过了目标长度,则只保留最左侧的部分,其他部分会被截断
  • 功能padEnd()方法会用一个字符串填充当前字符串(如果需要的话则重复填充),返回填充后达到指定长度的字符串。从当前字符串的末尾(右侧)开始填充
  • 返回值:在原字符串末尾填充指定的填充字符串直到目标长度所形成的新字符串。
'abc'.padEnd(10);          // "abc       "
'abc'.padEnd(10, "foo");   // "abcfoofoof"
'abc'.padEnd(6, "123456"); // "abc123"
'abc'.padEnd(1);           // "abc"

repeat(count)

  • 参数count: 介于 0 和 +Infinity 之间的整数。表示在新构造的字符串中重复了多少遍原字符串。
  • 功能repeat() 构造并返回一个新字符串,该字符串包含被连接在一起的指定数量的字符串的副本
  • 返回值:包含指定字符串的指定数量副本的新字符串。
"abc".repeat(-1)     // RangeError: repeat count must be positive and less than inifinity
"abc".repeat(0)      // ""
"abc".repeat(1)      // "abc"
"abc".repeat(2)      // "abcabc"
"abc".repeat(3.5)    // "abcabcabc" 参数count将会被自动转换成整数.
"abc".repeat(1/0)    // RangeError: repeat count must be positive and less than inifinity