ES6經常使用必備知識

ES6必備知識

1.變量聲明const和let

在ES6以前,咱們都是用var關鍵字聲明變量。不管聲明在何處,都會被視爲聲明在函數的最頂部(不在函數內即在全局做用域的最頂部)。這就是函數變量提高例如:javascript

  function aa() {
    if(bool) {
        var test = 'hello man'
    } else {
        console.log(test)
    }
  }

 

以上的代碼其實是:前端

 function aa() {
    var test // 變量提高
    if(bool) {
        test = 'hello man'
    } else {
        //此處訪問test 值爲undefined
        console.log(test)
    }
    //此處訪問test 值爲undefined
  }

 

因此不用關心bool是否爲true or false。實際上,不管如何test都會被建立聲明。java

接下來ES6主角登場:
咱們一般用letconst來聲明,let表示變量const表示常量letconst都是塊級做用域。怎麼理解這個塊級做用域?es6

  • 在一個函數內部
  • 在一個代碼塊內部

說白了 {}大括號內的代碼塊即爲letconst的做用域。面試

看如下代碼:編程

 function aa() {
    if(bool) {
       let test = 'hello man'
    } else {
        //test 在此處訪問不到
        console.log(test)
    }
  }
 
 

let的做用域是在它所在當前代碼塊,但不會被提高到當前函數的最頂部。json

再來講說const
const 聲明的變量都會被認爲是常量,意思就是它的值被設置完成後就不能再修改了。api

 const name = 'lux'
 name = 'joe' //再次賦值此時會報錯

 

還有,若是const的是一個對象,對象所包含的值是能夠被修改的。抽象一點兒說,就是對象所指向的地址沒有變就行。數組

  const student = { name: 'cc' }
    // 沒毛病
    student.name = 'yy'
    // 若是這樣子就會報錯了
    student  = { name: 'yy' }

 

說一道面試題promise

 var funcs = []
 for (var i = 0; i < 10; i++) {
    funcs.push(function() { console.log(i) })
 }
 funcs.forEach(function(func) {
     func()
 })

 

這樣的面試題是你們常見,不少同窗一看就知道輸出 10 十次
可是若是咱們想依次輸出0到9呢?
有兩種解決方法。直接看一下代碼。

 // ES5告訴咱們能夠利用閉包解決這個問題
    var funcs = []
    for (var i = 0; i < 10; i++) {
        funcs.push(
          (function(value) {
            return function() {
                console.log(value)
            }
        })(i)
      )
    }
    funcs.forEach(function(func) {
        func()
    })

 

 // 再來看看es6怎麼處理的
    const funcs = []
    for (let i = 0; i < 10; i++) {
        funcs.push(function() {
            console.log(i)
        })
    }
    funcs.forEach(func => func())

 

達到相同的效果,es6簡潔的解決方案是否是更讓你心動!!!

2.模板字符串

es6模板字符簡直是開發者的福音啊,解決了ES5在字符串功能上的痛點。

第一個用途,基本的字符串格式化。將表達式嵌入字符串中進行拼接。用${}來界定。

 //ES5 
    var name = 'lux'
    console.log('hello' + name)
    //es6
    const name = 'lux'
    console.log(`hello ${name}`) //hello lux

 

第二個用途,在ES5時咱們經過反斜槓(\)來作多行字符串或者字符串一行行拼接。ES6反引號(``)直接搞定。

 // ES5
    var msg = "Hi \
    man!
    "
    // ES6
    const template = `<div>
        <span>hello world</span>
    </div>`

 

對於字符串ES6固然也提供了不少厲害也頗有意思的方法😊 說幾個經常使用的。

 // 1.includes:判斷是否包含而後直接返回布爾值
    const str = 'hahay'
    console.log(str.includes('y')) // true

    // 2.repeat: 獲取字符串重複n次
    const str = 'he'
    console.log(str.repeat(3)) // 'hehehe'
    //若是你帶入小數, Math.floor(num) 來處理
    // s.repeat(3.1) 或者 s.repeat(3.9) 都當作成 s.repeat(3) 來處理

    // 3. startsWith 和 endsWith 判斷是否以 給定文本 開始或者結束
    const str =  'hello world!'
    console.log(str.startsWith('hello')) // true
    console.log(str.endsWith('!')) // true

 

