학습내용
this
실행 컨텍스트에서 현재 객체를 참조하는 키워드. 이때 객체는 함수 호출 방법에 따라 달라진다.
window(브라우저), global(node 환경)등의 전역 객체를 가리킨다. 예를 들어 브라우저 환경의 전역 공간에서 this === window는 true를 반환한다. 따라서 전역 변수를 선언할 때는 var, let, const 키워드를 사용하지 않아도 된다. 변수가 전역 객체의 프로퍼티로 선언되기 때문이다.
단, this를 사용하는 함수를 일반 함수로 호출하면 this는 전역 객체를 참조한다. 화살표 함수를 사용하면 이를 예방할 수 있다. 화살표 함수에서는 this가 전역 객체를 참조하지 않고 함수가 선언된 곳의 this를 참조한다.
전역 공간(Global Scope)
가장 바깥쪽에 존재하는 영역으로 프로그램이 시작될 때 생성되며, 프로그램이 종료될 때까지 유지된다. 이 영역에 선언된 변수를 전역 변수(Global Variable), 함수를 전역 함수(Global Functino)라고 한다. 전역 변수와 전역 함수는 모든 코드에서 접근 가능하기 때문에 전역 공간은 코드의 모듈성을 해치고, 의존성이 높아진다는 문제가 있다. 그러므로 전역 변수와 전역 함수를 최소화 하고 지역 공간을 활용하는 편이 좋다.
지역 공간(Local Scope)
함수 내에서 선언한 변수와 매개변수들이 포함된 공간으로 함수가 실행될 때 생성되며, 함수가 실행을 완료하면 소멸된다.function addOne(num) { let count = 0; return num + 1; }위 코드에서
count는addOne함수의 지역 공간에서 선언되었으므로,addOne이 호출될 때마다count가 새롭게 생성된다. 즉, 변수는 함수 내부에서만 접근 가능하며 함수 외부에서는 존재하지 않는다.이처럼 함수 내에서 필요한 데이터를 안전하게 보관하고, 전역 공간을 불필요하게 오염시키지 않아 안정적인 코드 작성이 가능하다.
this가 지정되지 않았으므로 전역 객체 window를 가리킨다. 단, strict mode에서는 this가 undefined를 가리킨다.
var func = function (x) {
console.log(this, x);
};
func(1);
this = window
주체가 되는 객체를 가리킨다.
var obj = {
method: func, // 위 함수의 func
};
obj.method(2) // = obj['method'](2)
method는 obj에 의해 호출되었으므로 this = obj
함수와 메서드의 차이
- 함수
단독 호출 가능 ex)getAge();- 메서드
호출 주체 필요 ex)person.getAge();
일반 함수와 마찬가지로 전역 객체를 가리킨다. this binding을 결정짓는 요소는 해당 함수를 호출하는 구문 앞에 .과 []의 여부다. 메서드 내부인지, 함수 내부인지 등의 주변 환경은 영향을 미치지 않는다.
var obj1 = {
outer: function() {
console.log(this); // obj1
var innerFunc = function() {
console.log(this); // window
}
innerFunc();
var obj2 = {
innerMethod: innerFunc
};
obj2.innerMethod();
}
};
obj1.outer();
첫 번째 this
obj1이 outer를 호출하고 있으므로 this= obj1
두 번째 this
outer 메서드 내부에 있지만 innerFunc() 함수를 독립적으로 호출하고 있으므로 this= window
this 우회하기변수 활용
var = obj1 = {
outer: function() {
console.log(this); // obj1
var innerFunc1 = function() {
console.log(this); // window
}
innerfunc1();
var self = this; // obj1
var innerFunc2 = function() {
console.log(self);
};
innerFunc2()'
}
};
obj1.outer();
원래대로라면 innerFunc2() 호출 시 this가 window를 반환해야하지만, outer에서 받아온 this값을 self라는 변수로 할당했기 때문에 obj1을 반환한다.
화살표 함수
var obj = {
outer: function() {
console.log(this); // obj
var innerFunc = () => {
console.log(this); // obj
};
innerFunc();
}
};
obj.outer();
화살표 함수는 this binding 과정을 생략하므롤 상위 메서드의 this값이 유지된다.
setTimeout
setTimeout(function() { console.log(this) }, 300);
setTimeout 함수는 this를 지정하지 않기 때문에 window 반환 (정확히는 console.log(this) 함수를 호출하는 과정에서 this가 유실되기 때문)
forEach
[1, 2, 3, 4, 5].forEach(function(x) {
console.log(this, x);
});
forEach 메서드는 this를 명시할 수도 있지만 아무런 명시가 없을 시에는 window를 반환한다.
addEventListner
document.body.innerHTML += '<button id="a">클릭</button>'
document.body.querySelector('#a').addEventListener('click', function(e) {
console.log(this, e);
});
addEventListner 메서드는 스스로의 this를 상속하기 때문에 <button id="a">클릭</button> 반환
인스턴스(생성자 함수로 만든 객체)를 가리킨다.
var Cat = function(name, age) {
this.bark = "이얏호응";
this.name = name;
this.age = age;
};
var yattong = new Cat('야통', 4) // this = yattong
var mu = new Cat('무', 3), // this = mu
매개변수를 할당해서 this값을 지정한다.
this값 지정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
this값 변경var obj = {
a: 1,
method: function(x, y) {
console.log(this.a, x, y);
};
obj.method(2, 3) ➡️ 1 2 3
this는 obj를 가리키므로 this.a는 a:1이다.
obj.method.call({a:4}, 5, 6) ➡️ 4 5 6
객체 안에 지정한 a의 값도 call 메서드로 변경 가능
call 메서드와 동일하나 두 번째 인자를 ,가 아닌 [배열]로 구분
func.call({x:1}, 4, 5, 6) = func.aplly({x:1}, [4, 5, 6])
유사 배열 객체(array-like-object)에 배열 메서드 적용
유사 배열
배열은 아니지만 배열처럼 동작하는 객체var obj = { 0: 'a', 1: 'b', 2: 'c', length: 3 };배열과 마찬가지로
length를 갖고 있으며index가 0부터 시작해서 1씩 증가한다.
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']
slice()
배열로부터 특정 범위의 값을 복사 후 해당 값들을 모아 새로운 배열로 생성하는 함수. 첫 번째 인자로 시작index, 두 번째 인자로 종료index를 받으며 시작부터 종료까지의 값을 복사 후 반환한다.
arguments에 배열 메서드 적용
function a() {
var argv = Array.prototype.slice.call(arguments);
argv.forEach(function(arg) {
console.log(arg);
});
}
a(5,1,2);
5
1
2
a 함수가 호출될 때 a의 인자를 call 메서드를 통해 넘겨받음
NodeList에 배열 메서드 적용
<div>첫 번째 div</div>
<div>두 번째 div</div>
<div>세 번째 div</div>
var nodeList = document.querySelectorAll('div');
var nodeArr = Array.prototype.slice.call(nodeList);
nodeArr.forEach(function(node) {
console.log(node);
});
<div>첫 번째 div</div>
<div>두 번째 div</div>
<div>세 번째 div</div>