ES6新特性

es6有哪些新特性?

一、let

1. 沒有變量提升

console.log(a);

let a = 4;

// a is not defined

2. 不能重複申明

let a = 4;

let a = 5;

console.log(a);

// Identifier 'a' has already been declared

3. 臨時失效區(暫時性死區)

var a = 5;

function fn(){

console.log(a);

let a = 4;

}

fn();

// a is not defined

4. 具有塊級作用域(由花括號包裹的區域)

同樣具有塊級作用域的還有const。

來看一個例子

var a = 5;

function foo(){

console.log(a); // undefined

if(false){

var a = 6;

}

}

這顯然不是我們想要的結果,因為

js在es6之前沒有塊級作用域

for(let i = 0; i < 3; i++){

console.log(i);

}

console.log(i);

// 0 1 2 i is not defined

{

let a = 10;

}

console.log(a);

// a is not defined

老生常談的閉包問題 實質上就是為了解決沒有塊級作用域帶來的問題

閉包

* 外部函數(作用域)中有內部函數(作用域)

* 內部函數調用了外部函數的局部變量

* 外部函數執行完後,因為內部函數還在使用該局部變量,所以該局部變量不被釋放,保證內部函數正常使用

* 閉包函數(立即執行函數)為

(function(){

// ...函數體

})();

var

aLi=document.getElementsByTagName('li');// len = n

for(var i = 0; i < aLi.length; i++){

aLi[i].onclick = function(){

console.log(i);

}

}

// n......n

var aLi=document.getElementsByTagName('li');// len = n

for(var i = 0; i < aLi.length; i++){

(function(i){

aLi[i].onclick = function(){

console.log(i);

}

})(i)

}

// 0、1、2....n

for循環實質可以理解為 由n個”{}”構成的,在每個花括號中,let的作用域都是獨立的,所以可以拿到每個i值。

但對於var來說實質是一個作用域,所以無法保留每個i的值。

二、const

在es6之前,如果我們想定義常量,通常由程序員自己約定

var NUM = 100;

將所有字母都大寫的變量約定為常量,但本質還是變量

1.const定義只是地址不能修改

const NUM = 100;

NUM = 200;

// Assignment to constant variable.

由const定義的常量,無法修改其地址值。

在這裡為啥要強調是地址值

因為 以下代碼在非嚴格模式下是可以通過的

const OBJ = {a: 100};

OBJ.a = 200;

console.log(OBJ.A);

// 200

這時候會發現這很坑啊!!!

怎麼辦呢,如果我們想要定義一個常量對象呢

const OBJ = {a: 100};

Object.freeze(OBJ);

OBJ.a = 200;

console.log(OBJ.a);

// 100

這樣就可以了..

2.沒有變量提升

3.塊級作用域

let 和 const 聲明的變量不掛在window上

三、class 類

在es6之前,我們要定義一個類,只能通過function來模擬

function Person(){

this.name = 'xxx';

}

Person.prototype.say = function(){

}

var person = new Person();

問:將屬性放在原型中會怎麼樣?

如 Person.prototype.name = 'xxx';

答:對於普通數據類型,沒有問題,但對於引用類型,對一個對象的修改,會影響所有繼承該類的對象

1.語法

class Person{

constructor(name){

this.name = name;

}

say() {

console.log(this.name);

}

}

var person = new Person();

person.say();

2.繼承的實現

class Man extends Person{

constructor(name, food){

super(name, food); // 必須放在構造器的第一行,代表調用父類的構造方法

this.food = food;

}

eat(){

console.log(this.food);

}

}

var man = new Man();

man.say();

3.static 靜態方法/變量

class Person{

constructor(){

}

static say(){

console.log(123); // 可以認為這是一個靜態方法

}

static name(){

return 'xxx'; // 可以認為這是一個靜態變量

}

}

Person.say();

在es6中,規定Class 內部只有靜態方法, 沒有靜態屬性

