0%

JS核心-(64)-ES6 章節:箭頭函式-與傳統函式不同之處

前言

介紹箭頭函式跟傳統函式的差別


箭頭函式沒有 arguments 參數

之前在傳統函式有介紹到,參數的傳入有一個 arguments 參數會來承接所有傳入的參數,

並且使用類陣列(Array-liked)的方式記錄起來。

const nums = function () {
    console.log(arguments);
}

nums(1,2,3,4,6,7,8,500,10);

但箭頭函式則沒有這個參數,那麼當如果我們需要記錄傳進來的參數的時候,該怎麼辦呢?

const nums = () => {
    console.log(arguments);
}

nums(1,2,3,4,6,7,8,500,10);



這個時候就可以使用其餘參數運算子來解決這個問題,利用三個點 ... +自定義變數名稱 arg

像這樣 (...arg) ,就可以將參數的內容以陣列的方式記錄在變數上。

const nums = (...arg) => {
    console.log(arg);
}

nums(1,2,3,4,6,7,8,500,10);


This 綁定的差異

箭頭函式沒有自己的 This,怎麼說呢?

var myName = '全域';
var person = {
    myName: '小明',
    callName: function () {
        console.log('1', this.myName);

        setTimeout(function () {
            console.log('2', this.myName);
            console.log('3', this);
        }, 10);
    }
}

person.callName();

看完這樣的程式碼,我們可以知道 callName 這個函式中,this 的指向會是 person 這個物件。另外, setTimeout 因為傳入的是 callback function ,所以這裡面的作用域的 this 指向是全域的物件 window

結果很明顯會是:

那麼我們稍微改動一下程式碼,把 callback function 改成箭頭函式的寫法,看看 this 會怎麼指向。

var myName = '全域';
var person = {
    myName: '小明',
    callName: function () {
        console.log('1', this.myName);

        setTimeout(() => {
            console.log('2', this.myName);
            console.log('3', this);
        }, 10);
    }
}

person.callName();

可以看到, this 的指向變成了外層作用域的 person

那麼這個時候,再把 callName 的傳統函式也改成箭頭函式的寫法的話呢?

var myName = '全域';
var person = {
    myName: '小明',
    callName: () => {
        console.log('1', this.myName);

        setTimeout(() => {
            console.log('2', this.myName);
            console.log('3', this);
        }, 10);
    }
}

person.callName();

改成箭頭函式以後,this的指向就跑到全域的物件 window 身上。

而且不管埋幾層都一樣

var odin = '1';
var obj = {
    odin: '2',
    arrfn: () => {
        console.log('2',this, this.odin)
        setTimeout(() => {
            console.log('2-setTimeout',this, this.odin)
        }, 10);
    },
    obj: {
        odin: '3',
        arrfn: () => console.log('3',this, this.odin),
        obj: {
            odin: '4',
            arrfn: function () { console.log('4',this, this.odin)},
            obj: {
                odin: '5',
                arrfn: function () {
                    console.log('5',this, this.odin)
                    setTimeout(() => {
                        console.log('5-setTimeout',this, this.odin)
                    }, 10);
                },
            }
        }
    }
};

obj.arrfn();
obj.obj.arrfn();
obj.obj.obj.arrfn();
obj.obj.obj.obj.arrfn();

只是如果改成傳統函式的話,規則又會跟之前的一樣,在被呼叫的時候,以前一個的物件為 this 的指向。


This 不同,導致 DOM 的 This 指向也不同

const ele = document.querySelector('p');
ele.addEventListener('click', function () {
    console.log(this);
});

一般來說,這樣撰寫以後,點擊畫面上的 p 元素,this 會指向該 p 元素的 DOM

但如果用箭頭函式撰寫的話

const ele = document.querySelector('p');
ele.addEventListener('click', () => {
    console.log(this);
});

就會指向全域的物件 window 身上。


無法透過 call, apply, bind 重新給予 this 的指向

因為箭頭函式沒有自己的 this,所以就算使用 call, apply, bind 重新給予 this 的指向,也無法改變。

const family = {
    myName: '小明家'
};

const fn = (para1, para2) => {
    console.log(this, para1, para2);
};

fn.call(family, '小明', '杰倫');


不具有 prototype,故無法作為建構函式使用

const Fn = function (a) {
    this.a = a;
}

const ArrowFn = (a) => {
    this.a = a;
}

console.log('Fn', Fn.prototype);
console.log('ArrowFn', ArrowFn.prototype);

const instanceFn = new Fn('a');
const instanceArrowFn = new ArrowFn('a');