this는 실행 컨텍스트가 생성될 때 결정(this binding)
=== this는 함수를 호출할 때 결정
var func = function (x) {
console.log(this, x);
};
func(1); // Window { ... } 1
var obj = {
method: func,
};
obj.method(2); // { method: f } 2
var obj = {
method: function (x) { console.log(this, x) }
};
obj.method(1); // { method: f } 1
obj['method'](2); // { method: f } 2
var obj = {
methodA: function () { console.log(this) },
inner: {
methodB: function() { console.log(this) },
}
};
obj.methodA(); // this === obj
obj['methodA'](); // this === obj
obj.inner.methodB(); // this === obj.inner
obj.inner['methodB'](); // this === obj.inner
obj['inner'].methodB(); // this === obj.inner
obj['inner']['methodB'](); // this === obj.inner
함수 내부에서의 this
1) 어떤 함수를 함수로서 호출할 경우, this는 지정되지 않음(호출 주체가 없으므로)
2) 실행컨텍스트를 활성화할 당시 this가 지정되지 않은 경우, this는 전역 객체를 가리킴
3) 따라서, 함수로서 ‘독립적으로’ 호출할 때는 this는 전역 객체
method의 내부함수에서의 this
1) method의 내부라고 해도, 함수로서 호출한다면 this는 전역 객체
2) this 바인딩에 관해서는
함수를 실행하는 당시의 주변 환경(method 내부인지, 함수 내부인지)는 중요하지 않고,
오직 해당 함수를 호출하는 구문 앞에 점 또는 대괄호 표기가 있는지가 중요함
var obj1 = {
outer: function() {
console.log(this); // obj1
var innerFunc = function() {
console.log(this);
}
innerFunc(); // 함수로서의 call -> this는 전역 객체
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
1) 변수 활용
var obj1 = {
outer: function() {
console.log(this); // obj
var innerFunc1 = function() {
console.log(this);
}
innerFunc1(); // this === window
var self = this;
var innerFunc2 = function() {
console.log(self);
};
innerFunc2(); // this === self
}
};
obj1.outer();
2) 화살표함수
화살표 함수는, 실행 컨텍스트를 생성할 때 this 바인딩 과정 자체가 없음
var obj = {
outer: function() {
console.log(this); // obj
var innerFunc = () => {
console.log(this);
};
innerFunc(); // this === obj
}
}
obj.outer();
setTimeout(function () { console.log(this) }, 300);
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
document.body.innerHTML += '<button id="a">클릭</button>';
document.body.querySelector('#a').addEventListener('click', function(e) {
console.log(this, e);
});
1) setTimeout 함수, forEach method는 콜백 함수를 호출할 때 대상이 될 this를 지정하지 않으므로,
this는 곧 window객체
2) addEventListner method는 콜백 함수 호출 시, 자신의 this를 상속하므로, this는addEventListner의 앞부분
(button 태그)
var Dog = function (name, age) {
this.bark = '멍멍';
this.name = name;
this.age = age;
};
var gae = new Cat('개', 6); //this : gae
var gangaji = new Cat('강아지', 2); //this : gangaji
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func(1, 2, 3); // Window{ ... } 1 2 3
func.call({ x: 1 }, 4, 5, 6}; // { x: 1 } 4 5 6
var obj = {
a: 1,
method: function (x, y) {
this 5
console.log(this.a, x, y);
}
};
obj.method(2, 3); // 1 2 3
obj.method.call({ a: 4 }, 5, 6); // 4 5 6
var func = function (a, b, c) {
console.log(this, a, b, c);
};
func.apply({ x: 1 }, [4, 5, 6]); // { x: 1 } 4 5 6
var obj = {
a: 1,
method: function (x, y) {
console.log(this.a, x, y);
}
};
obj.method.apply({ a: 4 }, [5, 6]); // 4 5 6
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)
function Person(name, gender) {
this.name = name;
this.gender = gender;
}
function Student(name, gender, school) {
Person.call(this, name, gender);
this.school = school;
}
function Employee(name, gender, company) {
Person.apply(this, [name, gender]);
this.company = company;
}
var ab = new Student('abbie', 'female', '서울대');
var bc = new Employee('bictor', 'male', '삼성');
//비효율
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);
//효율
var numbers = [10, 20, 3, 16, 45];
var max = Math.max.apply(null, numbers);
var min = Math.min.apply(null, numbers);
console.log(max, min);
//Spread Operation(ES6)
//https://paperblock.tistory.com/62
const numbers = [10, 20, 3, 16, 45];
const max = Math.max(...numbers);
const min = Math.min(...numbers);
console.log(max min);
call과 비슷하지만, 즉시 호출하지는 않고 넘겨받은 this 및 인수들로 새로운 함수를 반환하는 method
목적
1) 함수에 this를 미리 적용하는 것
2) 부분 적용 함수 구현
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
func(1, 2, 3, 4); // window객체
var bindFunc1 = func.bind({ x: 1 });
bindFunc1(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
bindFunc2(8, 9); // { x: 1 } 4 5 8 9
var func = function (a, b, c, d) {
console.log(this, a, b, c, d);
};
var bindFunc = func.bind({ x:1 }, 4, 5);
1) 내부함수
var obj = {
outer: function() {
console.log(this);
var innerFunc = function () {
console.log(this);
};
innerFunc.call(this);
}
};
obj.outer();
var obj = {
outer: function() {
console.log(this);
var innerFunc = function () {
console.log(this);
}.bind(this);
innerFunc();
}
};
obj.outer();
2) 콜백함수
var obj = {
logThis: function () {
console.log(this);
},
logThisLater1: function () {
setTimeout(this.logThis, 500);
},
logThisLater2: function () {
setTimeout(this.logThis.bind(this), 1000);
}
};
obj.logThisLater1();
obj.logThisLater2();
var obj = {
outer: function () {
console.log(this);
var innerFunc = () => {
console.log(this);
};
innerFunc();
};
};
obj.outer();
// forEach 예시
var report = {
sum: 0,
count: 0,
add: function () {
var args = Array.prototype.slice.call(arguments);
args.forEach(function (entry) {
this.sum += entry;
++this.count;
}, this);
},
average: function () {
return this.sum / this.count;
},
};
report.add(60, 85, 95);
console.log(report.sum, report.count, report.average());
// 콜백 함수와 함께 thisArg를 인자로 받는 method
// forEach, map, filter, some, every, find, findIndex, flatMap, from, forEach(Set, Map)