ES5、ES6、ES7電子教程
阿新 • • 發佈:2018-11-12
http://yanhaijing.com/es5/#about
ES5電子教程
中文版:http://yanhaijing.com/es5/#58
英文版:https://people-mozilla.org/~jorendorff/es5.1-final.html
ES6電子教程
中文版:http://es6.ruanyifeng.com/
英文版:http://www.ecma-international.org/ecma-262/6.0/#sec-type
ES6的瀏覽器相容性問題: https://segmentfault.com/a/1190000005128101
ES7電子教程
英文版:http://www.ecma-international.org/ecma-262/7.0/index.html
名詞解析
(1)連結: http://www.jb51.net/article/30719.htm
- 變數提升
1、查詢變數的順序是:活動物件-->全域性物件,一旦找到變數就停止查詢
2、javascrip函式級作用域的影響,即函式會建立新的作用域
3、變數提升,是把變數提升提到函式的頂部,只提升變數的宣告,賦值沒提升。
//場景一
var x = 1; //x儲存在全域性物件中 console.log(x); // 1 if (true) { var x = 2; //x儲存在活動物件中 console.log(x); //2 } console.log(x);// 2
//場景一
var v='Hello World';
(function(){
alert(v);
var v='I love you';
alert(v);
})();
//定義的三個變數
(function(){ var a='One'; var b='Two'; var c='Three'; })(); //實際上是這樣子的: (function(){ var a,b,c; a='One'; b='Two'; c='Three'; })();
所以在定義js變數時候,需要把變數放在塊級作用域的頂端,先定義變數,以防出現錯誤。
- 函式提升
1、函式提升:就是把函式宣告提到作用域的頂部
2、函式有兩種表達方式:函式宣告方式和函式表達方式
3、只有函式宣告方式才能提升
//函式宣告方式
function myTest(){
foo();
function foo(){
alert("我來自 foo");
}
}
myTest();
//函式表達方式
function myTest(){
foo();
var foo =function foo(){
alert("我來自 foo");
}
}
myTest();
- ** 暫時性死區**
只要一進入當前作用域,所要使用的變數就已經存在,但是不可獲取,只有等到宣告變數的那一行程式碼出現,才可以獲取和使用該變數。- ** let與var區別**
//不同之處
1、let宣告的變數只在let所在的程式碼塊內有效
2、var有變數提升,則宣告之前使用不會報錯;let沒有變數提升,宣告前使用會報錯
3、let存在暫時性死區,只要塊級作用域記憶體在let命令,它所宣告的變數就“繫結”(binding)這個區域,不再受外部的影響
var tmp = 123;
if (true) {
tmp = 'abc'; // ReferenceError
let tmp;
}
4、ES6規定,若區塊中存在let和const命令,這個區塊對這些命令宣告的變數,從一開始就形成了封閉作用域。凡在宣告前就使用這些變數,均報錯。
5、ES6規定暫時性死區和let、const語句不出現變數提升,主要是為了減少執行時錯誤。
6、let不允許在相同作用域內,重複宣告同一個變數
- ** 塊級作用域**
ES5只有全域性作用域和函式作用域,沒有塊級作用域,這帶來很多不合理的場景
1、避免由於變數提升,內層變數可能會覆蓋外層變數;
2、避免用來計數的迴圈變數洩露為全域性變數;
3、ES6允許塊級作用域的任意巢狀, 外層作用域無法讀取內層作用域的變數, 內層作用域可以定義外層作用域的同名變數;
{{{{{let insane = 'Hello World'}}}}};
{{{{ {let insane = 'Hello World'} console.log(insane); // 報錯}}}};
{{{{ let insane = 'Hello World'; {let insane = 'Hello World'}}}}};
4、塊級作用域可以替代立即執行的匿名函式的功能
5、ES5(嚴格模式)規定,函式只能在頂層作用域和函式作用域之中宣告,不能在塊級作用域宣告
6、ES6允許在塊級作用域之中宣告函式,只在大括號情況下可行,沒有大括號會報錯;函式宣告類似於var,存在函式提升
注意:環境導致的行為差異太大,應該避免在塊級作用域內宣告函式。 若需要,也應該寫成函式表示式,而不是函式宣告語句
- ** 頂層物件及其屬性**
根據不同環境,頂層物件指:
1、瀏覽器:window、self物件。有實體含義,即指代瀏覽器的視窗物件
2、node: global物件
ES5中,頂層物件的屬性與全域性變數等價,這是javascript語言設計的最大敗筆之一,原因:
1、沒法在編譯時就報出變數未宣告的錯誤,只有執行時才能知道。因為全域性變數可能是頂層物件的屬性創造的,而屬性的創造是動態的。
2、頂層物件到處可讀,不利於模組化程式設計
3、人為創造全域性變數
ES6中,對頂層物件及其屬性做了以下處理:
1、保留var和function命令,其定義的全域性變數依然為頂層物件的屬性
2、let、const、import、class四種命令定義的全域性變數不屬於頂層物件的屬性
使用this物件獲取頂層物件,但具有一定侷限性:
1、全域性環境中,this會返回頂層物件。
但是,Node模組和ES6模組中,this返回的是當前模組。
2、函式裡面的this,如果函式不是作為物件的方法執行,而是單純作為函式執行,this會指向頂層物件。
但是,嚴格模式下,這時this會返回undefined。
3、不管是嚴格模式,還是普通模式,new Function('return this')(),總是會返回全域性物件。
但是,如果瀏覽器用了CSP(Content Security Policy,內容安全政策),那麼eval、new Function這些方法都可能無法使用
在所有情況下,都取到頂層物件的方法:
//方法一:
(typeof window !== 'undefined'
? window
: (typeof process === 'object' &&
typeof require === 'function' &&
typeof global === 'object')
? global
: this);
//方法二:
var getGlobal = function () {
if (typeof self !== 'undefined') { return self; }
if (typeof window !== 'undefined') { return window; }
if (typeof global !== 'undefined') { return global; }
throw new Error('unable to locate global object');
};
- 解構(Destructuring)賦值
從陣列或物件中提取值,按照對應位置,對變數賦值
解構賦值型別:
1、陣列形式:資料結構具有Iterator介面.
var: var [v1, v2, ..., vN ] = array;
let: let [v1, v2, ..., vN ] = array;
const: const [v1, v2, ..., vN ] = array;
Set結構: let [x, y, z] = new Set(["a", "b", "c"]);
function* fibs() {
var a = 0;
var b = 1;
while (true) {
yield a;
[a, b] = [b, a + b];
}
}
var [first, second, third, fourth, fifth, sixth] = fibs();
// fibs是一個Generator函式,原生具有Iterator介面。解構賦值會依次從這個介面獲取值
2、物件形式:物件解構賦值與陣列解構賦值的區別:
* 陣列的元素按次序排序,變數的值與位置有關;左邊變數在右邊的值可以不賦值
* 物件的解構賦值,右邊的以欄位(變數名與變數值)形式存在,與左邊變數名的順序無關; 左邊的變數與右邊的變數一直,不可缺少
var { foo, bar } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
var { baz } = { foo: "aaa", bar: "bbb" };
baz // undefined
- 模式匹配
“模式匹配”,只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。
var [a,b,c]=[1,2,3]; //模式匹配法_變數的批量賦值
console.log(b);
//巢狀陣列解構
let [foo,[[fa],fb],fc] = [1,[[2],3],4];
console.log(fa)
let [one,,three] = [1,2,"123"];
console.log(three)
let [start, ...d]=["999",2,"56","00"];
console.log(start)
let [x, y, ...z] = ['a'];
console.log(x)
console.log(y)
console.log(z)
let [...arr] = [];
console.log(arr) //陣列
如果解構不成功,變數的值就等於undefined var [fo] = []; // fo undefined
var [bar, fo] = [1]; // fo undefined
// 如果右邊不是陣列,或者嚴格地說,不是可遍歷的結構,那麼會報錯:
let [foo] = 1;
let [foo] = false;
let [foo] = NaN;
let [foo] = undefined;
let [foo] = null;
let [foo] = {};
ES5與ES6區別
- 變數宣告方式
ES5:2種方式。var, function
ES6:6種方式。var, function,let, const, import, class
- 預設值
ES6允許變數指定預設值。
var [foo = true] = [];
foo // true
[x, y = 'b'] = ['a']; // x='a', y='b'
[x, y = 'b'] = ['a', undefined]; // x='a', y='b'
ES6內部使用嚴格相等運算子(===),判斷一個位置是否有值。所以,如果一個數組成員不嚴格等於undefined,預設值是不會生效的
var [x = 1] = [undefined];
x // 1
var [x = 1] = [null];
x // null
上面程式碼中,如果一個數組成員是null,預設值就不會生效,因為null不嚴格等於undefined
惰性求值: 如果預設值是一個表示式,那麼這個表示式是惰性求值的,即只有在用到的時候,才會求值 預設值可以引用解構賦值的其他變數,但是該變數必須已經宣告,否則會報錯。
作者:lzyuan
連結:https://www.jianshu.com/p/e90c447aa645
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯絡作者獲得授權並註明出處。