JS 紀錄8 - function 3 (Arror function)

JavaScript Arror function

Arrow function

有什麼特性

  • 箭頭函式本身沒有 this
    • 意思就是說,箭頭函數不會創造一個新的 this,而是從它的外圍作用域一併抓起
  • 箭頭函式 this 代表的是 function 執行時所屬的物件(function在外,function爸爸)
  • 在箭頭函數中,this 綁定定義時的作用域,而不是指向運行時所在的作用域
  • 只能用在匿名函式
  • 隱式回傳(內建return)
  • 箭頭函數使得 this 從 “動態” 變成 “靜態”

作用域

  • 箭頭函数的 this 綁定定義時所在的作用域(即 Timer 函數)
  • 普通函数的 this 指向運行時所在的作用域(即 window)
1
2
3
4
5
6
7
8
9
10
11
12
13
function Timer() {
this.s1 = 0;
this.s2 = 0;
// 箭頭函数
setInterval(() => this.s1++, 1000);
// 普通函数
setInterval(function () {
this.s2++;
}, 1000);
}
var timer = new Timer();
setTimeout(() => console.log('s1: ', timer.s1),3100); // 3 this = Timer
setTimeout(() => console.log('s2: ', timer.s2),3100); // 0 this = window

判斷

  • ( ) => 表示該變量存儲一個函數
1
function() === ()=>
  • 只有一個參數時,括號才能不加
1
2
(singleParam) => { statements }
singleParam => { statements }
  • 若無參數,就一定要加括號
1
() => { statements }
  • 簡化 callback function
1
[1,2,3].map(x => x * 2)
  • 沒用 花括號 ({}) 也只能在一行的語句的時候使用,會自動加 return
  • 使用 花括號 ({}) 可以加入多行的語句,return 不會自動加,需要自己加上否則得到 undefined
1
2
3
4
5
6
7
let funcA = x => x + 1
let funcB = x => { x + 1 }
let funC(a,b) => {return a+b}

funcA(1) // 2
funcB(1) // undefined
funC(1,2) // 3

可使用的情況

  • 用 箭頭函式 取出內層(return) myString 參數 (一般要用 隱式綁定)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
var myString = 'hello global',
obj = {};

function outer() {
this.myString = 'hello outer';
return () => { // closure
console.log(this) // 'hello outer' 未指定
this.myString = 'hello arrow function'; // 指定 在箭頭函數裡
console.log(this) // 'hello arrow function'
}
}

var arrowFn = outer.call(obj); // outer 綁定外層 this = obj 才可取出內層
console.log(obj.myString); // "hello outer"
arrowFn();

console.log(obj.myString); // "hello arrow function"
console.log(window.myString); // "hello global"

/*----------------------------------
// 隱式綁定 取出
var myString = 'hello global',
obj = {};

function outer() {
let self = this
self.myString = 'hello outer';
return (function(){
console.log(self) //'hello outer'
self.myString = 'hello arrow function';
console.log(self) // 'hello arrow function'
})
}

var arrowFn = outer.call(obj); // outer 綁定外層 self = obj 才可取出內層
console.log(obj.myString); // "hello outer"
arrowFn();

console.log(obj.myString); // "hello arrow function"
console.log(window.myString); // "hello global"

不可使用的情況

  • 函式物件中的call、apply、bind,無法“覆蓋”箭頭函式中的 this 值(本身沒有 this)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(function() {
return [
(() => this.x).bind({ x: 'inner' })()
];
}).call({ x: 'outer' }); // outer

/*----------------------------------
let family = {
ming: 'JJ'
}
const func = () => {
console.log(this);
}
const func2 = function () {
console.log(this);
}
func.call(family); // 箭頭函式 this 是 window
func2.call(family); // 一般函示 this 是 window
  • 箭頭函式無法用於建構式 constructor,使用 new 會產生錯誤
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MyCat(name) {
this.catName = name
console.log(this) // window
}

MyCat.prototype.sayCatName = () => {
return this.catName
}
MyCat.prototype.sayCatName2 = function(){
return this.catName
}

const cat = new MyCat('Mew')
console.log(cat.sayCatName()) // undefined
console.log(cat.sayCatName2()) // "Mew"
  • 箭頭函式沒有一般函式有的 arguments,如果要可以用 spread 代替
1
2
3
4
5
6
function foo(...a) {
setTimeout(() => {
console.log('args:', a);
}, 100);
}
foo(2, 4, 6, 8) // args: (4) [2, 4, 6, 8]
  • this 如果是用在監聽 DOM 上一樣會指向 window,所以無法使用在此情境
1
2
3
4
5
6
7
8
var elements = document.getElementsByTagName('div');
var changeDOM = () => {
console.log(this); // 指向 window Object
this.style.border = '1px solid red'. // 錯誤
}
for (var i = 0; i < elements.length; i++) {
elements[i].addEventListener('click', changeDOM, false);
}
  • 在物件的 prototype 屬性中定義的方法 this 會指向 window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function MyCat(name) {
this.catName = name
console.log(this) // window
}

MyCat.prototype.sayCatName = () => {
return this.catName
}
MyCat.prototype.sayCatName2 = function(){
return this.catName
}

const cat = new MyCat('Mew')
console.log(cat.sayCatName()) // undefined
console.log(cat.sayCatName2()) // "Mew"
  • 箭頭函式不能當作 generators 函數使用,使用 yield 會產生錯誤
  • 箭頭函式用於解決一般的 this 問題是可以,但並不適用於全部的情況
0%