3.函數

函數默認參數

在ES5咱們給函數定義參數默認值是怎麼樣?

 function action(num) {
        num = num || 200
        //當傳入num時,num爲傳入的值
        //當沒傳入參數時,num即有了默認值200
        return num
    }

 

但細心觀察的同窗們確定會發現,num傳入爲0的時候就是false,可是咱們實際的需求就是要拿到num = 0,此時num = 200 明顯與咱們的實際想要的效果明顯不同

ES6爲參數提供了默認值。在定義函數時便初始化了這個參數,以便在參數沒有被傳遞進去時使用。

function action(num = 200) {
        console.log(num)
    }
    action(0) // 0
    action() //200
    action(300) //300

   

箭頭函數

ES6頗有意思的一部分就是函數的快捷寫法。也就是箭頭函數。

箭頭函數最直觀的三個特色。

  • 不須要 function 關鍵字來建立函數
  • 省略 return 關鍵字
  • 繼承當前上下文的 this 關鍵字
//例如:
[1,2,3].map(x => x + 1)
    
//等同於:
 [1,2,3].map((function(x){
     return x + 1
 }).bind(this))

 

說個小細節。

當你的函數有且僅有一個參數的時候,是能夠省略掉括號的。當你函數返回有且僅有一個表達式的時候能夠省略{} 和 return;例如:

 var people = name => 'hello' + name
    //參數name就沒有括號

 

做爲參考

 var people = (name, age) => {
        const fullName = 'hello' + name
        return fullName
    } 
    //若是缺乏()或者{}就會報錯

 

要不整一道筆試題?哈哈哈哈哈哈哈哈。我無論我先上代碼了

    // 請使用ES6重構如下代碼
    
    var calculate = function(x, y, z) {
      if (typeof x != 'number') { x = 0 }
      if (typeof y != 'number') { y = 6 }

      var dwt = x % y
      var result

      if (dwt == z) { result = true }
      if (dwt != z) { result = false }
      
      return result
    }
    const calculate = (x, y, z) => {
      x = typeof x !== 'number' ? 0 : x
      y = typeof y !== 'number' ? 6 : y
      return x % y === z
    }

 

4.拓展的對象功能

對象初始化簡寫

ES5咱們對於對象都是以鍵值對的形式書寫,是有可能出現鍵值對重名的。例如:

 function people(name, age) {
        return {
            name: name,
            age: age
        };
    }

 

鍵值對重名,ES6能夠簡寫以下:

 function people(name, age) {
        return {
            name,
            age
        };
    }

 

ES6 一樣改進了爲對象字面量方法賦值的語法。ES5爲對象添加方法:

const people = {
        name: 'lux',
        getName: function() {
            console.log(this.name)
        }
    }

 

ES6經過省略冒號與 function 關鍵字,將這個語法變得更簡潔

 const people = {
        name: 'lux',
        getName () {
            console.log(this.name)
        }
    }

 

ES6 對象提供了 Object.assign()這個方法來實現淺複製。
Object.assign() 能夠把任意多個源對象自身可枚舉的屬性拷貝給目標對象,而後返回目標對象。第一參數即爲目標對象。在實際項目中,咱們爲了避免改變源對象。通常會把目標對象傳爲{}

   const objA = { name: 'cc', age: 18 }
    const objB = { address: 'beijing' }
    const objC = {} // 這個爲目標對象
    const obj = Object.assign(objC, objA, objB)

    // 咱們將 objA objB objC obj 分別輸出看看
    console.log(objA)   // { name: 'cc', age: 18 }
    console.log(objB) // { address: 'beijing' }
    console.log(objC) // { name: 'cc', age: 18, address: 'beijing' }
    console.log(obj) // { name: 'cc', age: 18, address: 'beijing' }

    // 是的,目標對象ObjC的值被改變了。
    // so,若是objC也是你的一個源對象的話。請在objC前面填在一個目標對象{}
    Object.assign({}, objC, objA, objB)

 

