程式語言是向後相容的,相對於ES5,ES6增加了一些新的特性,下面簡單介紹一些
-
let 和 const 命令
-
變數的解構賦值
-
模板字串
-
陣列新增的方法
-
字串新增的方法
-
class建立物件以及繼承
-
箭頭函式
-
Set 和 Map
1. let 和 const 命令
首先我們要知道這兩個命令是用來做什麼的:
let:定義一個變數;
const:定義一個常量。
在ES6之前我們定義一個變數使用的是關鍵字var,那麼有人會說ES6這樣是不是多此一舉呢?
當然不是,各有各的特點不能說誰一定好,要根據適應的環境來使用。它們的主要不同就是變數提升和作用域。下面我們通過程式碼來具體感受一下。
變數提升
我們來看下面的程式碼來看一下var和let定義的變數。
console.log(b); //undefined
var b = 100;
複製程式碼
根據上面的程式碼,我們知道瀏覽器的js引擎執行緒是根據程式碼結構執行的,那麼在執行的時候列印出來的應該是not defined,為什麼是undefined?undefined是一個基本資料型別,是在我們定義了這個變數沒有賦值的情況下才會列印出來。那麼這裡就存在一個我們在ES5中說的變數提升。什麼是變數提升?變數提升可以分兩個步驟:1、定義。2、執行。也就是說在程式碼開始執行的時候瀏覽器會先檢測整個程式碼,將定義部分提前,然後再去完成執行部分。所以上面程式碼的實際執行:如下:
var b;
console.log(b);
b = 100;
複製程式碼
如果我們使用let來定義呢?
console.log(b) //b is not defined
let b = 100
複製程式碼
列印出來 b is not defined,說明並沒有之前的變數提升,這裡嚴格按照先定義後執行的順序。
作用域
變數或者函式都有自己的作用域。在ES6中新增了一個新的概念:塊級作用域
在這之前只用全域性作用域以及區域性作用域。根據函式來區分,定義在函式裡面的變數的作用域叫做區域性作用域,定義在全域性的變數叫做全域性作用域。
那麼塊級作用域怎麼區別呢?
{
let a = 100;
console.log(a) //100
}
console.log(a) //a is not defined
複製程式碼
上面的程式碼就是一個塊級作用域,我們通過{}
來區別。一個{}
就是一個作用域。
下面我們來看一段程式碼來區別一下let 和 var 定義的變數的作用域。
// 程式碼一
var a = []
for(var i = 0; i < 3; i ++ ){
a[i] = function(){
console.log(i)
}
}
a[0](); //3
a[1](); //3
a[2](); //3
複製程式碼
我們希望的是a[0]()
能夠輸出 0a[1]()
能夠輸出 1,a[2]()
能夠輸出 2,上面程式碼中,變數i只用來控制迴圈,但是迴圈結束後,它並沒有消失,洩露成了全域性變數也就是這個i會一直存在。這是我們很不希望見到的。
//程式碼二
let a = []
for(let i = 0; i < 3; i ++ ){
a[i] = function(){
console.log(i)
}
}
a[0](); //0
a[1](); //1
a[2](); //2
複製程式碼
上面的程式碼很好理解,for迴圈下面是一個{}
程式碼塊,也就相當於一個作用域,每一個作用域裡面的i值互不影響。畫圖理解一下兩段程式碼。
在程式碼一中,使用var定義的i,當for迴圈執行完畢,i的值也隨著變化,最後的i值等於3 那麼之前a[i]
中的i值也會變化.但是程式碼二使用let定義的i會在{ }
中形成自己的作用域,不會因為父作用域數值的改變去改變自己本身的值,所以可以按照需求輸出。
當然在塊級作用域下使用函式宣告定義的函式還是會提升的,這點要注意,不能混淆。
const
const 是用來定義一個常量,它的作用域和let是一樣的,但是他們的區別在於,let可以先定義變數,在使用的過程中賦值,而const必須在定義的同時賦值,不能二次賦值。 如下:
//正確的用法
const p = 3.1;
console。log(p) //3.1
複製程式碼
//錯誤的用法
const a;
a = 2;
console.log(a) //
//Missing initializer in const declaration
複製程式碼
如果是引用性資料型別的話,const定義的常量儲存的是記憶體地址。這點要記住。
2. 變數的解構賦值
什麼是解構賦值,簡單點理解就是一次性給多個變數賦值。
平時我們賦值的時候一般是這樣的
let a = 1;
let b = 2;
let c = 3;
複製程式碼
這樣賦值沒問題但是卻增加了程式碼量,在ES6中允許
let [a,b,c] = [1,2,3]
複製程式碼
上面程式碼表示,可以從陣列中提取值,按照對應位置,對變數賦值。
本質上,這種寫法屬於“模式匹配”,只要等號兩邊的模式相同,左邊的變數就會被賦予對應的值。下面是一些使用巢狀陣列進行解構的例子。
let [foo, [[bar], baz]] = [1, [[2], 3]];
foo // 1
bar // 2
baz // 3
let [ , , third] = ["foo", "bar", "baz"];
third // "baz"
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] = [];
let [bar, foo] = [1];
複製程式碼
左右結構要一一對應
let [x, y] = [1, 2, 3];
x // 1
y // 2
let [a, [b], d] = [1, [2, 3], 4];
a // 1
b // 2
d // 4
複製程式碼
可以設定預設值,如果後面繼續賦值的話會被覆蓋掉。
let [a,b=2] = [1]
a //1
b //2
let [c,d = 3] = [1,5]
c //1
d //5
複製程式碼
給物件解構賦值
物件是一個無序的屬性集合,所以在給物件解構賦值的時候要和屬性名字一一對應。
let { bar, foo } = { foo: "aaa", bar: "bbb" };
foo // "aaa"
bar // "bbb"
複製程式碼
變數之間的賦值
let [x = 1, y = x] = []; //x=1, y=1
let [x = y, y = ] = []; //報錯
複製程式碼
上面的程式碼提示我們變數之間互相賦值的時候,賦值的變數必須是已經定義好的。 一個小的應用變數直間相互賦值的特性一個小的敲門
//將x,y的值調換
let x = 1;
let y = 2;
[x,y] = [y,x]
複製程式碼
字串之間的賦值
const [a, b, c, d, e] = 'hello';
a // "h"
b // "e"
c // "l"
d // "l"
e // "o"
//類似陣列的物件都有一個length屬性,因此還可以對這個屬性解構賦值。
let {length : len} = 'hello';
len // 5
複製程式碼
函式傳參時候的解構賦值
function add([x, y]){
return x + y;
}
add([1, 2]); // 3
複製程式碼
總而言之,在使用解構賦值的時候一定要一一對照
3. 模板字串
模板字串使用反引號 () 來代替普通字串中的用雙引號和單引號。模板字串可以包含特定語法(${})的佔位符
let obj = {
name : "xiaoxiao",
age : 15
}
console.log(`我叫${obj.name}今年${obj.age}歲了`)
複製程式碼
4. 陣列新增的方法
Array.isArray()
作用:判斷是否是陣列
let arr = [1,2,3]
console.log(Array.isArray(arr)) //true
複製程式碼
Array.from()
這個方法是Array構造器的靜態方法,作用:將類陣列物件轉化成真正的陣列
let obj = "hello"
console.log(Array.isArray(obj)) //false
let arr = Array.from(obj) //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(arr)
console.log(Array.isArray(arr)) //true
複製程式碼
Array.of()
作用:將一組值轉換為陣列
let arr1 = Array.of(3)
let arr2 = Array.of("3")
let arr3 = Array.of(1,2,3)
console.log(arr1,arr2,arr3) //[ 3 ] [ '3' ] [ 1, 2, 3 ]
複製程式碼
find和findlndex
find:用於找出第一個符合條件的陣列元素。找不到則是 undefined ;只要找到一個就會終止。如果需要全部找出來需要用filter();
findIndex:返回第一個符合條件的陣列元素的索引。找不到則是-1;
和indexof有異曲同工之妙,indexOf返回的是索引
let arr = [4,3,2,1]
let rs = arr.find(function(item,index){
return item ==2;
})
let rt = arr.findIndex(function(item,index){
return item == 3
})
console.log(rs) //2
console.log(rt) //1
複製程式碼
indexOf
//indexof
let arr = [1,2,6,8]
console.log(arr.indexOf(6)) //2
複製程式碼
includes
作用:判斷元素是否在陣列中存在。返回值是 true|false
let arr = [1,2,6,8]
console.log(arr.includes(6)) //true
複製程式碼
fill
作用:給陣列填充指定值。fill 方法用於空陣列的初始化非常方便。但是已有資料會被覆蓋。 fill 方法還可以接受第二個和第三個引數,用於指定填充的起始位置和結束位置
let arr1 = new Array(5)
arr1.fill("*")
console.log(arr1) //[ '*', '*', '*', '*', '*' ]
//覆蓋原有資料
let arr2 = [1,2,3]
arr2.fill("*")
console.log(arr2) //[ '*', '*', '*' ]
複製程式碼
陣列的擴充套件運算子
功能:把資料結構轉成陣列。和Array.from()的功能相似
let arr = "hello"
let arr2 = [...arr]
console.log(arr2) //[ 'h', 'e', 'l', 'l', 'o' ]
console.log(Array.isArray(arr2)) //true
複製程式碼
擴充套件運算子連結陣列
let arr1 = [1,2]
let arr2 = [3,4]
let arr = [...arr1,...arr2]
console.log(arr) [ 1, 2, 3, 4 ]
複製程式碼
注意:在使用擴充套件運算子的時候必須要用容器將其包括起來。
map
獲取一個新的陣列
//將成績加10並返回
let arr = [
{name:"aa",score:11},
{name:"bb",score:22},
{name:"cc",score:22},
{name:"dd",score:52},
{name:"ee",score:45},
{name:"ff",score:34},
{name:"gg",score:77},
{name:"hh",score:88},
]
let rs = arr.map((item,index,arr) => {
return item.score += 10
})
// let rs =arr.map((item,index,arr) => {
// return arr
// })
console.log(rs) //[ 21, 32, 32, 62, 55, 44, 87, 98 ]
複製程式碼
5. 字串新增的方法
includes(),startWith(),endsWith()
includes():返回布林值,表示是否找到了引數字串。
startsWith():返回布林值,表示引數字串是否在原字串的頭部。。
endsWith():返回布林值,表示引數字串是否在原字串的尾部。。
let s = 'Hello world!';
s.startsWith('Hello') // true
s.endsWith('!') // true
s.includes('o') // true
複製程式碼
這三個方法都支援第二個引數,表示開始搜尋的位置。
let s = 'Hello world!';
s.startsWith('world', 6) // true
s.endsWith('Hello', 5) // true
s.includes('Hello', 6) // false
複製程式碼
上面程式碼表示,使用第二個引數n時, endsWith的行為與其他兩個方法有所不同。 它針對前n個字元,而其他兩個方法針對從第n個位置直到字串結束。
repeat()
repeat方法返回一個新字串,表示將原字串重複n次。
'x'.repeat(3) // "xxx"
'hello'.repeat(2) // "hellohello"
'na'.repeat(0) // ""
//引數如果是小數,會被取整。
'na'.repeat(2.9) // "nana"
複製程式碼
padStart(),padEnd()
padStart()用於頭部補全,padEnd()用於尾部補全。
'x'.padStart(4, 'ab') // 'abax'
'x'.padEnd(5, 'ab') // 'xabab'
複製程式碼
上面程式碼中,padStart和padEnd一共接受兩個引數,第一個引數用來指定字串的最小長度,第二個引數是用來補全的字串。
如果原字串的長度,等於或大於指定的最小長度,則返回原字串。
'xxx'.padStart(2, 'ab') // 'xxx'
'xxx'.padEnd(2, 'ab') // 'xxx'
複製程式碼
如果用來補全的字串與原字串,兩者的長度之和超過了指定的最小長度,則會截去超出位數的補全字串。
'abc'.padStart(10, '0123456789')
// '0123456abc'
複製程式碼
如果省略第二個引數,預設使用空格補全長度。
'x'.padStart(4) // ' x'
'x'.padEnd(4) // 'x '
複製程式碼
padStart的常見用途是為數值補全指定位數。下面程式碼生成 10 位的數值字串。
'1'.padStart(10, '0') // "0000000001"
'12'.padStart(10, '0') // "0000000012"
'123456'.padStart(10, '0') // "0000123456"
複製程式碼
另一個用途是提示字串格式。
'12'.padStart(10, 'YYYY-MM-DD') // "YYYY-MM-12"
'09-12'.padStart(10, 'YYYY-MM-DD') // "YYYY-09-12"
複製程式碼
6. class建立物件以及繼承
我們我們建立一個物件有一下幾種方法
class Num{
constructor(name){
this.name = name
}
say(){
console.log(`我是${this.name}`)
}
}
let ra = new Num("小強")
ra.say() //我是小強
複製程式碼
也就是說我們可以直接通過一個類來直接new一個物件。
注意:
class 是關鍵字,後面緊跟類名,類名首字母大寫,採取的是大駝峰命名法則。類名之後是{}。
在{}中,不能直接寫語句,只能寫方法,方法不需要使用關鍵字
方法和方法之間沒有逗號。不是鍵值對
下面就是我們在做專案的時候所必須的--繼承。
根據需求的不同我們所需要的物件的屬性或者方法也可能不同,或者多點屬性或者方法,難道我們需要將之前所寫的屬性在重新寫一次嗎?如果需要100個物件,每一個物件都多一個屬性或者方法呢?這時候我們就用到了--繼承,讓子類繼承父類的方法和屬性的同時還可以有自己的屬性和方法。這也是我們現在最常用的建立物件的方式。
繼承
格式:
下面使用一個小案例,更進一步的瞭解一下。
定義一個NBAplayer類,然後讓mvp這個類繼承NBAplayer,可以可以使用父類的方法
class NBAplayer{
constructor(name,age,height){
this.name = name
this.age = age
this.height = height
}
say(){
alert(`姓名${this.name}年齡${this.age}身高${this.height}`)
}
static jump(){ //靜態方法 只能使用類名去掉用。
alert("我是靜態函式。。。。。物件無法呼叫")
}
}
class mvp extends NBAplayer{
constructor(name,age,height,year){
super(name,age,height)
this.year = year
}
showmvp(){
alert(`我是${this.year}年的mvp`)
}
}
let r2 = new mvp("xiaong",15,5,2222)
// r2.say(); //正常執行
// r2.showmvp() //正常執行
// NBAplayer.jump() //呼叫靜態函式。
mvp.jump()
複製程式碼
在繼承的時候有兩點要注意:
- 使用 extends 關鍵字來實現繼承
- 在子類中的構造器 constructor 中,必須要顯式呼叫父類的 super 方法,如果不呼叫,則 this 不可用
7. 箭頭函式
箭頭函式只是一個函式的簡寫,在做專案的時候這個可以很大程度降低程式碼量
//沒有引數的時候
function f(){console.log("....")} //寫為箭頭函式
var f1 = () => {console.log("....")}
var x = 10,y = 11;
//有一個引數x
var f2 = x => {console.log(x+x)}
//有兩個引數及以上的時候必須加括號
var f3 = (x,y) => {console.log(x+y)}
f1() //.......
f2(x) //20
f3(x,y) //21
複製程式碼
要注意的是使用箭頭函式的時候不能使用this,這兩個老死不相往來。
8. Set 和 Map
Set
set和陣列差不多但不是陣列,它是一種集合,它和陣列的區別在於:set裡面的值都是唯一的,沒有重複的。
看下面一段程式碼:在放入基本資料型別的時候需要使用[]
包起來
let arr = [1,1,1,2,5,5,6,9]
let s1 = new Set([1,1,1,2,5,5,6,9])
console.log(arr) //[ 1, 1, 1, 2, 5, 5, 6, 9 ]
console.log(s1) //Set { 1, 2, 5, 6, 9 }
console.log(Array.isArray(s1)) //false
複製程式碼
上面的程式碼我們很容易的看出來Set不是陣列,只是一個類陣列,那麼我們可以使用之前的知識將其轉化為陣列
let r2 = [...s1]
console.log(r2) //[ 1, 2, 5, 6, 9 ]
console.log(Array.isArray(r2)) //true
複製程式碼
在建立set的時候如果要放入物件需要使用add()方法
let s1 = new Set();
s1.add({name:"ddd"})
s1.add({age:15})
s1.add({year:2018})
for(let item of s1){
console.log(item)
}
複製程式碼
根據set裡面資料的唯一性可以做一個小的案例---陣列
let arr = [1,2,5,45,9,NaN,true,NaN]
let rs = [...(new Set(arr))]
console.log(rs) //[ 1, 2, 5, 45, 9, NaN, true ]
複製程式碼
Map
它類似於物件,裡面存放也是鍵值對,區別在於:物件中的鍵名只能是字串,但是使用map,它裡面的鍵可以是任意值。
建立一個Map
let m = new Map([
["name","xiaoming"],
["age","16"]
])
m.set(false,"sss")
m.set([],"a")
console.log(m) //Map { 'name' => 'xiaoming', 'age' => '16', false => 'sss', [] => 'a' }
複製程式碼
那麼很好理解Map是一個強大的類陣列,我們可以通過擴充套件運算子將其轉換為陣列,然後進行資料的處理等等。
Set和Map都可以轉換為陣列,需要注意的是它們的各自的新增元素的方法。
ES6的特性還有很多,這裡只是簡單的介紹了幾種我們比較常見的,如果大家在開發的過程中有什麼新的東西,多多留言.