一、ECMAScript和JavaScript關係
JavaScript 的創造者 Netscape 公司,決定將 JavaScript 提交給標準化組織 ECMA,希望這種語言能夠成為國際標
準,但是JavaScript本身也已經被 Netscape 公司註冊為商標,後面的標準都由ECMA制定,取名ECMAScript。
那麼ES6這個版本引入的新內容較多,通常指JavaScript語言的下一個版本。
二、let命令
ES6 新增了let
命令,用來宣告變數。它的用法類似於var
,但是所宣告的變數,只在let
命令所在的程式碼塊內
有效。
var和let定義變數區別:
<script>
//var的作用域是函式級的(函式內部定義變數只能函式裡面使用)
// function showName()
// {
// var myName = "張學友";
// alert(myName + "歡迎您!"); //此處的myName為"張學友"
// }
// showName();
// alert(myName + "歡迎您!"); //此處會報錯,myName只能在showName函式中使用
//var的作用域是函式級的(在程式碼塊中定義的變數可以在程式碼塊之外使用)
// if(1==1)
// {
// var myName = "張學友";
// }
// alert(myName + "歡迎您!"); //此處可以執行
//let的作用域是程式碼塊級別的
// if(1==1)
// {
// let myName = "張學友";
// }
// alert(myName + "歡迎您!"); //此處會報錯
//let不存在變數提升
// console.log(a); //報錯
// let a = "apple";
// console.log(b); //undefined
// var b = "banana";
</script>
var和let在迴圈計數時候的區別:
<script>
// for(var i = 1;i <= 10;i++)
// {
// //
// }
// alert(i); //此處會列印11,i在迴圈體內和迴圈體外都可以使用
//此時計數器的變數洩露成了全域性變數
// for(let i = 1;i <= 10;i++)
// {
// //
// }
// alert(i); //此處會報錯,i只在迴圈體內有效,在迴圈體外無效
// 輸出十個11
// i是全域性的,定時器程式碼在迴圈之後發生,所以列印十個11
// for (var i = 1; i <= 10; i++) {
// setTimeout(function(){
// console.log(i);
// })
// }
//輸出1 2 3 4 5 6 7 8 9 10
for (let j = 1; j <= 10; j++) {
setTimeout(function(){
console.log(j);
})
}
</script>
迴圈繫結網頁元素事件中var和let的區別:
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>迴圈繫結按鈕事件</title>
</head>
<body>
<h2>點選三個按鈕分別彈出1,2,3</h2>
<input type="button" class="myButton" value="第一個按鈕" />
<input type="button" class="myButton" value="第二個按鈕"/>
<input type="button" class="myButton" value="第三個按鈕"/>
</body>
</html>
<script>
//在此案例中i是全域性的,點選按鈕發生在迴圈之後,所以列印結果全部為4
// var list = document.getElementsByClassName("myButton");
// for(var i = 0;i < list.length;i++)
// {
// list[i].onclick = function(){
// alert(i+1);
// }
// }
//上述程式碼不能列印1,2,3,而是列印4,需要採取JS閉包來解決此問題;
//閉包就是能夠讀取其他函式內部變數的函式
// var list = document.getElementsByClassName("myButton");
// for(var i = 0;i < list.length;i++)
// {
// list[i].onclick = (function(num)
// {
// return function(){
// alert(num);
// }
// })(i+1);
// }
//如果使用ES6中let關鍵字則不存在上面演示的問題
var list = document.getElementsByClassName("myButton");
for(let i = 0;i < list.length;i++)
{
list[i].onclick = function(){
alert(i+1);
}
}
</script>
三、const命令
const
宣告一個只讀的常量。一旦宣告,常量的值就不能改變。
<script>
// const PI = 3.14;
// PI = 3.15; //此處會報錯,const宣告的變數不能改變其值
//const一旦宣告變數,就必須立即初始化,不能留到以後賦值。
//const PI; //報錯
//const實際上保證的,並不是變數的值不得改動,
//而是變數指向的那個記憶體地址所儲存的資料不得改動。
const arr = [];
arr.push('jack'); //可以執行
arr.push("rose"); //可執行
console.log(arr[0]);
console.log(arr[1]);
</script>
四、變數的解構賦值
1、陣列的解構賦值
ES6 允許按照一定模式,從陣列和物件中提取值,對變數進行賦值
// let a = 1;
// let b = 2;
// let c = 3;
//上述程式碼可以如下編寫(從陣列中提取值,按照對應位置,對變數賦值)
// let[a,b,c]=[1,2,3];
陣列解構賦值案例:
//let [a, [[b], c]] = [1, [[2], 3]]; //a=1,b=2,c=3
//let [ , , c] = ["jack", "rose", "mike"]; //c=mike
//let [x, , y] = [1, 2, 3]; //x=1,y=3
//let [head, ...tail] = [1, 2, 3, 4]; //head=1,tail=[2,3,4]
//let [x, y, ...z] = ['a']; //x=a,y=undefined,z=[]
解構不成功,變數的值就等於undefined:
//let [foo] = []; //解構不成功,foo=undefined
//let [bar, foo] = [1]; //bar=1,foo解構不成功foo=undefined
不完全解構:
左邊的模式只能匹配右邊的一部分,也可以解構成功:
let [x, y] = [1, 2, 3]; //x=1,y=2
字串解構(將字串當成一個陣列):
let [a, b, c, d, e] = 'hello';
console.log(a);
console.log(b);
console.log(c);
console.log(d);
console.log(e);
預設值:
解構賦值允許指定預設值
//let [foo = true] = []; //foo=true;
//let [x, y = 'b'] = ['a']; // x='a', y='b'
//let [x, y = 'b'] = ['a', undefined]; // x='a', y='b'
//let [x = 1] = [null]; //x=null(只有當一個陣列等於undefined,預設值才會生效)
預設值可以引用解構賦值的其他變數,但該變數必須已經宣告
//let [x = 1, y = x] = []; // x=1; y=1
//let [x = 1, y = x] = [2]; // x=2; y=2
//let [x = 1, y = x] = [1, 2]; // x=1; y=2
//let [x = y, y = 1] = []; // ReferenceError: y is not defined
2、物件的解構賦值
解構不僅可以用於陣列,還可以用於物件。
let { foo, bar } = { foo: 'aaa', bar: 'bbb' }; //foo='aaa', bar='bbb'
以上程式碼看上去和陣列解構賦值沒有多大區別,但是:
(1) 陣列解構中陣列的元素是按次序排列的,變數的取值由它的位置決定;
(2) 物件解構中物件的屬性沒有次序,變數必須與屬性同名,才能取到正確的值 ;
如下:
let { bar, foo } = { foo: 'aaa', bar: 'bbb' }; //foo="aaa" bar= "bbb"
let { baz } = { foo: 'aaa', bar: 'bbb' }; //baz = undefined,解構失敗,值為undefined
物件的解構賦值,可以很方便地將現有物件的方法,賦值到某個變數:
// 例一
let { log, sin, cos } = Math; //將Math物件的對數、正弦、餘弦三個方法,賦值到對應的變數上
// 例二
const { log } = console; //將console.log賦值到log變數,簡化程式碼
log('hello') // hello
如果變數名與屬性名不一致,必須寫成下面這樣:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' }; //baz = "aaa"
let obj = { first: 'hello', last: 'world' };
let { first: f, last: l } = obj; //f = 'hello' l = 'world'
這實際上說明,物件的解構賦值是下面形式的簡寫
let { foo: foo, bar: bar } = { foo: 'aaa', bar: 'bbb' };
真正被賦值的是後者,而不是前者:
let { foo: baz } = { foo: 'aaa', bar: 'bbb' };
//baz = "aaa" foo = error: foo is not defined
與陣列一樣,解構也可以用於巢狀結構的物件 :
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p: [x, { y }] } = obj;
x // "Hello"
y // "World"
注意,這時p
是模式,不是變數,因此不會被賦值。如果p
也要作為變數賦值,可以寫成下面這樣。
let obj = {
p: [
'Hello',
{ y: 'World' }
]
};
let { p, p: [x, { y }] } = obj;
x // "Hello"
y // "World"
p // ["Hello", {y: "World"}]
預設值:
let {x = 3} = {};
x // 3
let {x, y = 5} = {x: 1};
x // 1
y // 5
let {x: y = 3} = {};
y // 3
let {x: y = 3} = {x: 5};
y // 5
let { message: msg = 'Something went wrong' } = {};
msg // "Something went wrong"
預設值生效的條件是,物件的屬性值嚴格等於undefined
var {x = 3} = {x: undefined};
x // 3
var {x = 3} = {x: null};
x // null
注意點:
如果要將一個已經宣告的變數用於解構賦值,必須非常小心
// 錯誤的寫法
let x;
{x} = {x: 1};
上面程式碼的寫法會報錯,因為 JavaScript 引擎會將{x}
理解成一個程式碼塊, 只有不將大括號寫在行首,才能解決
這個問題。
// 正確的寫法
let x;
({x} = {x: 1});
由於陣列本質是特殊的物件,因此可以對陣列進行物件屬性的解構。
let arr = [1, 2, 3];
let {0 : first, [arr.length - 1] : last} = arr; //利用陣列下標解構賦值
first // 1
last // 3