사전 퀴즈
정답은 '오류가 발생한다'
apply, call, bind 등으로 this에 대해 주입한 상황이 아니고 new 키워드없이 실행한 함수 내 this는 전역 객체(window)를 바라본다.
즉 this.name = name의 결과는 window.name = name 이라는 이야기이다.
의도한 결과가 나오면 new Cat으로 인스턴스를 생성하여 this가 해당 인스턴스를 가리키도록 해야 한다.
var logger = (function(){
// logCount는 밖에서 접근할 수 없다. 일종의 private 효과
var logCount = 0;
function log(message) {
console.log(message);
logCount = logCount + 1;
}
function getLogCount() {
return logCount;
}
return {
log: log,
getLogCount: getLogCount
}
})()
=> logger만 window에 묶이고 내부에 있는 변수나 함수는 바깥에서 접근하지 않는다. (스코프의 오염 방지)
var idiots = {
name: 'idiots',
genre: 'punk rock',
members: {
roto: {
memberName: 'roto',
play: function() {
console.log(`band ${idiots.name} ${this.memberName} play start.`
}
}
}
}
perform 함수 아래 setTimeout으로 인해 실행되는 함수의 this는 RockBand의 this가 아니기 때문에, 참조 오류가 발생
클로저를 이용한 해결법
function RockBand(members) {
var that = this; // 특정 변수에 this를 선언
this.members = members;
this.perform = function() {
setTimeout(function(){
// this라 선언한 that 사용
that.members.forEach(function(member){ member.perform() })
}, 1000)
}
}
// setTimeout 스코프와 var that 스코프는 다르지만 자바스크립트의 클로저 특성으로 외부 변수 호출이 가능하다
var theOralCigarettes = new RockBand([
{
name: 'takuya',
perform: function() { console.log('a e u i a e u i')}
}
])
theOralCigarettes.perform()
bind를 이용한 해결법
function RockBand(members) {
var that = this;
this.members = members;
this.perform = function() {
setTimeout(function(){
this.members.forEach(function(member){ member.perform() })
}.bind(this), 1000)
}
}
var theOralCigarettes = new RockBand([
{
name: 'takuya',
perform: function() { console.log('a e u i a e u i')}
}
])
theOralCigarettes.perform()
call, apply, bind 차이점
bind를 이용하면 함수를 실행할 때 함수 안에 있는 this가 bind로 갈아끼워진 this로 바뀐다.
call, apply는 함수를 실행하는 역할을 한다. (조금 더 자세히 알아볼 것)
const numbers = [1, 2, 3, 4, 5];
for(var i = 0; i < numbers.length; i++){
(function(count){
setTimeout(function(){
console.log(`number index ${count}`);
}, 1000);
})(i)
}
let, const는 {} 블럭 스코프이다. 따라서 위 코드에서는 i가 length만큼 {}의 스코프가 따로 생성이 된다. (0 일때, 1 일때 ... 스코프가 따로따로 생성) setTimeout이 5번 실행이 될 때 i는 자신이 속해있는 중괄호 안에 있는 let을 참조한다.
const arr1 = []
arr1 = [1,2]; // Error!
// 가능
arr1.push(1);
arr1.push(2);
var a = 1;
function hello() {
console.log(a); // a가 hello function scope에 없는데에도 접근 가능함.
}
실행 컨텍스트 : 실행되기 전에 컴파일러가 코드를 읽으면서 함수에 대한 정보를 갖고 있는 객체를 메모리에 스택 형식으로 쌓는다.
https://poiemaweb.com/js-execution-context
추천 도서
더글라스 크락포드의 자바스크립트 완벽 가이드
자바스크립트 패턴과 테스트