以下寫法都無效

class Person{

constructor(){

}

name: 2

static name: 2

}

console.log(Person.name)

// undefined

四、Set 集合

Set是一個不能有重複元素的集合,重複添加無效

var s = new Set();

s.add(1);

s.add(2);

// s.delete(2) 刪除

// s.clear() 清空

// s.size() 長度

1.遍歷Set

var keys = s.keys(); // 返回一個迭代器

for(var k of keys){

console.log(k);

}

var values = s.values();

for(var v of values){

console.log(v);

}

var entries = s.entries(); // 將key和value 組合成一個數組返回

for(var e of entries){

console.log(e);

}

如果我們想在es6之前使用給數組去重

2.Array數組去重問題

方法一:

var arr = [1,2,3,4,1,1,1];

function fn(arr){

var map = {};

var newArr = arr.filter(function(item, index){

if(!map[item]){

map[item] = true;

return item;

}

});

return newArr;

}

fn(arr);

方法二:

var arr = [1,2,3,4,1,1,1];

function fn(arr){

var newArr = [];

for(var i = 0; i < arr.length; i++){

if(newArr.indexOf(arr[i]) === -1){

newArr.push(arr[i]);

}

}

return newArr;

}

fn(arr);

利用Array.from的方法三:

var arr = [1,2,3,4,1,1,1];

function fn(arr){

var s = new Set(arr);

return Array.from(s);

}

fn(arr);

3.Array返回只出現一次的元素

var arr = [1,2,3,4,1,1,1];

function fn(arr){

var newArr = [];

for(var i = 0; i < arr.length; i++){

if(arr.indexOf(arr[i]) === arr.lastIndexOf(arr[i])){

newArr.push(arr[i]);

}

}

return newArr;

}

fn(arr);

五、Map(鍵值對)

var m = new Map();

m.set('a',1);

m.set('b',2);

m.get('a'); // 1

// m.delete('a')

對象的屬性名 認為是字符串,但Map的鍵 可以是所有數據類型

forEach可以遍歷Array、Set、Map。

for of被專門用來遍歷迭代器。

六、arrow 箭頭函數

終於來到了箭頭函數的環節()=>{}

這是一種特別簡潔、優雅的函數寫法

他可以這麼寫

var fn = (item, index) => {console.log(item)}

也可以這麼寫

var fn = item => {console.log(item)}

還可以這麼寫

var fn = item => (item)

fn(2) // 2

還可以更簡潔

var fn = item => item

fn(2) // 2

=>後使用小括號() 表示將結果作為返回值,單行結果時還可以省略

當參數唯一時,還可以將前面的() 省略

但是他失去了一些東西…

var fn = () => {

console.log(arguments);

}

fn(2) // arguments is not defined

解決方法如下:

var fn = (...arg) => {

console.log(arg);

}

fn(2) // [2]

箭頭函數不可以當作構造函數,也就是說,不可以使用new命令,否則會拋出一個錯誤。

...稱為位擴展運算符,在下面會詳細介紹

但箭頭函數最厲害的地方還不在此

1.改變默認的this指向

箭頭函數能夠將函數外面的this指向同步到函數內部,比如說這樣:

var

aLi=document.getElementsByTagName('li');// len = n

for(var i = 0; i < aLi.length; i++){

aLi[i].onclick = function(){

setTimeout(function(){

console.log(this.innerHTML);

// 此時無法獲取,因為this指向調用他的對象,而setTimeout為window下的方法,此時this指向window

})

}

}

將function改為箭頭函數就能夠正確運行

var obj = {

a: 1,

say: function(){

console.log(this.a);

}

}

obj.say() // 1

上面乍一看這個挺正常的結果呀… 但是如果改成箭頭函數

var obj = {

a: 1,

say: () => {

console.log(this.a);

}

}

obj.say() // undefined

所以箭頭函數雖好,也要看清場合使用啊。


分享到:


相關文章: