###### tags: `JavaScript` `箭頭函式` `學習` {%hackmd BJrTq20hE %} # 甚麼是箭頭函式與箭頭函式this的指向差異 ## 1-1甚麼是箭頭函式? 箭頭函式是一種新的函是寫法,與一般函式的寫法不同,有可以縮寫的優點。 範例如下 ### 1-1-1一般函式 ```javascript= let arr = [1,2,3,4,5]; let newarr = arr.map(function(item){ return item*2 }); console.log(newarr);//[2,4,6,8,10] ``` ### 1-1-2箭頭函式 ```javascript= let arr = [1,2,3,4,5]; let newarr = arr.map((item)=>{ return item*2 }); console.log(newarr);//[2,4,6,8,10] ``` 可以發現把function移除,然後在()後加上=> ## 2-1箭頭函式的縮寫 如果函式的參數只有一個,參數()也可以省略。 加入沒有參數的話()或兩個含以上參數存在的話則()不可省略。 ```javascript= let arr = [1,2,3,4,5]; let newarr = arr.map(item=>{ return item*2 }); console.log(newarr);//[2,4,6,8,10] ``` ### 2-2箭頭函式的縮寫2 函式需要return值的時候{}也可以省略,但是要注意原本{}的內容要寫在同一行。 ```javascript= let arr = [1,2,3,4,5]; let newarr = arr.map(item=>item*2); console.log(newarr);//[2,4,6,8,10] ``` ## 3-1箭頭函式沒有自己的this 原函式寫法this的指向 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName (){ console.log(this.name+' this指向obj'); // 因為在callback function 內的this都指向全域。 setTimeout(function(){ console.log(this.name+' this指向window') }) }, } obj.callMyName();//Jack this指向obj window this指向window ``` 從上面的例子可以看到callMyName()是從obj內調用的所以this指向obj,而setTimeout這個callback function是一種simple call 可以想成setTimeout()是放在window裡所以setTimeout()的this會指向window。 ### 3-1-1 箭頭函式this的指向 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName (){ console.log(this.name+'1'); setTimeout(()=>{ console.log(this.name+'2') }) }, } obj.callMyName();//Jack1 Jack2 ``` 把setTimeout內的函是改寫為箭頭函式,因為箭頭函式沒有自己的this,所以在箭頭含式內的this會指向外層函式的作用域的this,外層函式為傳統函式所以this的指向與如何調用函是相關。 ### 3-1-3沒有外層函式的的箭頭函式的this指向全域 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName: ()=>{ console.log(this.name); }, } obj.callMyName();//window ``` 箭頭函式內的this會與外層函式的this指向相同,上面的範例中沒有外層函式,所以指向全域。 ### 3-1-4外層也是箭頭函式的this的指向全域 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName: ()=>{ console.log(this.name+'1'); setTimeout(()=>{ console.log(this.name+'2') }) }, } obj.callMyName();//window1 window2 ``` 因為setTimeout外層函數也是箭頭函式,所以this的指向看外層函式,又因為外層函式是箭頭函式且沒有更外層的函式所以所有的this都指向window。 ### 3-1-5確定this的指向-方法1 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName (){ let vm = this; setTimeout(function(){ console.log(vm.name) }) }, } obj.callMyName();//Jack ``` 在callback function同層宣告變數vm=this;改變this的指向 ### 3-1-5確定this的指向-方法2 ```javascript= var name ='window'; const obj = { name:'Jack', callMyName (){ setTimeout(()=>{ console.log(this.name) }) }, } obj.callMyName();//Jack ``` 使用箭頭函式沒有this,會與(外層函式)作用域的this指向相同的特性把setTimeout內的this指向obj。 ## 4-1 一般函式與箭頭函式其餘參數的差異 一般函式的其餘參數 ```javascript= function fn() { console.log(arguments) } fn(1, 2, 3, 4) //Arguments(4) [1, 2, 3, 4,] ``` 箭頭函式則是沒有其餘參數,會報錯。 ```javascript= const fn = () => { console.log(arguments) } fn(1, 2, 3, 4) // VM1730:2 Uncaught ReferenceError: arguments is not defined ``` ### 4-1-1 箭頭函式的其餘參數要怎麼寫? ```javascript= const fn = (par, ...pars) => { console.log(par) console.log('其餘參數',...pars) const value = Object.values(pars) console.log('取出其餘物件', value) } fn(1, 'a', 'b', 5, 6)// 1 '其餘參數' a b 5 6 // ['a', 'b', '5', '6'] ``` ## 5-1 箭頭函式與call()、apply()、bind()對於this的指向 原始函式 ```javascript= var name = '123' const obj = { name: 'Jack' } const fn1 = function(par1, par2) { console.log(this.name, par1, par2) } fn1.call(obj, 'May', 'John') // Jack May John ``` 箭頭函式 可以看到使用Call但試箭頭函式內的this是指向全域,原因是箭頭函式沒有外層函數,所以會指向全域。 ```javascript= var name = '123' const obj = { name: 'Jack' } const fn1 = (par1, par2) => { console.log(this.name, par1, par2) } fn1.call(obj, 'May', 'John') // 123 May John ``` 箭頭函式與一般函式放在一起看 ```javascript= var name = '123' const obj = { name: 'Jack', fn1: (par1, par2) => { console.log('fn1',this.name, par1, par2) }, fn2:function(par1, par2) { console.log('fn2',this.name, par1, par2) }, fn3:function(par1, par2) { setTimeout(()=>{ console.log('fn3',this.name, par1, par2) }) }, fn4:(par1, par2) => { setTimeout(()=>{ console.log('fn4',this.name, par1, par2) }) } } //雖然call有定義this指向但是在箭頭函式內的this的指向還是由外層函數的this指向為主,如果沒有外層函式則指向全域。 obj.fn1.call(obj, 'May', 'John') // 123 May John obj.fn2.call(obj, 'May', 'John') // Jack May John obj.fn3.call(obj, 'May', 'John') // Jack May John obj.fn4.call(obj, 'May', 'John') // 123 May John ``` [箭頭函式、call this的指向 範例](https://codepen.io/efzdamnp-the-lessful/pen/VwXQyvp?editors=0011) ## 6-1 箭頭函式沒有建構函式 簡單的來說箭頭函式沒辦法透過.prototype增加方法 一般函式 ```javascript= const List = function(name){ this.name = name } const List2 = (name)=> { this.name = name } console.log(List.prototype, List2.prototype) //{constructor: ƒ} undefined const list = new List('Jack') console.log(list) // List {name: 'Jack'} const list2 = new List2('Jack') // Uncaught TypeError: List2 is not a constructor ```