什麼是"暫時性死區"?
在代碼塊內,使用let命令聲明變量之前,該變量都是不可用的。
var tmp = 123;
let tmp; //報錯
typeof a; //報錯
let a = 1;
// 不報錯
var x = x;
// 報錯
let x = x;
// ReferenceError: x is not defined
如果區塊中存在let
和const
命令,這個區塊對這些命令聲明的變量,從一開始就形成了封閉作用域。凡是在聲明之前就使用這些變量,就會報錯。
暫時性死區的本質就是,只要一進入當前作用域,所要使用的變量就已經存在了,但是不可獲取,只有等到聲明變量的那一行代碼出現,纔可以獲取和使用該變量。
塊級作用域
1、外層作用域無法讀取內層作用域的變量。
{{{{
{let insane = 'Hello World'}
console.log(insane); // 報錯
}}}};
2、避免在塊級作用域內聲明函數。如果確實需要,也應該寫成函數表達式,而不是函數聲明語句。
// 函數聲明語句
{
let a = 'secret';
function f() {
return a;
}
}
// 函數表達式
{
let a = 'secret';
let f = function () {
return a;
};
}
3、ES6 的塊級作用域允許聲明函數的規則,只在使用大括號的情況下成立,如果沒有使用大括號,就會報錯。
// 不報錯
'use strict';
if (true) {
function f() {}
}
// 報錯
'use strict';
if (true)
function f() {}
const
1、只在聲明所在的塊級作用域內有效。
if (true) {
const MAX = 5;
}
MAX // Uncaught ReferenceError: MAX is not defined
2、一旦聲明,常量的值就不能改變。
3、只聲明不賦值,就會報錯。
4、同樣存在暫時性死區,只能在聲明的位置後面使用。
5、const只能保證指針是固定的(即總是指向另一個固定的地址),至於它指向的數據結構是不是可變的,不能完全控制。
const foo = {};
// 爲 foo 添加一個屬性,可以成功
foo.prop = 123;
foo.prop // 123
// 將 foo 指向另一個對象,就會報錯
foo = {}; // TypeError: "foo" is read-only
const a = [];
a.push('Hello'); // 可執行
a.length = 0; // 可執行
a = ['Dave']; // 報錯
數組解構
- 如果等號右邊不是可遍歷結構,那麼將會報錯。
- 只要某種數據結構存在Iterator接口,都可以進行解構,Set,生產函數等。
let [a] = 1;
let [a] = false;
let [a] = NaN;
let [a] = undefined;
let [a] = null;
let [a] = {}
對象解構
- 變量必須與屬相同名
- 如果不同名:(真正被賦值的是後者,而不是前者。)
let {foo:baz} = {foo:"aaa" , bar:"bbb"};
baz // "aaa"
如果要將一個已經聲明的變量用於解構賦值,請不要將花括號放在行首:
let x ;
({x} = {x:1});
可以方便的將現有對象的方法賦值到某個變量上:
//簡化console.log
const {log} = console;
log('簡化log')
//Math
let {sin} = Math;
字符串解構
字符串解構時被轉換成了一個類似數組的對象,可以讀取length屬性
字符串拓展
3個查詢是否包含字符串的新方法:
- includes():返回布爾值,表示是否找到了參數字符串。
- startsWith():返回布爾值,表示參數字符串是否在原字符串的頭部。
- endsWith():返回布爾值,表示參數字符串是否在原字符串的尾部。
- 它們都支持第二個參數,表示開始搜索的位置。
讓字符串重複n次:
- xxx.repeat(n),返回一個新的字符串,參數是 0 到-1 之間的小數,則等同於 0,0 到-1 之間的小數,取整以後等於
-0,
參數NaN
等同於 0。
ES2017引入了補全字符串長度功能,如果某個字符串不夠指定長度,會在頭部或者尾部補全
- padStrat() , 用於頭部補全,常見用途:爲數值補全位數,另一個用途是提示字符串格式。
-
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12" '09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
- padEnd() , 用於尾部補全
- 一共接受兩個參數,第一個參數補全生效的最大長度,第二個參數是用來補全的字符串
- 如果原字符串的長度,等於或者大於最大長度,補全不生效,返回源字符串。
- 如果用來不全的字符串與原字符串長度和超出最大長度,則截去超出位數後的補全字符串。
- 省略第二參數,空格自動補充。
返回正則表達式在當前字符串的所有匹配:
matchAll();
模板字符串 -- 編譯模板詳解
首先需要了解一些知識(正則):
-
( ) 標記一個子表達式的開始和結束位置,子表達式可以獲取供以後使用。要匹配這些字符,請使用 \( 和 \)。
-
. 匹配除換行符 \n 之外的任何單字符。要匹配 . ,請使用 \. 。
-
? 匹配前面的子表達式零次或一次,或指明一個非貪婪限定符。要匹配 ? 字符,請使用 \?。
-
+ 匹配前面的子表達式一次或多次。要匹配 + 字符,請使用 \+。
-
\ s 匹配任何空白字符,包括空格、製表符、換頁符等等。等價於 [ \f\n\r\t\v]。注意 Unicode 正則表達式會匹配全角空格符。
-
\S 匹配任何非空白字符。等價於 [^ \f\n\r\t\v]。
-
replace中的$1代表什麼? $1是正則裏的捕獲,就是前面的(.*?)裏的東西
-
eval()是什麼? eval() 函數可計算某個字符串,並執行其中的的 JavaScript 代碼
自己寫的簡化版例子:
全部代碼:
let template = `
<p>
<@ name @>
</p>
`;
function complate(template){
let reg = /<@(.+?)@>/g;
template = template.replace(reg,'`) \n javas($1) \n javas(`');
template = 'javas(`' + template + '`)';
let script = `
(function parse(name){
var output = '';
function javas(html){
output+=html;
}
${template};
return output;
})
`
return script;
}
let parse = eval(complate(template));
document.querySelector('div').innerHTML = parse('DEMO1')
解析:
//首先 有這樣一個自定義模板
let template = `
<p> <@name@></p>`;
如果想把它轉化爲可解析的模板,需要將其轉化爲JavaScript表達式字符串,如下:
javas(`<p>`)
javas( name )
javas(`</p>`)
步驟:
//首先 需要使用字符串的replace方法,通過正則更改<@@>
let reg = /<@(.+?)@>/g;
template = template.replace(reg,'`) \n javas($1) \n javas(`');
得到結果:
<p>`)
javas( name )
javas(`</p>
可以看到拼接並不完全,接下來:
template = 'javas(`' + template + '`)';
//拼接完即可拿到:
/*
javas(`<p>`)
javas( name )
javas(`</p>`)
*/
拼接完成以後,需要將template放在一個函數中返回:
let script = `
(function parse(name){
let output = '';
function javas(html){
output+=html;
}
${template};
return output;
})
`;
至此已完成大半,下面將其封裝成函數:
function complate(template){
let reg = /<@(.+?)@>/g;
template = template.replace(reg,'`) \n javas($1) \n javas(`')
template = 'javas(`' + template + '`)';
let script = `
(function parse(name){
var output = '';
function javas(html){
output+=html;
}
${template};
return output;
})
`
return script;
}
最後調用:
let parse = eval(complate(template)); //調用return的script模板字符串
document.querySelector('div').innerHTML = parse('DEMO1'); //傳入name值渲染到div
輸出一下script看起來更直觀:
(function parse(name){
var output = '';
function javas(html){
output+=html;
}
javas(`<p>`)
javas( name )
javas(`</p>`);
return output;
})
可以看到這裏進行的操作:
- 定義parse方法用來傳入name和調用,定義javas方法,傳入參數即爲模板字符串和變量,拼接到空字符串上返回,這樣就可以得到正常的html結構,最後通過eval()執行函數
output的輸出:
<p>
DEMO1
</p>