5.更方便的數據訪問--解構

數組和對象是JS中最經常使用也是最重要表示形式。爲了簡化提取信息,ES6新增了解構,這是將一個數據結構分解爲更小的部分的過程

ES5咱們提取對象中的信息形式以下:

 const people = {
        name: 'lux',
        age: 20
    }
    const name = people.name
    const age = people.age
    console.log(name + ' --- ' + age)

 

是否是以爲很熟悉,沒錯,在ES6以前咱們就是這樣獲取對象信息的,一個一個獲取。如今,解構能讓咱們從對象或者數組裏取出數據存爲變量,例如

 //對象
    const people = {
        name: 'lux',
        age: 20
    }
    const { name, age } = people
    console.log(`${name} --- ${age}`)
    //數組
    const color = ['red', 'blue']
    const [first, second] = color
    console.log(first) //'red'
    console.log(second) //'blue'

 

要不來點兒面試題,看看本身的掌握狀況?

   // 請使用 ES6 重構一下代碼

    // 第一題
    var jsonParse = require('body-parser').jsonParse

    // 第二題
    var body = request.body
    var username = body.username
    var password = body.password

    // 1.
    import { jsonParse } from 'body-parser'
    // 2. 
    const { body, body: { username, password } } = request

 

6.Spread Operator 展開運算符

ES6中另一個好玩的特性就是Spread Operator 也是三個點兒...接下來就展現一下它的用途。

組裝對象或者數組

    //數組
    const color = ['red', 'yellow']
    const colorful = [...color, 'green', 'pink']
    console.log(colorful) //[red, yellow, green, pink]
    
    //對象
    const alp = { fist: 'a', second: 'b'}
    const alphabets = { ...alp, third: 'c' }
    console.log(alphabets) //{ "fist": "a", "second": "b", "third": "c"}

 

有時候咱們想獲取數組或者對象除了前幾項或者除了某幾項的其餘項

    //數組
    const number = [1,2,3,4,5]
    const [first, ...rest] = number
    console.log(rest) //2,3,4,5
    //對象
    const user = {
        username: 'lux',
        gender: 'female',
        age: 19,
        address: 'peking'
    }
    const { username, ...rest } = user
    console.log(rest) //{"address": "peking", "age": 19, "gender": "female"}

 

對於 Object 而言,還能夠用於組合成新的 Object 。(ES2017 stage-2 proposal) 固然若是有重複的屬性名,右邊覆蓋左邊

  const first = {
        a: 1,
        b: 2,
        c: 6,
    }
    const second = {
        c: 3,
        d: 4
    }
    const total = { ...first, ...second }
    console.log(total) // { a: 1, b: 2, c: 3, d: 4 }

 

7.import 和 export

import導入模塊、export導出模塊

//所有導入
import people from './example'

//有一種特殊狀況,即容許你將整個模塊看成單一對象進行導入
//該模塊的全部導出都會做爲對象的屬性存在
import * as example from "./example.js"
console.log(example.name)
console.log(example.age)
console.log(example.getName())

//導入部分
import {name, age} from './example'

// 導出默認, 有且只有一個默認
export default App

// 部分導出
export class App extend Component {};

 

之前有人問我,導入的時候有沒有大括號的區別是什麼。下面是我在工做中的總結:

1.當用export default people導出時,就用 import people 導入(不帶大括號)

2.一個文件裏,有且只能有一個export default。但能夠有多個export。

3.當用export name 時,就用import { name }導入(記得帶上大括號)

4.當一個文件裏,既有一個export default people, 又有多個export name 或者 export age時,導入就用 import people, { name, age } 

5.當一個文件裏出現n多個 export 導出不少模塊,導入時除了一個一個導入,也能夠用import * as example

  

8. Promise

在promise以前代碼過多的回調或者嵌套,可讀性差、耦合度高、擴展性低。經過Promise機制,扁平化的代碼機構,大大提升了代碼可讀性;用同步編程的方式來編寫異步代碼,保存線性的代碼邏輯,極大的下降了代碼耦合性而提升了程序的可擴展性。

