콜백 함수 내부의
this
가 메소드를 호출한 객체를 가리키게 하려면 아래의 3가지 방법이 있다.
- 콜백함수의 this는 기본적으로
window(전역객체)
binding이다.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
var that = this; // ㅁthis: Prefixer 생성자 함수의 인스턴스
return arr.map(function (x) {
return that.prefix + ' ' + x;
});
};
var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
//생성자함수속this는 인스턴스에바인딩, 이것을 that할당으로 회피
//that은 이제 콜백함수 내부에서도 인스턴스이다.
(콜백함수내부 this는 window에 바인딩됨)
function Prefixer(prefix) {
this.prefix = prefix;
} //생성자함수 this는 생성자함수가 생성한 '인스턴스' (여기서는 pre객체)
Prefixer.prototype.prefixArray = function (arr) {
return arr.map(function (x) {
return this.prefix + ' ' + x; //콜백의 this는 원래 window지만 map 2nd param으로 따로 지정해줌.
}, this); // this: Prefixer 생성자 함수의 인스턴스 //map scope속 this가 아니라 prefixArray scope속 this = 메서드호출객체
};
var pre = new Prefixer('Hi'); / pre.prefix === Hi
console.log(pre.prefixArray(['Lee', 'Kim']));
//1.map의 2nd파라미터 this는 '메서드속 this는 메서드호출객체에 바인딩된다.'의 속성을 따라
//this === arr
//2.console.log(pre.prefixArray(['Lee', 'Kim'])); //
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
return arr.map(function (x) {
return this.prefix + ' ' + x;
}.bind(this)); // this: Prefixer 생성자 함수의 인스턴스
};
/*bind메서드의 인자로 들어가는 this는 prefixArray메서드의 스코프속에 있으므로
이 this는 메서드호출객체인 Prefixer에 바인딩, map의 콜백의
this는 Prefixer(prefixArray메서드호출객체)가 된다.*/
var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));
고차 함수
는 외부 상태 변경이나 가변(mutable) 데이터를 피하고 불변성(Immutability)을 지향하는함수형 프로그래밍
에
기반을 두고 있다. 함수형 프로그래밍은 순수 함수(Pure function)와 보조 함수의 조합을 통해 로직 내에 존재하는
조건문과 반복문을 제거하여 복잡성을 해결하고 & 변수의 사용을 억제하여
상태 변경을 피하려는 프로그래밍 패러다임이다.
조건문이나 반복문은 로직의 흐름을 이해하기 어렵게 하여 가독성을 해치고,
변수의 값은 누군가에 의해 언제든지 변경될 수 있어 오류 발생의 근본적 원인이 될 수 있기 때문이다.
(*고차함수: 값으로 취급하여 파라미터나,반환값으로 이용가능한 함수)
1.forEach
:요소순회 -> 콜백실행2.map
: 요소순회 -> 콜백리턴값으로 새로운배열 리턴3.filter
: 요소순회 -> 콜백리턴이 true인 요소만 모아 새로운 배열로 리턴4.reduce
: 요소순회 -> '이전의' 콜백실행 리턴값을 다시 콜백에 전달(하여 그결과를 다시반환.
// reduce는 acc(누산기),cur(현재값), idx(현재인덱스), src(원본배열:self)를 인자로 받는다.
// acc에 initialValue제공시 acc===초기값, cur===arr[0]
// acc에 initialValue 미제공시 acc===arr[0], cur===arr[1]공통점:
1. 메서드를 호출한 배열의 요소가 콜백을 순회,
2. (item,index) 다음으로 콜백에 전달하는 (this)는 원본 배열을 수정할 수 있다.
[추후 추가예정]
sort(오름차순정렬)
: 유니코드포인트에 순서로 정렬, sort에 넣어주는 비교함수(콜백)으로 정렬순서를 명확히한다
숫자비교callback: [(a,b) => a-b : a반환(a<b이면)]
문자열비교callback: [(a,b) => a[key] > b[key] ? 1 : (a[key] < b[key] ? -1 : 0) ; ]
cf)arr.reverse()
내림차순 정렬(유니코드포인트 기준)some
every
find
findIndex
: 배열을 순회, 각 요소에 대해 인자로 주어진 콜백을 실행, 반환값은
'undefined'
=>단순히 요소가 순회하며 콜백을 실행함에 의의가 있음.
// forEach 메소드는 원본 배열(this)을 변경하지 않는다.
하지만 콜백 함수는 원본 배열(this)을 변경할 수는 있다.
// 원본 배열을 직접 변경하려면 콜백 함수의 3번째 인자(this)를 사용한다.
: 배열요소가 콜백에전달되어, 콜백의 리턴값으로 새로운배열을 만듦.
function Prefixer(prefix) {
this.prefix = prefix;
}
Prefixer.prototype.prefixArray = function (arr) {
// 콜백함수의 인자로 배열 요소의 값, 요소 인덱스, map 메소드를 호출한 배열, 즉 this를 전달할 수 있다.
return arr.map(function (x) {
// x는 배열 요소의 값이다.
return this.prefix + x; // 2번째 인자 this를 전달하지 않으면 this === window
}, this);
};
const pre = new Prefixer('-webkit-');
const preArr = pre.prefixArray(['linear-gradient', 'border-radius']);
console.log(preArr);
// [ '-webkit-linear-gradient', '-webkit-border-radius' ]
[해설]
1. Prefixer생성자함수로 pre라는 인스턴스 생성
2. pre.prefixArray( ['linear-gradient','border-radius']);
인스턴스는 프로토타입메서드 호출가능,
3.map메서드 속 콜백의 this는 메서드호출객체(인스턴스=pre)를 가리킨다.
따라서 map은 호출배열의 아이템을 콜백으로 넘겨 콜백반환값으로 새로운 배열을 만드므로,
console.log(preArr); // [ '-webkit-linear-gradient', '-webkit-border-radius' ]이다.
4. map메서드의 2번째 인자로 this를 넘기면 this에는 메서드호출객체가 할당된다. (this ===pre)
//this를넘겨주지 않으면 this는 전역객체window에 자동 바인딩되므로 주의해야한다.
//꼭 this를 2nd parameter로 넘겨준다.
(요소순회 -> 콜백 return true인 아이템만 추출한 새로운 배열을 반환한다.)
//콜백에는 기본적으로 item,index,self 전달이 가능함.
// filter메소드는 if문을 대체가능하다.
const result = [1, 2, 3, 4, 5].filter(function (item, index, self) {
console.log(`[${index}] = ${item}`);
return item % 2; // 홀수만을 필터링한다 (1은 true로 평가된다)
});
console.log(result); // [ 1, 3, 5 ]
// acc에 initialValue(2nd param)있으면,
acc===initV cur===arr[0](첫 번째요소)
// acc에 initialValue없으면,
acc===arr[0], cur===arr[1](두 번째요소)
previousValue: 이전 콜백의 반환값
currentValue : 배열 요소의 값
currentIndex : 인덱스
array : 메소드를 호출한 배열, 즉 this
const arr = [1, 2, 3, 4, 5];
// 합산
const sum = arr.reduce(function (previousValue, currentValue, currentIndex, self) {
console.log(previousValue + '+' + currentValue + '=' + (previousValue + currentValue));
return previousValue + currentValue; // 결과는 다음 콜백의 첫번째 인자로 전달된다
});
console.log(sum); // 15: 1~5까지의 합
/*
1: 1+2=3
2: 3+3=6
3: 6+4=10
4: 10+5=15
15
*/
// 최대값 취득
const max = arr.reduce(function (pre, cur) {
return pre > cur ? pre : cur; (pre>cur 이면 pre 리턴, pre<cur이면 cur리턴 // max값 리턴)
});
console.log(max); // 5: 최대값
const sum = [1, 2, 3, 4, 5].reduce(function (pre, cur) {
return pre + cur;
}, 5);
// pre.1st = 5 , cur.1st =1 -> pre.2nd =5+1=6 cur.2nd = 2 -> pre.3rd=6+2=8 cur.3rd=3 ....
console.log(sum); // 20
// 5 + 1 => 6 + 2 => 8 + 3 => 11 + 4 => 15 + 5
객체로 이루어진 배열에 들어 있는 값을 합산하기 위해서는 반드시
초기값을 주어 각 항목(item)이 여러분의 함수를 거치도록 해야 합니다.
(item이 객체인 배열은 반드시 초깃값 할당 필요)
const products = [
{ id: 1, price: 100 },
{ id: 2, price: 200 },
{ id: 3, price: 300 }
];
// 프로퍼티 값을 합산
const priceSum = products.reduce(function (pre, cur) {
console.log(pre.price, cur.price);
// 숫자값이 두번째 콜백 함수 호출의 인수로 전달된다. 이때 pre.price는 undefined이다.
return pre.price + cur.price;
});
console.log(priceSum); // NaN
해당 item그대로 반환
[{x:2}].reduce(callback) // {x:2}
// 초기값을 전달하면 에러를 회피할 수 있다.(reduce호출시에는 언제나 초기값을 전달하는 것이 보다 안전하다)
const sum = [].reduce(function (pre, cur) {
console.log(pre, cur);
return pre + cur;
}, 0);
console.log(sum); // 0