ECMAScript 6入門(2)

上篇文章我們介紹了ES6的多行字符串表示方法,map,set,for...of循環(huán),rest參數(shù)以及l(fā)et和const,這次我們接著來看看ES6有哪些過人之處。

ECMAScript 6為數(shù)組增添的新方法:map(),reduce(),filter()

①map()

語法:arr.map(函數(shù));

功能:相當于讓arr的每個數(shù)據(jù)執(zhí)行了一次()中的方法,例:

function add(a){
    return  b =a*a;
}
var arr = [1,2,3,4];
var newArr = arr.map(add);
console.log( newArr);
image

②reduce()

語法:arr.reduce(函數(shù));

功能:把一個函數(shù)作用在arr的每一個元素上,它必須接收兩個參數(shù),reduce()把結果繼續(xù)和序列的下一個元素做累積計算。例:要把[1,2,3,4,5,6]變換成整數(shù)123456,就可以用reduce()做到

function changeNumber(x,y){
      return  x * 10 + y;
 }
var arr = [1,2,3,4,5,6];
var newArr = arr.reduce(changeNumber);
console.log(newArr);

③filter()

語法:arr.filter(函數(shù));

功能:用于把Array的某些元素過濾掉,然后返回剩下的元素,和map()類似,Array的filter()也接收一個函數(shù)。和map()不同的是,filter()把傳入的函數(shù)依次作用于每個元素,然后根據(jù)返回值是true還是false決定保留還是丟棄該元素。例:利用filter()刪除數(shù)組中的偶數(shù)項

function deleteOushu(x){
     return x % 2 !== 0;
}
var arr = [1,2,3,4,5,6,7,8,9,10];
var newArr = arr.filter(deleteOushu);
console.log(newArr);
image

filter()接收的回調(diào)函數(shù)可以有多個參數(shù)。第一個參數(shù)表示Array的某個元素。另外兩個參數(shù),表示元素的位置和數(shù)組本身:

var arr = ['A', 'B', 'C'];
var r = arr.filter(function (element, index, self) {
    console.log(element); 
    // 依次打印'A', 'B', 'C'
    console.log(index); 
    // 依次打印0, 1, 2
    console.log(self); 
    // self就是變量arr
    return true;
});

我們還可以利用filter()巧妙的去除數(shù)組的重復項:

var arr = ["a","b","c","b","a","d"];
var newArr = arr.filter(function(element,index,self){
    return self.indexOf(element)===index;
});
y.png

箭頭函數(shù)

ES6標準新增了一種新的函數(shù):Arrow Function(箭頭函數(shù))

x => x * x;

這個箭頭函數(shù)等價于

function (x){
    return  x * x ;
}

箭頭函數(shù)相當于匿名函數(shù),并且簡化了函數(shù)定義。箭頭函數(shù)有兩種格式,一種像上面的,只包含一個表達式,連{ ... }和return都省略掉了。還有一種可以包含多條語句,這時候就不能省略{ ... }和return:

x => { 
    if(x>0) {
        return x * x;
    } 
    else{
        return -x * x;
    } 
}; 

如果參數(shù)不是一個,就需要用括號()括起來:

(x,y) => x * x + y * y;

無參數(shù)時就用():

() => 1;

可變參數(shù):

(x, y, ...rest) => {
    var i, sum = x + y;
    for (i=0; i<rest.length; i++) {
        sum += rest[i];
    }
    return sum;
}

如果要返回一個對象就要注意,如果是單表達式,這么寫的話會報錯:

x => { foo: x }    // SyntaxError

因為和函數(shù)體的{ ... }有語法沖突,所以要改為:

x => ({ foo: x })

箭頭函數(shù)看上去是匿名函數(shù)的一種簡寫,但實際上,箭頭函數(shù)和匿名函數(shù)有個明顯的區(qū)別:箭頭函數(shù)內(nèi)部的this是詞法作用域,由上下文確定。箭頭函數(shù)完全修復了this的指向,this總是指向詞法作用域,也就是外層調(diào)用者obj。由于this在箭頭函數(shù)中已經(jīng)按照詞法作用域綁定了,所以,用call()或者apply()調(diào)用箭頭函數(shù)時,無法對this進行綁定,this取決于箭頭函數(shù)在哪定義,this不可變,在函數(shù)內(nèi)部這個執(zhí)行環(huán)境中相當于常量。
箭頭函數(shù)沒有arguments,不能通過arguments對象訪問傳入?yún)?shù),只能使用顯示命名或者其他特性完成。
箭頭函數(shù)不能使用new關鍵字來實例化對象,不然會報錯。

箭頭函數(shù)跟普通函數(shù)的區(qū)別,什么是匿名函數(shù)
(1)不需要function
(2)省略return
(3)繼承當前上下文的關鍵字(定義時所在對象)
( 4)不能用作構造函數(shù)
(5)不能用yeild
(6)this固有化
(7)不能使用call,apply,bind去改變

匿名函數(shù):沒有名字的函數(shù)表達式,可以實現(xiàn)動態(tài)編程。

generator(生成器)

一個generator看上去像一個函數(shù),但可以返回多次。函數(shù)執(zhí)行過程中,如果沒有遇到return語句(函數(shù)末尾如果沒有return,就是隱含的return undefined;),控制權無法交回被調(diào)用的代碼。generator跟函數(shù)很像,定義如下:

function* foo(x) { 
    yield x + 1;
    yield x + 2;
    return x + 3;
}

