영원히 변하지 않을 자바스크립트의 초석 개념 3가지
ECMAScript 3판을 다루는 ‘자바스크립트를 깨우치다’란 책을 읽었다. 그리고 이 책에서 말하는 영원히 변하지 않을 자바스크립트 초석 개념이라고 생각하는 3가지에 대해서 정리했다.
this는 함수가 호출되는 네 가지 방식에 의해서 결정된다
this
의 값은 함수가 호출될 때의 컨텍스트에 따라 결정된다. 호출되는 시점에 결정되기 때문에 동적이라고 할 수 있다. 함수가 호출되는 방식 네가지 (함수, 메서드, 생성자, 간접)만 기억한다면 this
를 아주 쉽게 이해 할 수 있다.
함수 호출
일반적인 함수로 호출되면 전역 객체 (헤드 객체)를 참조한다. 브라우저에서는 window
객체이고 Node.js에서는 global
객체다. 엄격모드(strict mode)에서는 undefined
가 된다.
function solution () {
console.log(this)
}
메서드 호출
메서드로 호출될 때는 해당 메서드를 속성으로 가진 객체를 참조한다.
var book = {
title: '자바스크립트를 깨우치다',
read: function () {
console.log(`'${this.title}' 책을 읽었다.`)
}
}
console.log(book.read()) // '자바스크립트를 깨우치다' 책을 읽었다.
생성자 호출
new
키워드와 함께 생성자로 호출되면 생성된 인스턴스 객체를 참조한다.
function Book (title) {
this.title = title
}
var book = new Book('자바스크립트를 깨우치다')
console.log(book.title) // 자바스크립트를 깨우치다
간접 호출
call()
, apply()
, bind()
메서드를 사용하여 간접적으로 호출할 때는 첫 번째 인자로 전달된 객체를 this
로 사용한다.
function Book (title) {
this.title = title
}
function read () {
console.log(`'${this.title}' 책을 읽었다.`)
}
var book = new Book('자바스크립트를 깨우치다')
read.call(book) // '자바스크립트를 깨우치다' 책을 읽었다.
그리고 ES6 화살표 함수
ES3에서 this
는 함수 호출 방식에 따라서 생성자 호출, 간접 호출, 메서드 호출, 함수 호출(자유함수)에 따라 this
가 결정되었다. 그러나 ES6 이후 도입된 화살표 함수는 위 규칙을 완전히 무시하고 주변 스코프를 상속 받는다.
스코프는 함수를 정의할 때 결정된다
말 그대로 어디서 호출하였는지와 상관없이 코드를 작성할 때 정해진다. 이를 정적 스코프 또는 렉시컬 스코프라고 한다.
자바스크립트의 네 가지 스코프
ES3에서는 크게 전역 스코프(global), 함수 스코프(local), eval 스코프 3가지가 있었다. 그리고 ES6에서부터 let
과 const
로 선언된 변수가 가지는 블록 스코프가 도입되었다.
스코프 체인
함수 스코프, 블록 스코프, 전역스 코프는 스코프 체인으로 서로 연결 되어 있다. 그래서 변수를 찾을 때 현재 스코프에서 찾지 못하면 상위 스코프로 이동하여 변수를 찾는다.
eval 스코프는 자신과 자신을 감싸는 스코프에는 접근 할 수 있다. 하지만 스코프 체인을 형성하지는 않기 때문에 독립적이다. (그런데 알아도 쓸데는 없다)
클로저
이미 반환된 함수가 스코프 체인에 의해서 상위 스코프의 변수에 접근할 수 있는 것을 말한다. 정적 스코프, 즉 코드가 작성될 때 정의된 접근 범위를 벗어나서도 스코프 체인에 의해서 이전 부모 함수의 스코프에 접근할 수 있게 되는 것이다.
function readBook () {
var title = '자바스크립트를 깨우치다'
return function () {
console.log(`'${title}' 를 읽었다.`)
}
}
var reading = readBook() // function () { ... } 내부 익명 함수가 반환된다.
reading() // 외부에서 내부 익명 함수를 실행해도 상위 스코프의 title 변수에 접근해서. '자바스크립트를 깨우치다' 를 읽었다. 가 출력된다.
프로토타입
- 자바스크립트에서 Function 객체로부터 생성된 모든 함수 객체 또는 인스턴스는 prototype 속성을 가진다.
- prototype 속성은 상위 객체에 접근하기 위한 체인을 형성하는 역할을 한다.
자바스크립트는 모든 것이 객체 처럼 동작한다. 원시 타입도 객체 처럼 동작하기 위해 일시적으로 래퍼 객체(wrapper object)를 생성하여 감싼다.
그리고 모든 객체는 __proto__
속성을 갖고 있다. 이 속성은 해당 객체의 생성자 함수의 prototype
속성을 가리킨다. 생성자 함수의 prototype
속성은 상위 객체의 속성과 메서드를 상속 받고 있다. 객체의 속성이나 메서드를 접근 할 때 해당 객체에 없으면 prototype
속성을 통해서 상위 객체를 참조한다. 이 과정은 최상위 객체인 Object.prototype
에 도달할 때 까지 반복된다. 이러한 동작방식을 프로토타입 체인이라고 한다.
끝 맺음
this
는 함수가 호출되는 방식에 따라서 바인딩되는 값이 달라지는 동적인 성격을 갖는다. 반면 scope
는 코드가 정의된 위치에 따라 정적으로 결정된다. 화살표 함수의 this
는 함수가 정의된 위치에 따라 결정된다. ES6 이후의 this
에서는 정적인 성격도 가지게 된것이다. 혹시 아직 this
와 scope
를 말로 설명하는 것이 어렵다면 정적인지 동적인지를 구분해서 생각해보는 것만으로도 도움이 될 수 있다.
프로토타입은 더 정리할게 없다.