字符串和字符串对象
1.写法
1.普通表示
字符串可以使用单引号或者双引号。多数JS项目约定使用单引号(')。
可以用单引号包含双引号,也可以用双引号包含单引号。
'ab"c"dd'或者"abc'd'e"
如果想单引号包含单引号,或者双引号包含双引号,需要使用转义符号:
'abc\'de' // abc'de "abc\"de" // abc"de
2. 长字符串
如果想写长字符串,不能直接换行,会报错,有2种常见写法。
var str = "Hello world, I'm Lyra"; // 如果想分行写 // 1)在最后加\ var str = "Hello world,\ I'm Lyra"; // 2) 使用+拼接字符
3. 模版字符串
如果想保留书写格式,使用模版字符串。
var str = `a b`
1.模板编译
用js实现html模板。
将模版字符串转为正式的模板,以下是ejs模板示例:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>ejs模版解析</title> </head> <body> <div id="root"></div> <script> var data = { supplies: ['boom', 'cleaner', 'mop'] } var template = ` <ul> <% for(let i=0; i<data.supplies.length;i++) {%> <li><%=data.supplies[i]%></li> <%}%> </ul> `; /* 中间形式代码: echo(<ul>); for(let i=0; i<data.supplies.length;i++) { echo(<li>) echo(data.supplies[i]) echo(</li>) } echo(</ul>); */ // 写一个编译函数 function compile(template) { // 使用正则表达式解析模板符号,将其转为上面中间形式代码 regExp = /<%([\s\S]+?)%>/g; regExpEqul = /<%=(.+?)%>/g; // 先执行这个替换,否则会错乱 var template = template .replace(regExpEqul, '`); \n echo( $1 ); \n echo(`') .replace(regExp, '`); $1 \n echo(`') var template = 'echo(`' + template + '`)'; // 定义html输出函数 var output = ""; function echo(html) { output += html; } // 返回一个可以传入数据的函数 return function parse(data) { eval(template); return output; } } const innerHtml = compile(template)(data) window.root.innerHTML = innerHtml; </script> </body> </html>
2. 模板标签
非小括号的函数调用方式;使用模版字符串调用。
let message = SaferHTML`<p>${sender} has sent you a message.</p>`; // SaferHTML 是个标签函数
实际传参形式如下
let message = SafeHTML( ["<p>", " has sent you a message.</p>", raw: Array(2)], ${sender})
可以用来过滤Html字符串,防恶意输入
let message = SaferHTML`<p>${sender} has sent you a message.</p>`; function SaferHTML(templateData) { let s = templateData[0]; for (let i = 1; i < arguments.length; i++) { let arg = String(arguments[i]); // Escape special characters in the substitution. s += arg.replace(/&/g, "&") .replace(/</g, "<") .replace(/>/g, ">"); // Don't escape special characters in the template. s += templateData[i]; } return s; }
2.字符的Unicode码表示
1)\HHH 三位8进制数 // 只能表示256个字符
2)\xHH 两位16进制数 // 只能表示256个字符
3)\uHHHH 四位16进制数
4) \u{字符} // 大括号内的数字是16进制的数字,即使没有0x符号。 ES6表示法,可以展示大于0xFFFF的值
// 示例:版权符号 '\251' // ©️ '\xA9' // ©️ '\u00A9' // ©️
s引擎内部每个字符都是utf-16格式,16位存储(2个字节)。
但是在ES5中,对于超过\u0000-\uFFFF范围的字符来说,js会将其分成两个字符(4个字节)。str.length的长度为2。
在ES6中,可以使用大括号来表示码点大于0xFFFF的字符,如:
'\u1D306' // 在ES5中因为超过\uFFFF,会被解析成"\u1D30" + 6, 即"ᴰ6" // ES5如果想要正确显示大于0xFFFF的字符,需要将其写成第一个字符\uD800-\uDBFF之间,第二个字符位于\uDC00-\uDFFF之间的拼接字符。 '\uD834\uDF06' // "𝌆"--正确 // ES6中就可以直接用大括号表示 '\u{1D306}' //"𝌆"
码点大于0xFFFF的字符,可以被for...of...遍历器正确遍历
3.转义字符
需要使用反斜杠转义的主要有:
\r 回车 \n 换行 \\ 反斜杆 \' 单引号 \" 双引号
4. Base64编码
Base64,顾名思义,就是基于64个字符。就是将任意值转为0-9,A-Z,a-z,+,/这64个字符组成的可打印字符。
用途:1)显示特殊字符,比如ASCII码的前31位。2)将二进制数据(比如图片)转为文本
有两个方法:
btoa(str); // 转为Base64 atob(str); // 从Base64转为原来的值
上面的方法仅适用于ASCII码,对于诸如汉字等非ASCII码,需要先通过encodeURIComponent处理
var str ="你好"; btoa(encodeURIComponent(str)); //"JUU0JUJEJUEwJUU1JUE1JUJE" decodeURIComponent(atob("JUU0JUJEJUEwJUU1JUE1JUJE")) // "你好"
5.字符串对象方法
1.静态方法--返回码点对应字符
1) String.fromCharCode(码点,码点,,,)
返回码点对应的字符,使用于0x0000-0xFFFF之间的字符,超出的可以拆分成两个字符
2) String.fromCodePoint(码点,,,)
作用同上,但是作为ES6新增方法,可以解析大于0xFFFF的字符。
String.fromCodePoint(0x20bb7); // "𠮷"
3)String.raw`str`---标签函数
将模版字符串的所有变量替换,并且将斜杠转义
String.raw`Hi\n${2+3}!` === "Hi\\n5!"; // true // 但是在页面上展示是"Hi\n5!" // 相当于 String.raw({raw: ['Hi\\n','!'],},5);
2. 实例方法--基本方法
1)String.prototype.charAt([index]) ---根据位置返回字符(0x0000-0xFFFF)
index可以省略,默认是0,即第一个位置。
和字符串按照数组索引取值类似,不同点在于[]取值超过范围返回undefined,
该方法超过有效index,返回“”空字符串。
2) String.prototype.charCodeAt([index]) --- 根据位置返回码点(十进制)(0x0000-0xFFFF)
index默认是0,结果想转16进制,可以调用toString(16)
3) String.prototype.codePointAt([index]) --- 根据位置返回码点(十进制)
功能和2)相同,但是可以识别大于0xFFFF的字符。
'ad'.codePointAt(1); // 100
4)String.prototype.normalize()---Unicode码统一化
返回结果相同的不同表示形式统一化
有四种参数: NFC,NFD,NFKC,NFKD
'\u01D1'.normalize() === '\u004F\u030C'.normalize()
3.实例方法---字符串变更
1) String.prototype.concat(多个参数) ---拼接字符串
会将不是字符串的参数转为字符串
2)String.prototype.slice(start, end) ---截取字符串
遵循[)左闭右开原则,如果参数<0,表示从后面数。
如果start>end,返回“”
3)String.prototype.substring(start, end) --- 截取字符串
遵循[)左闭右开原则,如果参数<0, 将负数转为0.
如果start>end,交换两者的值。
4)String.prototype.substr(start,length) --- 截取字符串
如果start<0, 从后面数;
如果length<0, 将length置为0
5)String.prototype.toLowerCase(),String.prototype.toUpperCase()--转大小写
6)String.prototype.split(string/RegExp[, limit]) --- 分割字符串
第一个参数可以是字符串或者正则表达式,第二个限制返回的长度。
如果正则表达式带有括号,则括号匹配的内容也会返回
'aaa*a*'.split(/a*/); // ['', '*', '*'] 'aaa*a*'.split(/(a*)/); // ['', 'aaa' , '*', 'a', '*']
7)String.prototype.replace(string/RegExp, string/function)---替换字符串
不改变原字符串。
一般只替换第一个匹配的字符
'abaaaaaac'.replace('a', 'A'); //"Abaaaaaac"
当正则表达式使用g修饰符时,会替换所有匹配的字符
'abaaaaaac'.replace(/a/g, 'A') //"AbAAAAAAc"
第二个参数如果是字符串,可以有几个特殊值。
1) '$&' // 被替换的字符 'abc'.replace(/b/, '$&'); // abc 2)'$`' // 被替换内容前面的所有字符 'dddabc'.replace(/b/, '$`'); //"dddadddac" 3) '$\'' // 被替换内容后面的所有字符 'abcd'.replace(/b/, '$\''); //acdcd 4) '$n' // 组匹配的第n个内容 'abc'.replace(/(.)(.)/g, '$&-$1-$2-$`-$\'-$$'); // "ab-a-b--c-$c" //由上可知,$&==ab,$1 == a,$2==b,$` == '', $\' === c 5)$$ // 表示$符号
6)$<组名> // 表示具名组匹配的引用;和$n性质一样
第二个参数如果是函数,函数参数为:($&, $1,.,,...$n, $&索引, 原字符串,groups)
8)String.prototype.repeat(n)---将字符串重复n次
如果n是Infinity或者<=-1, 返回RangeError;
如果-1<n<1, n默认取0;
如果是其他值,向下取整
9) String.prototype.trim()----去除首尾空白字符 ES5
String.prototype.trimStart()--- 去除首部空白字符ES2019
String.prototype.trimEnd() --- 去除尾部空白字符ES2019
10)padStart(length, str),padEnd(length, str) --- 补全字符串
length表示补全后的字符串长度,原字符串长度大于length,返回原值;
str用于补全的字符,默认是空格。
'05'.padStart(10,'YYYY-MM-DD'); // "YYYY-MM-05"
4. 实例方法---字符串查找
1)indexOf(str[, start])---从start向后查找第一个目标字符串的位置
lastIndexOf(str[, start])---从start向前开始查找第一个目标字符串的位置
start表示开始查找的位置
'abcdaddfdsa'.indexOf('a'); // 0 'abcdaddfdsa'.indexOf('a',4); // 4 'abcdaddfdsa'.indexOf('a',-1); // 0 当start<0时,按照0处理
'abcdaddfdsa'.lastIndexOf('a',3); // 0
2) search(str/RegExp) --- 从头查找目标字符串第一个出现的位置
作用和indexOf相同,不同点在于search可以使用正则表达式
'abca'.search('a'); // 0 'abca'.search(/a/); // 0
3)match(str/RegExp) --- 用数组返回查找的结果
如果查找失败,返回null;
当为正则表达式时,如果有g修饰符,返回所有的匹配结果,忽略组匹配。
当为正则表达式时,如果没有g修饰符,或者为字符串时,会返回组匹配,并且返回input和index属性。
'abca'.match(/(.)/g); // ["a", "b", "c", "a"] 'abca'.match(/(.)/); // ["a", "a", index: 0, input: "abca", groups: undefined]
//其中第一个是匹配结果,第二个是组匹配,index是匹配的位置,input是原字符串
4)matchAll(RegExp) --- 用遍历器返回所有匹配结果。返回的是遍历器。
和3)相比, 可以遍历整个字符串,还可以获得组匹配。
matchAll返回的是一个遍历器;好处是比数组节约资源;
可以通过...扩展运算符和Array.from()可以将其转为数组。
const a = 'abca'.matchAll(/(.)/g); // RegExpStringIterator {} [...a]; /* [ ["a", "a", index: 0, input: "abca", groups: undefined], ["b", "b", index: 0, input: "abca", groups: undefined], ["c", "c", index: 0, input: "abca", groups: undefined], ["a", "a", index: 0, input: "abca", groups: undefined] ] */
5)includes(str)---通过布尔值返回查找结果
6)startsWith(str, start) --- 通过布尔值是否以str开头
start参数表示查找的起始位置
'abc'.startsWith('a'); // true 'abc'.startsWith('a', 1); // false
7)endsWith(str, beforeIndex)---通过布尔值是否以str结尾
beforeIndex表示前beforeIndex个字符。
'abc'.endsWith('a',1); // true 前一个字符以a结尾 'abc'.endsWith('a'); // false
5. 实例方法-字符串比较
str1.localeCompare(str2) --- 比较字符串大小
按照自然语言比较,不同于比较运算符
结果是1, 表示str1 > str2
结果是0,表示str1 === str2
结果是-1,表示str1 < str2
'B'.localeCompare('a'); // 1 前者大 'B'>'a'// false 前者小
该方法还可以用来比较汉字,按照汉语拼音的顺序
'按'.localeCompare('们') // -1 '我'.localeCompare('们') // 1