[TOC]
> js字符串小记,相关备忘,保持更新中...
## 普通字符串拼接的问题
1. 普通字符串拼接时候一串字符里不能换行(对应的模板字符串中是能的)
```
let str = '我是一串
普通的字符串'; //此处进行了换行,会报错
console.log(str);
```
解决方案:在准备换行之前使用`\`转义
```
let str = '我是一串\
\
普通的字符串'; //此处进行了换行,会报错
console.log(str);
```
2. `'`、`""`需要手动转义
模板字符串中若要输出单双引号不再需要加上`\`
```
let str = `'单引号"双引号`;
console.log(str);
```
但模板字符串的 **`** 还是需要转义的哦!
## 模板字符串的简单实现
```
let name = 'ahhh';
let str = '你好,${name}';
function tmpstr(str){
str.replace(/\$\{(.*?)\}/,function(){
return eval(arguments[1]);
})
}
<<< 输出
你好,ahhh
```
## 字符串模板中的标签函数
```
let name = 'ahhh';
let where = '艾泽拉斯';
let str = tag`${name}你要去${where}买菜吗?`
function tag(strings,...tags){
console.log(arguments);
console.log(strings);
console.log(tags);
}
console.log(str);
//直接输出str 其实就是调用tag函数 `xx`部分就相当于函数传参
<<< 输出
{
‘0’:['','你要去','买菜吗'] //注意这里这个数组是以${}为分隔符的
,‘1’:‘ahhh’
,‘2’:‘艾泽拉斯’
}
[ '', '你要去', '买菜吗?' ]
[ 'ahhh', '艾泽拉斯' ]
```
字符串模板中的每一对`${}`称之为一对标签。除却标签的部分即为普通字符串。
tag函数的arguments参数中的第一个参数是字符串模板中的**所有普通字符**,但需要注意的一点是`${}`处于整个模板字符串开头或结尾时会在第一个参数的数组的开头或结尾多一个`''`字符串,
另外若两队标签紧靠在一起,像这样`${a}${b}`,那标签a和标签b之间也会多一个`''`。
总之,有**x**对`${}`就会在整个字符串中切**2x**刀,分成**2x+1**份(strings+tags)。
> 推荐阅读 [ES6 标签模板](https://www.cnblogs.com/sminocence/p/6832331.html)
## ejs模板引擎核心原理
### 什么是模板引擎
模板引擎就是把`数据对象`渲染到`指定模板`的`指定位置上`。每种模板引擎都有自己专门标记**指定位置**的符号,像ejs,就是以`<%...%>`和`<%=...%>`来作为标识符号的。
### 设计思路
关键词:`with`、`Function`、`字符串拼接`
先说`with`,with是一种作用域,它的作用域范围是它所接受的对象
在一个with作用域里,我们能直接拿到它所接受对象的属性(你可以理解成with把这个对象解构了)
```
let obj = {
name:'ahhh'
,age:'111'
,hobby:'sleep'
}
with(obj){
console.log(`${name}今年${age}岁,TA唯一的兴趣就是${hobby}`)
}
<<<
ahhh今年111岁,TA唯一的兴趣就是sleep
```
想想我们平时是怎么使用模板引擎的?是不是经常`for data.length`,`if(data.xx===)`、`if(!data.xx)`这样的。
这里的data就像我们上面栗子中的obj
```
let data = {
user:{name:ahhh}
}
(function(){
let tpl = '';
with(data){
if(user){
tpl += `hi~${user.name}`;
}else{
tpl += `to login~`;
}
}
retrun tpl;
})...
```
和我们使用ejs时的样子进行对比
```
<%if(user){%>
hi~<%=user.name%>;
<%}else{%>
to login~
<%}%>
```
### 实现
1. 把ejs的这种形式转换成with与字符串拼接的形式
```
function render(filepath,data,callbcak){
fs.readFile(filepath,'uf8',function(err,str){
if(err)return callbcak(err,null);
let head = "let tpl =``;\r\nwith(data){\r\ntpl=`";
str = str.replace(/<%=[\w\W]+?%>/g,function(){
return '${'+arguments[1]+'}';
});
str = str.replace(/<%[\w\W]+?%>/g,function(){
return "`;\r\n"+arguments[1]+"\r\ntpl +=`";
});
let tail = "`}\r\nreturn tpl;";
let html = head+str+tail;
...
});
}
```
**注意为了让tpl形成闭合,我们在head部分的末尾追加了一个 tpl=\`,在tail开头时也追加了一个 \`**
2. 将拼接后的字符串传递给`Function`生成一个真正函数
```
...
let fn = Function('data',html);
let ret = fn(data);
callbcak(null,ret);
...
```
上面的整个实现是兼容express模板引擎规范的
这个`render`函数的第三个参数`callbcak`是express中`res.render`所传递进render中的`done`回调(如果编译成功就将编译成功后的html作为响应返回,如果失败则返回错误信息)
## 字符串常用方法
### startsWith
```
let url = 'https://www.baidu.com';
let boolean = url.startsWith('https');
console.log(boolean);
<<<
true
```
>[danger] **注意:** 这个方法名必须要吐槽一下加深一下印象?md?带个s??看见没有,它居然带s!!卧槽,你说你凭啥要带个s???,还有下面的endsWith,卧槽,你说你带s就算了,你能不统一下,你padStart又不带s了???
### endsWith
```
let ext = '123.jpg';
let boolean = ext.endsWith('.jpg');
console.log(boolean);
<<<
true
```
### includes
```
let str = 'hello,world!';
let boolean = str.includes('world');
console.log(boolean);
<<<
true
```
### padStart
.padStart(minlength,fill)
第一个参数为字符串最小长度,第二个参数为填充字符,若字符串小于最小长度会用填充字符在开头出开始填充(padEnd这是在结尾处开始填充)。
```
let d = new Date();
let h = d.getHours().toString();
let m = d.getMinus().toString();
let s = d.getSeconds().toString();
let t = `${h.padStart(2,0)}:${m.padStart(2,0)}:${s.padStart(2,0)}`;
setInterval(function(){
console.log(t);
},1000)
```