// setTimeout() & clearTimeout() 사용해보기
setTimeout(() => {
console.log("sumin")
}, 3000)
// 3초 뒤에 콘솔 출력
const h1El = document.querySelector("h1")
h1El.addEventListener("click", () => {
clearTimeout(timer)
})
// h1태그 클릭 시 3초뒤 함수 실행
📌 함수의 인수로 사용되는 함수
특정한 실행 위치를 보장해주는 용도로 콜백 함수를 활용한다.
function timeout(callback) {
setTimeout(() => {
console.log("sumin")
callback()
}, 3000)
}
timeout(() => {
console.log("done!")
})
timeout( ) 함수의 인수로 "done!"을 출력하는 코드를 넣으면 콜백함수가 된다.
이렇게 만들어진 콜백함수가 callback의 매개변수로 들어간다.
const sumin = {
firstName: "sumin",
lastName: "kim",
getFullName: function () {
return `${this.firstName} ${this.lastName}`
},
}
function User(first, last) {
this.firstName = first
this.lastName = last
}
// prototype 메소드로 호출
User.prototype.getFullName = function () {
return `${this.firstName} ${this.lastName}`
}
// 새로운 객체 생성
const mango = new User("mango", "yoon")
console.log(mango.getFullName())
// 한번만 만들어져있는 getFullName()함수를 참조하여 mango yoon 출력
new 키워드를 통해 만들어진 함수(user)를 생성자 함수라 한다.
= 객체 데이터를 생성하는 함수
User
와 같이 new키워드로 생성된 함수는 파스칼케이스로 입력한다.
생성자함수로 실행한 결과를 반환해서 할당된 변수( mango )를 생성자 함수의 instance라 한다.
user함수 prototype 속성 부분에 getFullName을 할당해주면 몇개의 객체를 생성하던 메모리에는 딱 한번만 만들어진다. 즉, new 키워드를 통해 생성자 함수와 instance를 만들고 prototype 속성을 통해 하나의 메모리 공간을 만든다. 그렇기때문에 자바스크립트는 prototype 기반의 프로그래밍 언어라고도 부른다.
상당히 복잡해보이는 생성자함수.. 생성자 함수를 더 깔끔하게 구현 할 수 있는 방법이 있다.
📖 위의 코드로 Class를 사용해보자!
class User {
constructor(first, last) {
// function 생략 가능
this.firstName = first
this.lastName = last
}
getFullName() {
return `${this.firstName} ${this.lastName}`
}
}
const sumin = new User("sumin", "kim")
const mango = new User("mango", "yoon")
console.log(sumin) // User {firstName: 'sumin', lastName: 'kim'}
console.log(mango.getFullName()) // mango yoon
class 내부에는 constructor
생성자가 존재해야 한다. 생성자는 클래스의 instance인 객체를 생성할 때 초기화를 담당하는 코드 블록이다. 클래스의 상속관계에서 초기화를 수행할 수 있도록 부모 클래스의 생성자를 호출하는 특징이 있다. 그렇기때문에 생성자 내부에는 return
이 존재하지 않는다. new키워드를 통해 생성자함수가 명시적으로 호출되고 그것이 새로운 객체에 할당한다. class키워드를 사용하여 기존보다 깔끔한 문법을 구현 할 수 있다.
this 가 정의된 함수에서 일반함수는 호출 위치에 따라 this를 정의하고, 화살표함수는 자신이 선언된 함수 범위에서 this를 정의한다. this가 정의되지 않은 함수에서는 상관없다.
처음 들으면 이게 무슨말이지 싶을거다.......
const sumin = {
name: "sumin",
// 일반함수
normal: function () {
console.log(this.name)
},
// 화살표함수
arrow: () => {
console.log(this.name)
},
}
sumin.normal( )
메소드를 호출하면 sumin
객체 내부에 위치하기때문에 그 객체가 곧 this가 된다. 즉, 호출 위치에서 정의된다.
sumin.arrow()
메소드 호출 위치와 전혀 상관 없이 this
가 선언된 함수 범위에서 정의되어 undifined를 출력한다. 즉, 화살표함수가 만들어지는 위치에서 this
가 정의된다.
📌 일반함수에서의 this 예시
const timer = { name: "sumin!", timeout: function () { setTimeout(function () { console.log(this.name) }, 3000) }, } timer.timeout()
위의 로직에서 this
를 호출한 위치는 timeout()
함수이다. 그러나 현재 this
는 setTimeout()
함수를 정의하고있어 출력되지 않는다.
📌 화살표함수에서의 this 예시
const timer = { name: "sumin!", timeout: function () { setTimeout(() => { console.log(this.name) }, 3000) }, } timer.timeout()
this
가 정의된 위치는 timeout()
함수 내부의 setTimeout()
함수 내부에 위치한다. 즉, 함수 범위는 timeout()
함수가 되고 this
는 일반함수가 정의된 timer
객체를 가르키기때문에 this
는 결국 timer
가 된다.
상황에 따라 잘 사용하기!!
그렇다면 this는 과연 무엇일까!!!!! 왜 이렇게 혼란스럽게 하는 것일까....
실행 컨텍스트(맥락)를 지원하는 자바스크립트의 키워드 this
는 기본적으로 선언된 위치에 따라 값이 달라진다.
📌 첫번째 ) this는 항상 객체를 바라본다. this = 객체
this 상황에따라 참조하는 객체가 달라진다. 전역공간에 있을 때의 this는 window를 바라본다. 그러면this === window
가 된다. 그렇다면 window.eventHandler
가 this.eventHandler
로 되는 것 일까?
아니다 !
코드는 기본적으로 명시적으로 쓰이는걸 선호한다. 에러와 버그와 모든 리스크를 생각해서 명시적으로 사용할 수 있을 땐 명시적으로 쓰자! 그래서 명시적이지 않은 this가 어려운 것이라고 한다..
📌 두번째 ) 실행 맥락( excute context=실행맥락 )으로 this를 연결한다.
let obj = {
id: 1,
getId: function(){
return this.id
}
}
console.log(obj,id) // 1
console.log(obj.getId()) // 1
console.log(this.id) // undefined
this는 getId( )
메소드의 소유객체인 obj를 가르키고있다. 실행에서의 맥락으로 this를 연결하여 값이 출력되지만 메소드 내부의 this.id의 값은 정해져있지 않다.
📌 세번째 ) 실행시 소유자 확인이 안되면 this는 전역객체에 연결된다.
function caller(fn) {
console.log(fn()) // undefined
}
let obj = {
id: 1,
getId: function(){
return this.id
}
}
caller(obj.getId)
값이 undefined로 나온 이유는 호출이 실행되는 순간에는 소유자(obj)가 사라진다. 즉 this는 소유자인 obj에 연결되어있고 연결된 obj가 함수의 fn으로 들어가면 this의 실행은 obj까지가 된다.