1. Arrow Function
var a = function() {
return new Date()
}
var a = () => {
return new Date()
}
위와 아래는 동일하다.
여기서 더 축약할 수 있음!
var a = () => new Date()
a라는 함수는,
어떤 것을 받을 건데,
걔가 => 뒤의 내용으로 될 거야.
함수내부의 내용이 반환값(return) 밖에 없으면,
중괄호와 return까지 없애서 그 자체가 return
이 되게 가능함.
var b = a => a * a;
인자가 하나인 경우엔 괄호
도 생략 가능.
var d = (a,b) => {
console.log(a * b)
}
return할 것이 없으면 더이상 축약하지 못함.
여기서 예외!
var e = function (x) {
return {
x: x
}
}
// 아래와 같이 축약 가능
var e = x => ({ x })
객체를 즉시 반환을 해야하는 경우에는,
return 생략했다고 { x: x} 이렇게 쓸 수 없음.
(arrow function의 스코프로 인식하기 때문)
객체임을 명시하기 위해서 괄호로 묶어줘야함
.
해석하자면,
함수 e에 들어온 x가,
x property를 key와 value로 하는 객체로 만들어져서 반환될 거야.
var f = function (a) {
return function (b) {
return a + b;
}
}
// 아래와 같이 변환 가능
var f = a => b => a + b;
var z = f(1)(2);
위 예제는 closer.
a를 받은 것을 실행한 결과를 가지고 다시 b로 보냄.
함수 f를 실행할 때 1을 넘겨 준것이 a에 들어가고,
다시 2를 넘겨준게 b에 들어간다.
1-1. 상세
-
1) (매개변수) => { 본문 }
-
2) 매개변수가 하나뿐인 경우 괄호 생략 가능
- 3) 매개변수가 없을 경우엔 괄호 필수
- (아예 안쓰겠다는 확신이 있다면 ` _ ` 도 가능)
-
4) 본문이
return [식 or 값]
뿐인 경우{ }
와return
키워드 생략 가능 -
5) 위 4) 에서 return할 값이
객체
인 경우엔 괄호 필수 - 6) 실행컨텍스트 생성시 ⭐️
this 바인딩
을하지 않음
⭐️
⭐️ 중요 ⭐️
1-2. arrow function의 this 바인딩
arrow 함수는,
기존 함수의 기능을 문법적으로 보기 편하게, 직관적으로 표시하게끔 만든 것만은 ❌
함수를 가볍게
가져가기 위해서!
- 기존의 경우
const obj = {
a () {
console.log(this) // - (1)
const b = function () {
console.log(this) // - (2)
}
b()
}
}
obj.a()
(1)의 this는 obj
메소드로 호출했기 때문에, 당연히 ` . `의 앞인 obj
(2)의 this는 window
함수라는 것 자체가 실행되는 순간
에 this를 바인딩
한다.
this를 찾는데, 바인딩할 this가 없으니까 자동으로 전역객체인 window
를 바인딩한 것.
- arrow function의 경우
const obj = {
a () {
console.log(this) // - (1)
const b = () => {
console.log(this) // - (2)
}
b()
}
}
obj.a()
(1)의 this는 obj
(2)의 this는 obj
arrow function은 실행되어서 실행 컨텍스트가 생성될 때,
this바인딩 자체를 하지 않는다.
b는 this를 들고있지 않으니, 외부 스코프의 this
를 그대로 가져와서 쓰는 것.
this 바인딩을 하지 않는 것은 또 뭐가 있었지?
block scope
!
block scope도 함수 scope와는 다르게 this 바인딩을 하지 않고 외부의 this를 가져옴.
🤷🏻♀️ : 그럼 arrow function이 block scope인 거야?
=> 답 : ❌
예제
const a = () => {
var x = 10;
}
a();
console.log(x);
- 1) arrow function ==
block scope
라면?
arrow function이 block scope라면,
var는 block scope의 영향을 받지 않고 외부 변수로 인식
하니까 x가 출력 될거야.
- 2) arrow function ==
함수 scope
라면?
arrow function이 함수 scope라면,
var로 선언한 변수는 함수 scope안에 갇혀서
밖에서는 x를 찾지 못할 거야.
=> 결과
=> arrow function이 block scope인 것이 ❌
arrow 함수는 기존 함수와 동일하게 함수 scope
임!
this 바인딩의 유무 | |
---|---|
한다 | 안한다 |
function scope | block scope |
function | arrow function |
arrow function는
함수 스코프
를 생성- 단, 실행 컨텍스트 생성시 this 바인딩❌
const obj = {
grades: [80, 90, 100],
getTotal: function () {
this.total = 0 // 여기서의 this는 obj
this.grades.forEach(function(v) {//여기도 obj
this.total += v
// 여기는 forEach가 돌려주는 콜백함수.
// 콜백함수 안에서 this는, 그냥 함수 실행이기 때문에 window
// 그래서 window.total의 v가 증가
})
}
}
obj.getTotal()
console.log(obj.total)
console.log(total) // NaN. 처음에 아무것도 없었으니,
// undefined + 80 + 90 + 100 이 됐으니 숫자가 아님
var total = 0;
const obj = {
grades: [80, 90, 100],
getTotal: function () {
this.total = 0;
this.grades.forEach(function(v) {
this.total += v;
})
}
}
obj.getTotal();
console.log(total) // 270
obj.total // 0
여기서 obj.total가 0이 찍히는 이유?
forEach 콜백함수 안에 this가 전달되지 않았기 때문.
- 1) 직접 this를 지정해주는 방법
(forEach argument의 뒤에는
this argument 인자
가 들어옴.)
var total = 0;
const obj = {
grades: [80, 90, 100],
getTotal: function () {
this.total = 0;
this.grades.forEach(function(v) {
this.total += v;
},this)
}
}
obj.getTotal();
obj.total // 270
- 2) arrow function을 사용하는 방법
var total = 0;
const obj = {
grades: [80, 90, 100],
getTotal: function () {
this.total = 0;
this.grades.forEach(function(v) {
this.total += v;
},this)
}
}
obj.getTotal();
obj.total // 270
this 바인딩을 하지 않는 arrow function을 써버리면 간단.
🙋♀️ : arrow function은 this 바인딩 안하니까 너무 좋은거구나!
❌ 좋지만은 않다.
1-2-1. 단점
- 1) this 변경 불가
const a = () => {
console.log(this)
}
a()
이때의 this는 window.
a.call( {} )
call의 첫번째 인자는 this니까, 새로운 this를 지정해줘도 ❌
콜백이 아닌 일반 함수였다면?
const c = function () {
console.log(this)
}
c()
이때의 this는 마찬가지로 window.
c.call( {} )
undefined 출력.
함수실행시에 this를 {} 인 채로 실행하라고 줬으니까!
그래서 this 바인딩한 상태에서 실행하는 것.
=> 그렇다고 arrow function에서의 call이 제 기능을 못하는 건 아님.
call 본연의 기능
첫번째 인자로 this인자를 넘겨주고, 뒤에 실행할 argument들(인자들)을 넘겨줌.
call 비교 예제
function sum (...arg) {
console.log(this);
return arg.reduce((p,c) => p + c);
}
sum(1,2,3,4,5);
sum.call({},1,2,3,4,5);
this 변경 O, call 전달 O
const sum2 = (...arg) => {
console.log(this);
return arg.reduce((p,c) => p + c);
}
sum2(1,2,3,4,5);
sum2.call({},1,2,3,4,5);
this 변경 X, call 전달 O
=> 결론
this 바인딩만 안될 뿐, call은 제역할을 한다
1-3. 생성자 함수
- 기존 함수
function sum (...arg) {
console.log(this);
return arg.reduce((p,c) => p + c);
}
console.dir(sum)
prototype이 존재 = 생성자함수
로 사용 가능
- arrow function
const sum2 = (...arg) => {
console.log(this);
return arg.reduce((p,c) => p + c);
}
console.dir(sum2)
prototype이 없음 = 생성자함수
로 사용 불가능
const b = new sum()
// sum { }
const c = new sum2()
//error! sum2 is not a constructor
concise method와 arrow function
- 공통점
- prototype 프로퍼티가 X => 생성자함수로 X
- arguments, callee => hidden. invoke해야만 값을 얻을 수 있다
- 차이점
- concise method
- method는 method로만. 함수로 사용불가
- arrow function
- method는 함수로만.(내부함수로써는 method로 가능)
const b = {
name: '하하',
bb () {
return this.name;
},
a: x => {
return this.name;
}
}
b.bb(); // '하하'
b.a(); // ''
여기서 b.a는 왜 아무것도 나오지 않을까?
b.a는 arrow function
이라 this를 바인딩하지 않기 때문.
근데 왜 빈문자열이 나오지?
=> window.name이 이미 있기 때문에.
window.name = '안뇽';
b.a(); // '안뇽'
b.a는 메소드로써의 기능❌, 함수로써의 기능
this가 객체를 가리키게 할 수 없다.
🤷🏻♀️ : 그럼 arrow 함수를 언제 써야 method로써의 의미가 있지??
메소드 안에서 같은 this를 가지고 써야할 때(내부함수로 쓸 때)
아래처럼
const b = {
name: '하하',
bb () {
const b = x => {
return this.name;
}
console.log(b());
},
}
b.bb(); // '하하'