this는 실행 컨텍스트가 생성될 때 결정된다. 이것을 'bind한다'라고 한다.
함수명(); // 스스로 수행
객체.메서드명(); // 어떤 객체가 메서드를 실행시켜 줘야 함
/** CASE1 : 함수 */
// 호출 주체를 명시할 수 없기 때문에 이 때 this는 전역 객체를 의미한다.
let func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1
/** CASE2 : 메서드 */
// 호출 주체를 명시할 수 있기 때문에 this는 해당 객체(obj)를 의미한다.
let func = function (x) {
console.log(this, x);
};
let obj = {
method: func,
};
obj.method(2); // { method: f } 2
함수로서 호출할 때 그 함수 내부에서의 this:
호출 주체가 없다. 즉 this는 지정되지 않는다. 실행 컨텍스트를 활성화할 때 this가 지정되지 않으면 this는 전역 객체를 의미한다.
함수로서 독립적으로 호출할 때 this는 항상 전역객체를 가리킨다.
메서드 내부함수에서의 this:
메서드의 내부에 있다고 해도, 함수로서 호출한다면 this는 전역 객체를 의미한다.
1. 변수를 활용하는 방법
내부 스코프에 이미 존재하는 this를 별도의 변수(이 경우 self)에 할당하는 방법
var obj1 = {
outer: function() {
console.log(this); // (1) outer
// AS-IS
var innerFunc1 = function() {
console.log(this); // (2) 전역객체
}
innerFunc1();
// TO-BE
ver self = this;
var innerFunc2 = function() {
console.log(self); // (3) outer
};
innerFunc2();
}
};
2. 화살표 함수(this를 바인딩 하지 않는 함수)
일반 함수와 화살표 함수의 가장 큰 차이점은, 'this 바인딩 여부'에 있다.
var obj = {
outer: function() {
console.log(this); // (1) obj
var innerFunc = () => {
console.log(this); // (2) obj
};
innerFunc();
}
}
obj.outer();
콜백함수도 함수기 때문에 this는 전역 객체를 호출한다. 단, 콜백함수를 넘겨 받은 함수에서 콜백함수에 별도로 this를 지정한 경우는 예외로 그 대상을 참조한다.
setTimeout함수, forEach 메서드는 콜백 함수를 호출할 때 대상이 될 this를 지정하지 않으므로 this는 곧 전역(global) 객체이다.
addEventLisstner 메서드는 콜백 함수 호출 시 자신의 this를 상속하므로, 이 때 this는 addEventListener의 앞부분이다.
생성자 함수(구체적인 인스턴스를 만들기 위한 일종의 틀)에서의 this는 항상 새로 생성될 인스턴스를 지칭한다.
var Cat = function (name, age) {
this.bark = '야옹';
this.name = name;
this.age = age;
};
var samsaek = new Cat('삼색', 3); // this: samsaek
var tuxedo = new Cat('턱시도', 4); // this: tuxedo
1. call()
this가 전역객체를 바라보는 경우, 호출 주체가 있는 경우 모두 call()를 사용해서 명시적 this바인딩이 가능하다.
/** this가 전역객체를 호출하는 경우 */
var func = function (a, b, c) {
console.log(this, a, b, c);
};
// no binding
func(1, 2, 3); // global, 1 2 3
// 명시적 binding
func.call({ x:1 }, 4, 5, 6}; // { x:1 } 4 5 6
/** this의 호출 주체가 있는 경우 */
var obj = {
a: 1,
method: function (x, y) {
console.log(this, a, x, y);
}
};
// no binding
// method 함수 안의 this는 항상 obj
obj.method(2, 3); // 1 2 3
// 명시적 binding
obj.method.call({a: 4}, 5, 6); // 4 5 6
2. apply()
call()과 비슷하지만, this 뒤에 오는 매개 변수를 대괄호[]로 묶어준다는 차이점이 있다.
var obj = {
a: 1,
method: function (x, y) {
console.log(this, a, x, y);
}
};
// 명시적 binding
obj.method.apply({a: 4}, [5, 6]); // 4 5 6
/** 유사배열 객체 */
// 배열은 아니지만 배열의 형태를 갖추고 있다.
// 배열처럼 .push(), /slice() 같은 배열 메서드를 사용할 수 없다.
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
//그러나 배열 메서드를 쓰는 것'처럼'은 할수 있다.
Array.prototype.push.call(obj, 'd');
console.log(obj); // {0: 'a', 1: 'b', 2: 'c', 3: 'd', length: 4}
var arr = Array.prototype.slice.call(obj);
console.log(arr); // ['a', 'b', 'c', 'd']
객체를 배열로 쉽게 바꿔주는 메서드
/** 유사배열 객체 */
var obj = {
0: 'a',
1: 'b',
2: 'c',
length: 3
};
var arr = Array.from(obj);
console.log(arr); // ['a', 'b', 'c']
function Coffee(name, price) {
this.name = name;
this.price = price;
}
function Americano(name, price, bean) {
Coffee.call(this, name, price);
this.bean = bean;
}
function Latte(name, price, milk) {
Coffee.call(this, name, price);
this.milk = milk;
}
var Ame = new Americano("매일 아메리카노", "2100", "과테말라");
var Lte = new Latte("매일 라떼", "2900", "저지방우유");
var numbers = [10, 20, 3, 16, 45];
/** 반복문을 활용한 방법 */
var max = min = numbers[0];
numbers.forEach(function(number)) {
if (number > max) {
max = number;
}
if (number < min) {
min = number;
}
});
console.log(max, min); // 45 3
/** apply()를 활용한 방법 */
var max1 = Math.max.apply(null, numbers);
var min1 = Math.min.apply(null, numbers);
console.log(max1, min1); // 45 3
/** spread operator를 활용한 방법 */
var max2 = Math.max(...numbers);
ver min2 = Math.min(...numbers);
console.log(max2, min2); // 45 3
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
/** 함수에 this를 미리 적용하는 목적 */
var bindFunc1 = func.bind({x: 1});
bundFunc1(5, 6, 7, 8); // {x: 1} 5 6 7 8
/**부분 적용 함수를 만드는 목적 */
var bindFunc2 = func.bind({x: 1}, 4, 5);
bindFunc2(6, 7); // {x: 1} 4 5 6 7
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
/** 함수에 this를 미리 적용하는 목적 */
var bindFunc1 = func.bind({x: 1});
/**부분 적용 함수를 만드는 목적 */
var bindFunc2 = func.bind({x: 1}, 4, 5);
console.log(func.name); // func
console.log(bindFunc1.name); // bound func
console.log(bindFunc2.name); // bound func
화이팅!! ㅠㅠ