this 키워드를 쓰면 그 함수를 가지고 있는 오브젝트
를 가리킨다. (전역에서는 window를 출력함)
addEventListener 안에서는 이벤트가 발생한 대상
을 가리킨다.
특징 : 내부의 this 값을 변화시키지 않음. 외부의 this 값을 그대로 재사용할 수 있음.
var object = {
name: ["kim", "lee", "park"],
func: function () {
console.log(this);
object.name.forEach(function () {
console.log(this);
});
},
};
object.func();
var object = {
name: ["kim", "lee", "park"],
func: function () {
console.log(this);
object.name.forEach(() => {
console.log(this);
});
},
};
object.func();
arrow function 는 외부의 this 값을 그대로 재사용 할 수 있으므로 편리하다.
var func = function() {
}
func();
var func = () => {
}
func();
arrow function 의 장점
직관적이다. 파라미터가 1개면 소괄호를 생략할 수 있다.
var func = function(a){ return a+10 };
===
var func = a => a + 10;
[1,2,3,4].forEach(function(a){
console.log(a)
})
// 1,2,3,4
[1,2,3,4].forEach( a => console.log(a));
// 1,2,3,4
arrow function 은 this 키워드를 재정의 해주지 않으므로
eventlistener 와 object 에서 사용할 때 주의해야 한다.
document.getElementById('button').addEventListener('click', (e) => {
e.currentTarget !== this; // this가 window를 출력함
})
var obj = {
func : () => {
return this; // windows 를 출력함
}
}
obj.func();
arrow function 은 eventlistener의 this 에서 제대로 활용할 수 있는 것 처럼 보인다.
다른 오브젝트나 function 안에서는 arrow function 을 사용한 this 를 사용하는 것 보다
e.currentTarget 이나 일반적인 함수선언을 하는게 좋겠다.
예시 한줄로 이해할 수 있는데,
document.querySelector(".button").addEventListener("click", function () {
console.log(this);
setTimeout(() => {
// setTimeout(function() {
console.log(this);
}, 1000);
});
eventListener 안의 this 함수는 이벤트 대상을 가리키게 되므로 버튼 요소를 가져온다.
그런데 콜백함수를 써야하는 setTimeout 같은 메소드를 사용할 때,
대상이 버튼을 가리키게 하고싶다면 arrow function 을 이용해서 상위요소의 this 값을 가져오면 되겠다.
위의 함수에서 이벤트리스너의 function 부분을 arrow function 으로 변경하면
마찬가지로 window 를 리턴하게 되니 주의.
복잡하고 햇갈리지만 정말 유용한 기능이다.
var 키워드를 대체해서 나온 문법.
변수에는 선언, 할당, 범위 라는 세가지 성격을 반드시 가지고 있는데,
javscript 의 변수 세가지는 각각 아래와 같은 특징을 가지고 있다.
var : 재선언 : O 재할당 : O 범위 : function
let : 재선언 : X 재할당 : O 범위 : { } (중괄호)
const : 재선언 : X 재할당 : X 범위 : { } (중괄호)
단, const 변수로 선언한 object 내의 key, value 값은 변경이 가능하다.
이마저도 수정이 불가능하게 만들고싶다면 object.freeze(obj)
라는 문법도 있다.
use strict
로 엄격모드까지 선언하면 에러메세지도 출력할 수 있다.
예를들어,
var name = 30;
라는 변수를 선언했다고 하면 자바스크립트에서는
<script>
var name;
...
name = 30;
</script>
이런식으로 변수의 선언을 변수 범위 최상단에 고정시켜놓고 지정위치에서 변수를 할당한다.
var name='lee', age=20;
모든 곳에서 쓸 수 있는 변수
습관적으로 script 최상단에 넣으면 전역으로 변수가 할당된다.
그런데,
window.name = 'kim'
이런식으로 window 에 할당하면 전역변수로 name 을 부를때마다 kim 을 출력받을 수 있다.
개발자들은 전역변수를 window 로 선언하는걸 지향한다고 한다.
좀 더 직관적이어서 그렇다는 것 같다.
func();
function func() {
console.log(hello);
let hello = "hi";
}
func2();
var func2 = function () {
console.log(hello);
let hello = "hi";
};
그냥봐도 총체적 난국인 이 두 함수를 어떤식으로 고칠 수 있을까 ?
우선 첫번째.
func 함수는 호이스팅되어 최상단에 위치하게 되므로 func() 가 함수선언보다 상단에 있어도
문제없이 작동된다.
물론 func 함수 안에 있는 let = hello 도 호이스팅이 된다.
그러나 호이스팅이 되는건 선언
부분.
값이 아직 할당되지 않았으므로 제대로 결과가 나오지 않는것이다.
var 로 변수를 선언하면 undefined 값이 자동으로 담겨 호이스팅이 되므로
에러를 출력하지 않고 undefined 값을 리턴하게 된다.
let 과 const 는 이러한 오류와 실수를 방지하기 위해 호이스팅시에 값을 할당하지 않는다.
func();
function func() {
let hello = "hi";
console.log(hello);
}
이런식으로 수정하면 되겠다.
두번째는 좀 더 난국이다.
비슷한 문제같지만
func2();
var func2 = function () {
let hello = "hi";
console.log(hello);
};
Uncaught TypeError: func2 is not a function
func2 가 함수가 아니라는 에러가 뜬다.
왜그럴까 ?
자세히 보면 함수를 정의하는 방식에 차이가 있다.
첫번째 경우를 함수 선언식
, 두번째의 경우를 함수 표현식
이라고 부르는데
함수 표현식은 호이스팅되지 않는다.
정확히는 함수 표현식의 선언부분, var func2; 부분만 호이스팅 된다.
함수 선언식은 함수의 전부가 호이스팅 된다.
var func2 가 정의되기 이전에는 var 로 변수를 선언했으므로 undefined 가 담겨있을테니
함수가 아니라는 에러가 뜨는것이다.
var func2 = function () {
let hello = "hi";
console.log(hello);
};
func2();
이런식으로 고쳐주면 문제없이 작동한다.
<body>
<div style='display : none'>modal1</div>
<div style='display : none'>modal2</div>
<div style='display : none'>modal3</div>
<button>btn1</button>
<button>btn2</button>
<button>btn3</button>
</body>
<script>
var buttons = document.querySelectorAll('button');
var modals = document.querySelectorAll('modal');
for(var i=0; i < button.length; i++){
buttons[i].addEventListener('click',function(){
modals[i].style.display = 'block'
})
}
</script>
//Uncaught TypeError: Cannot read properties of undefined (reading 'style')
at HTMLButtonElement.<anonymous>
querySelectorAll 로 찾은 버튼을 클릭하면 모달을 활성화시켜주는 기능.
하지만 var 는 변수의 범위가 function 이라 전역으로 선언이 되어버린다.
실행순서
에 주의해서 보면 어떤 문제인지 잘 알 수 있다.
EventListenr 는 특정 이벤트가 발생했을 경우
실행되는데,
반복문은 이미 i++ 가 4번 실행이 됐기 때문에,
buttons[4], modals[4]를 찾으려고 하면 찾을 수 없는것이다.
따라서 변수의 범위가 중괄호인 let 으로 바꿔주면 정상적으로 작동한다.
이런 유효범위를 스코프(scope) 라고 하는데,
정확한 뜻으로는 자신이 선언된 위치에 따라 식별자 자신을 참조 가능한 유효범위
를 말한다.
식별자는 유일해야하지만 유효범위, 즉 스코프가 다르다면 중복이 가능하다.
let과 const 를 이러한 관점으로 바라볼 때,
코드 블록(if, while, for, function), 중괄호로 감싸진 영역의 스코프를 가진다.
var가 함수 레벨 스코프를 가지는 것과는 엄연하게 구분된다.
처음 자바스크립트를 배울 때 가급적이면 var를 사용하지 말라는 조언이 이러한 이유 때문이다.