和函數(shù)不同的是generator由function定義(注意多出的號),并且除了return語句,還可以用yield返回多次。例:編寫一個產(chǎn)生斐波那契數(shù)列的函數(shù),可以這么寫:

function fib(max) {
    var t=0; 
    var a=0;
    var b=1;
    var arr=[0, 1];
    while (arr.length < max) { 
        t = a + b;
        a = b;
        b = t;
        arr.push(t);
    }
    return arr;
}
fib(5);      // 測試結果[0, 1, 1, 2, 3]

函數(shù)只能返回一次,必須返回一個Array。generator就可以一次返回一個數(shù),不斷返回多次。用generator改寫如下:

function* fib(max) {
    var t=0;
    var a=0;
    var b=1;
    var n=1;
    while (n < max) {
        yield a;
        t = a + b;  
        a = b;
        b = t;
        n++;
    }
    return a;
}
fib(5);    // fib{[[GeneratorStatus]]: "suspended",[[GeneratorReceiver]]:Window}

fib(5)僅僅是創(chuàng)建了一個generator對象,還沒有去執(zhí)行它
調(diào)用generator對象有兩個方法,一是不斷地調(diào)用next()方法:

var f = fib(5);
f.next();    // {value: 0, done: false}
f.next();    // {value: 1, done: false}
f.next();    // {value: 1, done: false}
f.next();    // {value: 2, done: false}
f.next();    // {value: 3, done: true}

value就是yield的返回值,done表示這個generator是否已經(jīng)執(zhí)行結束了。為true時value就是return的返回值,并且generator對象就已經(jīng)全部執(zhí)行完畢,不要再繼續(xù)調(diào)用next()了。
第二個方法是直接用for ... of循環(huán)迭代generator對象,這種方式不需要我們自己判斷done:

for (var x of fib(5)) {
    console.log(x);    // 依次輸出0, 1, 1, 2, 3
}       

class繼承

繼承中我們看到了JavaScript的對象模型是基于原型實現(xiàn)的,特點是簡單,缺點是理解起來比傳統(tǒng)的類-實例模型要困難,最大的缺點是繼承的實現(xiàn)需要編寫大量代碼,并且需要正確實現(xiàn)原型鏈。新的關鍵字class從ES6開始正式被引入到JavaScript中。class的目的就是讓定義類更簡單。
我們先回顧用函數(shù)實現(xiàn)Student的方法:

function Student(name) {
    this.name = name;
} 
Student.prototype.hello = function () {
    alert('Hello, ' + this.name + '!');
}

如果用新的class關鍵字來編寫Student,可以這樣寫:

class Student {
    constructor(name) {
        this.name = name;
    } 
    hello() {
        alert('Hello, ' + this.name + '!');
    }
}

比較一下就可以發(fā)現(xiàn),class的定義包含了構造函數(shù)constructor和定義在原型對象上的函數(shù)hello()(注意沒有function關鍵字),這樣就避免了Student.prototype.hello = function () {...}這樣分散的代碼。
最后,創(chuàng)建一個Student對象

var xiaoming = new Student('小明'); 
xiaoming.hello();

用class定義對象的另一個巨大的好處是繼承更方便了。想一想我們從Student派生一個PrimaryStudent需要編寫的代碼量?,F(xiàn)在,原型繼承的中間對象,原型對象的構造函數(shù)等等都不需要考慮了,直接通過extends來實現(xiàn):

class PrimaryStudent extends Student { 
    constructor(name, grade) { 
        super(name); 
        // 記得用super調(diào)用父類的構造方法! 
        this.grade = grade; 
    } 
    myGrade() {
    alert('I am at grade ' + this.grade);
    }
}

注意PrimaryStudent的定義也是class關鍵字實現(xiàn)的,而extends則表示原型鏈對象來自Student。子類的構造函數(shù)可能會與父類不太相同,例如,PrimaryStudent需要name和grade兩個參數(shù),并且需要通過super(name)來調(diào)用父類的構造函數(shù),否則父類的name屬性無法正常初始化。
PrimaryStudent已經(jīng)自動獲得了父類Student的hello方法,我們又在子類中定義了新的myGrade方法。
ES6引入的class和原有的JavaScript原型繼承有什么區(qū)別呢?實際上它們沒有任何區(qū)別,class的作用就是讓JavaScript引擎去實現(xiàn)原來需要我們自己編寫的原型鏈代碼。簡而言之,用class的好處就是極大地簡化了原型鏈代碼。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

  • 三,字符串擴展 3.1 Unicode表示法 ES6 做出了改進,只要將碼點放入大括號,就能正確解讀該字符。有了這...
    eastbaby閱讀 1,670評論 0 8
  • 本文為阮一峰大神的《ECMAScript 6 入門》的個人版提純! babel babel負責將JS高級語法轉(zhuǎn)義,...
    Devildi已被占用閱讀 2,131評論 0 4
  • 一、let 和 constlet:變量聲明, const:只讀常量聲明(聲明的時候賦值)。 let 與 var 的...
    dadage456閱讀 828評論 0 0
  • 孩子雖然因你而來,但是并不屬于你。今天早晨被《游戲力》第二章帶讀末尾這樣一句近乎殘酷的話觸動,內(nèi)心激起千層浪! 孩...
    喀秋莎寶閱讀 310評論 0 0
  • 過了兩天(真的是兩天)“房奴”的生活,晚上掙扎了下把剛到手的工資轉(zhuǎn)到房貸里,夜里醒了還是轉(zhuǎn)了回來。 感受不太好。 ...
    起噫步走閱讀 337評論 0 0

友情鏈接更多精彩內(nèi)容