說白了就是用同步的方式去寫異步代碼。

發起異步請求

 fetch('/api/todos')
      .then(res => res.json())
      .then(data => ({ data }))
      .catch(err => ({ err }));

 

今天看到一篇關於面試題的頗有意思。

    setTimeout(function() {
      console.log(1)
    }, 0);
    new Promise(function executor(resolve) {
      console.log(2);
      for( var i=0 ; i<10000 ; i++ ) {
        i == 9999 && resolve();
      }
      console.log(3);
    }).then(function() {
      console.log(4);
    });
    console.log(5);

//「2 3 5 4 1」

 

Excuse me?這個前端面試在搞事!

固然以上promise的知識點,這個只是冰山一角。須要更多地去學習瞭解一下。

9.Generators

生成器( generator)是能返回一個迭代器的函數。生成器函數也是一種函數,最直觀的表現就是比普通的function多了個星號*,在其函數體內可使用yield關鍵字,有意思的是函數會在每一個yield後暫停。

這裏生活中有一個比較形象的例子。我們到銀行辦理業務時候都得向大廳的機器取一張排隊號。你拿到你的排隊號,機器並不會自動爲你再出下一張票。也就是說取票機「暫停」住了,直到下一我的再次喚起纔會繼續吐票。

OK。說說迭代器。當你調用一個generator時,它將返回一個迭代器對象。這個迭代器對象擁有一個叫作next的方法來幫助你重啓generator函數並獲得下一個值。next方法不只返回值,它返回的對象具備兩個屬性:done和value。value是你得到的值,done用來代表你的generator是否已經中止提供值。繼續用剛剛取票的例子,每張排隊號就是這裏的value,打印票的紙是否用完就這是這裏的done。

// 生成器
    function *createIterator() {
        yield 1;
        yield 2;
        yield 3;
    }
    
    // 生成器能像正規函數那樣被調用,但會返回一個迭代器
    let iterator = createIterator();
    
    console.log(iterator.next().value); // 1
    console.log(iterator.next().value); // 2
    console.log(iterator.next().value); // 3

 

那生成器和迭代器又有什麼用處呢?

圍繞着生成器的許多興奮點都與異步編程直接相關。異步調用對於咱們來講是很困難的事,咱們的函數並不會等待異步調用完再執行,你可能會想到用回調函數,(固然還有其餘方案好比Promise好比Async/await)。

生成器可讓咱們的代碼進行等待。就不用嵌套的回調函數。使用generator能夠確保當異步調用在咱們的generator函數運行一下行代碼以前完成時暫停函數的執行。

那麼問題來了,我們也不能手動一直調用next()方法,你須要一個可以調用生成器並啓動迭代器的方法。就像這樣子的

 function run(taskDef) { //taskDef即一個生成器函數

        // 建立迭代器,讓它在別處可用
        let task = taskDef();

        // 啓動任務
        let result = task.next();
    
        // 遞歸使用函數來保持對 next() 的調用
        function step() {
    
            // 若是還有更多要作的
            if (!result.done) {
                result = task.next();
                step();
            }
        }
    
        // 開始處理過程
        step();
    
    }

 

生成器與迭代器最有趣、最使人激動的方面,或許就是可建立外觀清晰的異步操做代碼。你沒必要處處使用回調函數,而是能夠創建貌似同步的代碼,但實際上卻使用 yield 來等待異步操做結束。

總結

ES6新特性遠不止於此,但對於咱們平常的開發來講。這算不上所有,可是能算得上是高頻使用了。固然還有頗有好玩有意思的特性。好比一些數組的新方法、class...等等。包括用set處理數組去重問題等等。我和個人小夥伴們都驚呆了!

有什麼問題,歡迎不吝賜教!

做者:陳嘻嘻啊連接:https://www.jianshu.com/p/287e0bb867ae來源:簡書簡書著做權歸做者全部,任何形式的轉載都請聯繫做者得到受權並註明出處。

相關文章
相關標籤/搜索