JavaScriptES6上新增了很多字符串的方法。
目录
在以前版本中也有查找的方法,比如说indexOf(),就可以查找是否含有,但是这个方法返回的索引位,当找不到的时候返回的是-1,显然是很麻烦的。
ES6产生了3个查找字符串的方法:includes()、startsWith()、endsWith();
includes()
这个方法参数是查找的字符串,如果找到返回true,找不到返回false。
let str = "apple banana";'
console.log(str.includes("apple")) //true
includes()方法可以支持第二个参数,表示开始搜索的位置。
let str = "apple banana";
console.log(str.includes("banana",6)) //true
startsWith()
这个方法表示查找原字符串是否以给定的字符串开头,开始的位置,返回Boolean,成功返回true,否则返回false
let str = "Hello";
console.log(str.startsWith("H")); //true
console.log(str.startsWith("e")); //false
这个方法也是可以支持第二个参数,表示开始搜索的位置
let str = "Hello";
console.log(str.startsWith("e",1)); //true
endsWith()
这个方法表示查找原字符串是否以给定的字符串结尾,返回Boolean类型,成功返回true,否则返回false
let str = "Hello world";
console.log(str.endsWith("world")); //true
endsWith()支持第二个参数,表示搜索前n个字符。是指从第n + 1个位置搜索前n个字符。
let str = "Hello world";
console.log(str.endsWith("w",7)) //true
repeat()
返回一个新的字符串,表示将原字符串重复n次
console.log("x".repeat(3)) //xxx
console.log("hello".repeat(2)) //hello
console.log("hello".repeat(0)) //"" 将原字符串重复0次返回空字符串
//如果参数是小数,会被取整(向下取整)
console.log("x".repeat(2.3)) //xx
//如果参数是负数或者Infinity,会报错
console.log("x".repeat(-1)) //error
console.log("x".repeat(Infinity)) //error
//但是,如果参数是在0 到 -1之间的小数的话,则等同于0,这是因为参数会先进行取整运算,0 到 -1之间的小数,取整以后等于 -0 repeat视为0;
console.log("x".repeat(-0.5)) //""
//如果参数为NaN的时候等同于0
console.log("x".repeat(NaN)) //""
//如果参数为字符串的话则先转换为数字,转换不成按照0计算
console.log("x".repeat("3")) //xxx
console.log("x".repeat("str")) //""
padStart()、padEnd()
ES2017引入了字符串补全的功能,如果某个字符串不够指定长度,会在头部或尾部补全,padStart()表示头部补全,padEnd()表示尾部补全。
两个方法都是支持两个参数,第一个参数是指定字符串的长度,第二个参数是不够长度补的字符串。
console.log("x".padStart(4,"a")) //aaax
console.log("x".padEnd(4,"a")) //xaaa
如果原字符串的长度大于指定的最小长度,则返回原字符串。
console.log("xxxx".padStart(3,"a")) //xxxx
console.log("xxxx".padEnd(3,"a")) //xxxx
如果用来补全的字符串与原字符串,二者的长度超过了指定的最小长度,则会截去超过位数的自妇产,然后补全字符串。
console.log("xxx".padStart(10,"0123456789")) //0123456xxx
console.log("xxx".padEnd(10,"0123456789")) //xxx0123456
如果省略第二个参数,则默认使用空格补全长度。
console.log("xxx".padStart(10)) // xxx
console.log("xxx'.padEnd(10)); //xxx
padStart的常见用途是为数值补全指定位数和用于提示或刷新字符串格式
console.log("1".padStart(10,"0")) //0000000001
console.log("123".padStart(10,"0")) //0000000123
// 提示/刷新
console.log("12".padStart(10,"YYYY-MM-DD")); //YYYY-MM-12
console.log("09-12".padStart(10,"YYYY-MM-DD")) //YYYY-09-12
模板字符串
传统的我们在写字符串的时候,需要引入变量的时候用字符串相加的方式引入,换行还需要用+号来连接,非常的繁琐,不方便,ES6引入了模板字符串解决了这个问题。
模块字符串(template string)是增强版的字符串。用反引号(`)标识。它可以当作普通字符串使用。也可以用来定义多行字符串,或者在字符串中嵌入变量。
//普通字符串
console.log(`In javascript \n is a line-feed`);
//多行字符串
console.log(`我正在学习
javascriptES6
`)
//字符串中嵌入变量
let test = '123', time = 'today';
console.log(`今天是${time},我是${test}`);
如果在模板字符串中需要使用反引号。则前面要用反斜杠转义
let str = `
this
is \`js\`
`.trim();
console.log(str);
如果使用模块字符串表示多行字符串,所有的空格和缩进都会被保留在输出之中。
div.innerHTML = `
<ul>
<li>1</li>
<li>2</li>
</ul>
`
trim--使用模块字符串,空格和换行都会被保留,上面代码<ul>标签前面会有一个换行。如果你不想要换行,可以使用trim清除多行字符串中第一行字符串的换行。
div.innerHTML = `
<ul>
<li>1</li>
<li>2</li>
</ul>
`.trim();
模板字符串中嵌入变量,需要将变量名写在${}之中
let str = "abc";
let str1 = `this is ${str}`
在大括号内部可以放入任意的JavaScript表达式,可以进行运算,以及引用对象属性。
let x = 1;
let y = 2;
console.log(`${x} + ${y} = ${x + y}`); //1 + 2 = 3
console.log(`${x} + ${y * 2} = ${x + y * 2}`) //1 + 4 = 5
let obj = {
a : 1,
b : 2,
}
console.log(`${obj.a + obj.b}`) //3
模板字符串之中还可以调用函数,调用之后字符串为函数的返回值
function fu(){
console.log(123);
return 123;
}
console.log(`${fn()}`) //123 123
//第一个123为函数中输出的,第二个为模板字符串中的
特别注意的是:如果大括号中的值不是字符串,将按照一般的规则转换成字符串。比如,大括号中是一个对象,将默认调用对象的toString方法。
如果模板字符串中的变量没有声明,将会报错
console.log(`${name}`) //error
由于模板字符串的大括号内部就是执行的JavaScript代码,因此大括号内部是一个字符串,将会原样输出。
console.log(`Hello${`World`}`) //HelloWorld
由于模板字符串内部就是执行的JavaScript代码,所以模板字符串开可以嵌套着使用,
const tmpl = addrs => `
<table>
${addrs.map(addr =>`
<tr>
<td>${addr.name}</td>
<td>${addr.age}</td>
</tr>
`).join("")}
</table>
`;
let data = [
{name : "张三",age : 18,}
{name : "李四",age : 20,}
],
console.log(tmpl(data));
如果需要引入模板字符串本身,在需要的时候执行,也是可以的
let str = 'return' + '`Hello ${name}`';
let fun = Function("name",str);
console.log(fun("wang")) /Hello wang
//先以字符串的形式定义好,在函数需要是使用
标签模板
模板字符串可以紧跟在一个函数名的后面,该函数将被调用来处理这个模板字符串,这被称为“标签模板”功能
alert`123` //123
标签模板其实不是模板,而是函数调用的一种特殊形式,‘标签’指的就是函数,紧跟在后面的模板字符串就是它的参数。但是,如果模板字符串中有变量,就不是简单的调用了,而是会将模板字符串先处理成多个参数,再调用函数。
let a = 5;
let b = 10;
tag`Hello ${a + b} world ${a * b}`; == tag(['Hello ', 'world',''],15,50)
上面代码中,模板字符串前面有一个表示名tag,它是一个函数,整个表达式的返回值,就是tag函数处理模板字符串后的返回值。
函数tag依次会接受多个参数
function tag(stringArr,value1,value2){
// .....
}
//等同于
function tag(stringArr,...values){
// ...
}
tag函数的第一个参数是一个数组,该数组的成员是模板字符串中那些没有变量替换的部分,也就是说,变量替换只发生在第一个成员和第二个成员之间;第二个成员和第三个成员之间,以此类推。
tag函数的其他参数,都是模板字符串各变量被替换后的值,由上为例,tag函数会接受到三个参数
tag函数的参数: 第一个参数['Hello ' , 'world ',''];
第二个参数15
第三个参数50
也就是说tag函数的实际调用时tag(['Hello ','world ',''],15,50);
let a = 5;
let b = 10;
let tag = (s,v1,v2) =>{
console.log(s[0]); //Hello
console.log(s[1]); //world
console.log(s[2]); //""
console.log(v1); //15
console.log(v2); //50
}
tag`Hello${a + b}world${a * b}`;
下面是一个更复杂的例子,将各个参数按照原来的位置拼合回去
let totle = 30;
function passthru(literals){
let result = "";
let i = 0;
while(i < literals.length){
result += literals[i ++];
if(i < arguments.length){
restlt += arguments[i];
}
}
return result;
}
console.log(passthru`The totle is ${title}(${totle * 10.5} is max)`)
passthru函数采用rest参数的写法如下
let passthru = (literals, ...values) => {
let output = "";
let index;
for(index = 0; index < values.length ; index ++){
output += literals[index] + values[index];
}
output += literals[index];
return output;
};
let msg = passthru`The totle is ${totle}(${totle * 10.5} with t)`;
console.log(msg);
标签模板'的一个重要的作用,就是过滤HTML字符串,防止用户输入恶意内容\
function SaferHTML(templateDate){
let s = templateDate[0];
for(let i = 1 ; i < arguments.length ; i++){
let arg = String(arguments[i]);
s += arg.replace(/&/g,"&")
.replace(/</g,"<")
.replace(/>/g,">");
s += templateDate[i];
}
return s;
}
let sender = `<script>alert("abc")<script>`;
let message = SaferHTML`<p>${sender} has sent you a message.</p>`;
模板处理函数的第一个参数(模板字符串数组),还有一个raw属性
console.log`123`; //["123",raw: Array(1)];
上面代码中console.log接受到的参数,实际上是一个数组,该数组有个raw属性,保存的是转义后的原字符串
let tag = (strings) => {
console.log(strings.raw[0]); //First line\nSecond line
}
tag`First line\nSecond line`;
上面代码中,tag函数的第一个参数strings,有一个raw属性,也指向一个数组,该数组的成员与strings数组完全一致,二者唯一 的区别就是字符串里面的斜杠被转义了,
比如strings.raw数组会将\n 视为 \\ n两个字符,而不是换行符,这是为了方便取得转义之前的原始模板而设计的
String.raw
ES6还为原生的String对象,提供了一个raw方法。
string.raw方法,往往用来充当模板字符串的处理函数,返回一个斜杠都被转义(即,斜杠前再加一个斜杠)的字符串,对应于替换变量后的模板字符串。
console.log(String.raw`Hi\n${2 + 3}`); //Hi\n5
console.log(String.raw`Hi\u000A`); //Hi\u000A
console.log(`Hi\n${2 + 3}`); // Hi 5
如果原字符串的斜杠已经转义,那么String.raw会再次进行转义
console.log(String.raw`\\n`);
String.raw方法可以作为处理模板字符串的基本方法,它将所有的变量替换,而且对斜杠进行转义,方法下一步作为字符串来使用。String.raw方法也可以作为正常的函数来使用,这时,它的第一个参数应该是一个具有raw属性的对象,,且raw属性的值应该是一个数组。
let arr = [];
let obj = { raw: 'test' };
let len = obj.raw.length;
for(let i = 0; i < len - 1; i++){
arr[i] = " ";
}
arr.unshift(obj);
console.log(String.raw.apply(null,arr));
console.log(String.raw({ raw : 'test'},0,1,2)); 等同于 console.log(String.raw({raw : ['t','e','s','t']},0,1,2));
String.raw作为函数 原理代码
String.raw = function(strings,...values){
let output = '';
let index;
for(index = 0; index < values.length; index ++){
output += strings.raw[index] + values[index];
}
output += strings.raw[index];
return output;
}
console.log(String.raw({ raw: 'test' }, 0, 1, 2)); //t0e1s2t