[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)
```