1. 程式人生 > >ES6精解(2):箭頭函式

ES6精解(2):箭頭函式

基本用法

在ES6中允許使用 => 來定義函式,如下:

 var f = a => a;
    console.log(f(1)); //1

就等同於

 var f = function(a){
         return a;
    }
    console.log(f(1)); //1

從上面可以看出,在箭頭左側的是代表引數,若引數只有一個,()可以省略,箭頭右側的表示函式程式碼塊,若程式碼塊裡面是個返回值,則{}可以省略不寫

1.無引數情況

若箭頭函式不需要引數,則左側用()代替,如下:

  var f = () => {
      console.log("無引數情況");
   }
    f();//無引數情況

2.有引數情況

  var f = (a, b) => {
        return a+b;
   }
    console.log(f(1,2)); //3
 var f = a => a;
 console.log(f(1)); //1

如果箭頭函式有引數,則需要用()括起來,若只有一個引數,括號可以省略不寫

在這裡要注意一個情況,就是當箭頭函式直接返回一個物件的時候,如下:

    var f = () => {name:'liming', age:22}; //報錯
    console.log(f());

這樣寫肯定是報錯的,因為{}執行時變成程式碼塊,會去執行程式碼,所以要用一個()括起來才可以,如下:

var f = () => ({name:'liming', age:22}); 
console.log(f());

執行結果為:

{name: "liming", age: 22}

以上這個寫法才是正確的

箭頭函式注意點

1.this指向

 var a = '全域性變數a';
    var obj={
        a:'區域性變數a',
        fn1:function(){
            console.log(this.a);
        },
        fn2:()=>{
            console.log(this.a);
        }
    }
    obj.fn1();
    obj.fn2();

輸出結果為:

區域性變數a
全域性變數a

普通函式的this我們知道是指向最近的一個物件,而箭頭函式的this實際上是指向定義時的this,比如把上面程式碼改為:

 var obj={
        a:'區域性變數a',
        fn1:function(){
            console.log(this.a);
        },
        fn2:()=>{
            console.log(this.a);
        }
    }
    obj.fn1();
    obj.fn2();

輸出結果為:

區域性變數a
undefined

此時因為箭頭函式是指向全域性的,全域性沒有變數a則輸出undefined,這裡的fn1和fn2都是全域性函式,所以箭頭函式this指向的是定義時的全域性,而普通函式的this指向的是最近的一個物件

上面如果那個例子不太明白,可以再看下如下例子:

    this.a = '全域性a';
    function Timer() {
         this.a = 'timer中的a';
        // 普通函式
        setTimeout(function () {
            console.log('普通函式:', this.a);
        });

        // 箭頭函式
        setTimeout(() => {
            console.log('箭頭函式:',this.a);
    });
    }
   new Timer();

輸出結果為:

普通函式: 全域性a
箭頭函式: timer中的a

這裡普通函式會指向全域性是因為,距離普通函式最近的物件是setTimeOut,而setTimeOut是掛在全域性作用域中,所以普通函式指向全域性,箭頭函式指向的是定義時的物件,箭頭函式是在Timer中定義的,所以箭頭函式指向Timer

如果把以上程式碼改為如下:

 this.a = '全域性a';
    function Timer() {
         this.a = 'timer中的a';
        // 普通函式
        setTimeout(function () {
            console.log('普通函式:', this.a);
        });

        // 箭頭函式
        setTimeout(() => {
            console.log('箭頭函式:',this.a);
    });
    }
   Timer();

輸出結果:

普通函式: timer中的a
箭頭函式: timer中的a

這個是為什麼呢,因為如果是new Timer相當於是建構函式,構造了一個物件,如果是Timer()就相當於是呼叫函式Timer()這兩者還是有區別的,如果是呼叫函式Timer(),這個時候this的指向都是全域性,在區域性修改this.a會覆蓋全域性的this.a

通過以上,我們可以知道普通函式跟箭頭函式this指向的區別是:

普通函式: this指向最靠近的一個物件

箭頭函式: this指向定義時的物件,也就是說箭頭函式一旦定義完成,它的指向是固定的,沒法改變,它的指向是定義時所在的作用域,而不是執行時的作用域

2.不可以當做建構函式

箭頭函式不可以當做建構函式,也就是不可以new一個,否則會報錯,如下:

    var fn = ()=>{
        console.log("123");
    }
    new fn(); //Uncaught TypeError: fn is not a constructor

以上會報錯,因為箭頭函式本身沒有屬於自己的this,所以箭頭函式不可以當做建構函式,也因為箭頭函式沒有自己的this,所以call()、apply()、bind()這些方法去改變this的指向對箭頭函式也是無效的,如下:

  this.x = 'outer';
    (function() {
        console.log([
            (() => this.x).bind({ x: 'inner' })()
        ]);
    })();

輸出結果為:

["outer"]

把箭頭函式通過bind繫結可見無效,箭頭函式還是指向全域性

以上是個人總結,有什麼不足之處歡迎留言探討!