최근 수정 시각 : 2025-01-05 20:06:46

JavaScript/문법

파일:상위 문서 아이콘.svg   상위 문서: JavaScript
프로그래밍 언어 문법
{{{#!folding [ 펼치기 · 접기 ]
{{{#!wiki style="margin: 0 -10px -5px; word-break: keep-all"
프로그래밍 언어 문법
C( 포인터 · 구조체 · size_t) · C++( 자료형 · 클래스 · 이름공간 · 상수 표현식 · 특성) · C# · Java · Python( 함수 · 모듈) · Kotlin · MATLAB · SQL · PHP · JavaScript( 표준 내장 객체) · Haskell( 모나드)
마크업 언어 문법
HTML · CSS
개념과 용어
함수( 인라인 함수 · 고차 함수 · 콜백 함수 · 람다식) · 리터럴 · 상속 · 예외 · 조건문 · 반복문 · 참조에 의한 호출 · eval · 네임스페이스 · 호이스팅
기타
#! · == · === · deprecated · NaN · null · undefined · 배커스-나우르 표기법
}}}}}}
프로그래밍 언어 목록 · 분류 · 문법 · 예제


1. 개요2. 편집 지침3. 시작하기
3.1. HTML 문서 내에서 쓰이는 자바스크립트3.2. 문서 밖에서 쓰이는 자바스크립트
4. 자료형
4.1. 원시 값
4.1.1. Null 자료형4.1.2. Undefined 자료형4.1.3. Boolean 자료형4.1.4. Number 자료형4.1.5. BigInt 자료형4.1.6. String 자료형4.1.7. Symbol 자료형
4.2. 객체
5. 변수 선언
5.1. 자동 선언5.2. var 선언5.3. let 선언5.4. var 선언과 let 선언의 차이5.5. const 선언
6. 함수
6.1. 함수의 선언6.2. 함수의 호출6.3. 함수의 반환
7. 반복문
7.1. for 반복문7.2. while 반복문7.3. do-while 반복문
8. 클래스
8.1. 객체의 프로토타입8.2. 클래스의 구성8.3. 객체 지향
8.3.1. Getter/Setter8.3.2. 정적 메서드8.3.3. Private 메서드8.3.4. 상속
9. 논리연산자10. 표준 내장 객체11. 관련 문서

1. 개요

이 문서는 프로그래밍 언어 JavaScript의 문법을 정리한 것이다.

2. 편집 지침

소스 코드로 예시를 들 때 아래와 같이 문법을 활용하여 소스코드를 써 주시기 바랍니다.
{{{#!syntax javascript (소스코드)}}}

아래는 예시코드입니다.
#!syntax javascript 
console.log("Hello, world!")

본 문서에서 쓰이는 문법의 대부분은 Javascript 라이브러리인 Node.js 문법이 아닌 브라우저에서 쓰이는 ECMAScript 최신버전을 기준으로 다룹니다. HTML와 관련된 문법을 다룰 수 있습니다.

3. 시작하기

3.1. HTML 문서 내에서 쓰이는 자바스크립트

HTML 문서 내에서 자바스크립트를 사용하고 싶다면 <script> 태그를 사용하자.
#!syntax html
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>사이트</title>
</head>
<body>
    <button onclick="sayHello()">안녕!</button>
    <script>
        function sayHello() {
            alert("안녕하세요")
        }
    </script>
</body>
</html>

위 예제는 안녕 버튼을 누르면 sayHello라는 script 태그 내의 함수가 호출되어서 alert로 "안녕하세요"가 출력된다.

3.2. 문서 밖에서 쓰이는 자바스크립트

이번엔 위 문단의 예제에서 script 부분만 떼와서 파일을 분리해보자.
  • 외부 파일인 file.js
    {{{#!syntax javascript
function sayHello() {
alert("안녕하세요")
}
}}}
참고로 자바스크립트는 파일 확장자로 *.js 또는 *.javascript를 사용한다.
  • 원본 파일인 index.html
    {{{#!syntax html
<!DOCTYPE html>
<html lang="ko">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>사이트</title>
</head>
<body>
<button onclick="sayHello()">
<script src="script.js"></script>
</body>
</html>
}}}
몇 천, 몇 만줄 단위를 넘어가는 코드를 사용해야 하고, 코드가 여러 html 페이지에서 재사용된다면 외부 파일로 분리하는 방법이 좋다.

4. 자료형

4.1. 원시 값

원시 값 (Primitive values)[1]
언어의 최하위 수준에서 직접 표현되는 불변

원시 값은 typeof 연산자로 테스트할 수 있지만 null만은 다르다. 아래 항목 참고

null과 undefined를 제외한 모든 원시 타입에는 객체 래퍼(Object wrapper)가 있는데, 작업하는데 유용한 속성들을 제공한다. String(), Number() 등이 바로 그것. 만약 원시 값에서 속성을 접근한다면, 언어 차원에서 원시 타입을 래퍼로 감싸 객체의 속성에 접근한다.
예를 들어, "나무"라는 String 자료형의 값에 "위키"를 뒤에 붙이기 위해 아래와 같은 코드를 실행한다면,
#!syntax javascript "나무".concat("위키")
아래와 같이 자동으로 String 래퍼로 감싸 래퍼의 concat 속성에 접근해 실행하게 된다.
#!syntax javascript String("나무").concat("위키")
주의할 점은 null과 undefined는 해당하는 객체 래퍼가 없어, 속성에 접근하면 TypeError가 발생하므로, 선택적 체이닝(Optional chaining) 연산자를 사용해 오류를 피하는 것이 중요하다. 특히 undefined 항목을 보면 알 수 있듯이 변수명이 잘못되었거나, 값이 잘못들어올 경우, 의도된 값이 아닌 경우, JavaScript는 모두 undefined로 처리하기 때문에 오류의 여지가 있는 부분에 연산자를 활용하는 것은 하나의 팁이다.
<rowcolor=#fff> 자료형 typeof 반환 값 객체 래퍼(Object wrapper)
<colcolor=#fff><colbgcolor=#c9a600> Null "object"[2] 없음
Undefined "undefined" 없음
Boolean "boolean" Boolean()
Number "number" Number()
BigInt "bigint" BigInt()
String "string" String()
Symbol "symbol" Symbol()

4.1.1. Null 자료형

Null 자료형(Null type)
Null 자료형은 원시 값 중 하나로, 어떤 값이 의도적으로 비어있음[3]을 표현하며, boolean 연산에서는 false로 취급한다. Null 자료형은 null이라는 오직 하나의 값만 가질 수 있다.

typeof 연산자로 반환 값을 알 수 없는데, 객체임을 나타내는 "object"를 반환하기 때문이다. 따라서 null은 일치 연산자로 비교해야 한다.
#!syntax javascript
const nullvalue = null;
console.log(typeof nullvalue) // "object" 반환, null 테스트 불가
if (nullvalue === null) {
    console.log("null") // 일치 연산자로 테스트
}

파일:상세 내용 아이콘.svg   다른 언어의 null의 쓰임에 대한 자세한 내용은 Null(프로그래밍 언어) 문서
번 문단을
부분을
참고하십시오.

4.1.2. Undefined 자료형

Undefined 자료형(Undefined type)
Undefined 자료형은 원시 값 중 하나이며, undefined라는 오직 하나의 값만 가질 수 있다.

정말 어디서나 볼 수 있는데, 함수의 반환 값이 없을 때, 존재하지 않는 객체일때, 변수를 초기화했을 때 등 JavaScript 자체의 기본값으로써 쓰인다.

Null 자료형과의 차이는 개념적으로 undefined는 값이 없음을, null은 객체가 없음을 뜻한다.

파일:상세 내용 아이콘.svg   자세한 내용은 undefined 문서
번 문단을
부분을
참고하십시오.

4.1.3. Boolean 자료형

Boolean 자료형(Boolean type)
Boolean 자료형은 원시 값 중 하나이며, 논리 요소를 나타낸다. 그리고 truefalse 두 가지의 값을 가질 수 있다. 일반적으로 조건부 연산[4]에 활용된다.

추가로, 불리언 값이 전달되어야 할 조건문에서 다른 자료형의 값이 전달될 경우, 불리언으로 자동으로 변환된다. 10 > 2, "True", "False", true 등은 true로 취급되고, 10 < 2, false 등은 false로 취급된다. 이외에도 여러 값이 false로 취급되나 자세한 것은 밑에서 다룬다.

4.1.4. Number 자료형

Number 자료형(Number type)
Number 자료형은 원시 값 중 하나이며, 숫자를 나타낸다. 정수와 소수(부동소수점)를 모두 포괄하며, [math(2^{-1074})]부터 [math(2^{1024})]까지의 숫자를 저장한다. 이 범위를 넘어가는 값[5]은 자동으로 변환된다.
  • Number.MAX_VALUE보다 큰 양수값: +Infinity
  • Number.MIN_VALUE보다 작은 양수값: +0
  • Number.MAX_VALUE보다 큰 음수값: -Infinity
  • Number.MIN_VALUE보다 작은 음수값: -0

참고로 NaN(Not-a-Number)도 숫자에 포함되며 NaN은 항상 자기자신과 같지 않다.

0, -0, 0.0, NaN은 Boolean으로 변환될 경우 항상 false로 취급된다.

4.1.5. BigInt 자료형

BigInt 자료형(BigInt type)
BigInt 자료형은 임의 정밀도로 정수를 나타낼 수 있는 숫자 원시 값이다. 대신 Number와 달리 소수를 나타낼 수 없다. Number.MAX_SAFE_INTEGER를 넘어가는 Number 자료형의 안전한 정수 제한을 넘어서는 큰 정수도 안전하게 저장할 수 있다.

정수 끝에 n을 추가하거나, BigInt() 함수를 호출해 생성할 수 있다.
9007199254740991n, BigInt(9007199254740991)

BigInt와 Number를 비교 연산자로 비교했을때 동등 연산자(느슨하게)로 비교하면 true, 일치 연산자(엄격하게)로 비교하면 false가 나온다.
#!syntax javascript
100n == 100 // true
100n === 100 // false

4.1.6. String 자료형

String 자료형(String type)
String 자료형은 원시 값 중 하나로, 텍스트 데이터를 나타낸다. 즉 문자의 나열이다.

String은 배열처럼 "hello"[1]을 하면, ["h", "e", "l", "l", "o"][1]과 같이 두 번째 인덱스에 있는 "e"를 꺼내오게 된다.

기본적으로 원시 값이기 때문에 String 자료형 값은 불변이다. 따라서 "나무" + "위키"를 하는 건 앞의 "나무"라는 기존의 String에 "위키"라는 String을 결합한 것이 아닌, 새 String을 만들어 "나무위키"라는 하나의 문자열을 만드는 것이다.

내용이 없고 비어있는 값은 항상 false로 취급되며, 반대로 내용이 있으면 문자열에 어떤 내용이 있던간에 항상 true가 반환된다. 따라서 "0", "False"는 true이다.

4.1.7. Symbol 자료형

Symbol 자료형(Symbol type)
Symbol 자료형은 고유하고 불변한 원시 값이며, 객체의 속성으로 사용될 수 있다. 이 자료형의 사용 목적은 다른 코드에서 만든 키와 중복되지 않음을 보장하는 새 고유한 속성 키를 만들때이다.

4.2. 객체

객체(Object)
원시 값과 달리 유일한 변경 가능한 값이다. 컴퓨터 과학에서의 객체는 식별자로 참조할 수 있는 메모리 상의 값을 말한다. 함수(Functions)도 사실 callable(호출할 수 있는)이라는 기능을 지닌 객체이다. 프로토타입이라는 개념을 갖고 있는데, 이는 JavaScript의 핵심 개념이다. 항목 참고.

5. 변수 선언

변수 선언에는 여러가지 키워드(var, let, const)가 관여되는데, 기초적인 변수 선언 방법은 총 4가지 이다.
#!syntax javascript
a = 1; // 자동 선언
var a = 1; // var 키워드 사용
let a = 1; // let 키워드 사용
const a = 1; // const 키워드 사용

5.1. 자동 선언

자동 선언
자동 선언은 키워드를 사용하지 않고 선언하는 변수이다. 브라우저 콘솔창에서 간단한 선언 용도로 사용 가능하다.
#!syntax javascript a = 1;

5.2. var 선언

var 선언
var 선언은 var 키워드를 사용해 선언하는 변수이며, 함수 범위(function-scoped), 전역 범위(globally-scoped) 변수이다. 1999년부터 사용되었지만 여러 문제로 인해서 2015년부터는 비권장으로 오래된 브라우저를 위한 레거시 문법으로써 남아있다.
#!syntax javascript var a = 1;

5.3. let 선언

let 선언
let 선언은 let 키워드를 사용해 선언하는 변수이며, 블록 범위(function-scoped) 변수이다. var 키워드의 혼란한 범위 문제 등으로 2015년 ECMAScript 6에 신규 도입된 문법이다.
#!syntax javascript let a = 1;

5.4. var 선언과 let 선언의 차이

이 차이 때문에 var 선언이 사장된 이유이기도 하다.

[ var은 중복 선언이 가능하다 ]
const처럼 재할당이 불가능하다는 것이 아니라, 키워드를 재사용해서 중복 선언이 가능하다는 뜻이다.
#!syntax javascript
var foo = "안녕";
var foo = "Hello"; // 가능함

let bar = "안녕";
let bar = "Hello"; // SyntaxError: Identifier 'b' has already been declared

이처럼 var은 키워드를 사용한 선언이 여러번 가능하지만, let은 SyntaxError 오류를 반환한다.
[ 호이스팅 ]
파일:상세 내용 아이콘.svg   자세한 내용은 호이스팅 문서
번 문단을
부분을
참고하십시오.
호이스팅은 변수의 정의가 그 범위에 따라 선언과 할당으로 분리되어 변수의 선언을 항상 컨텍스트 내(스코프 등)의 최상위로 끌어올리는 것을 의미한다. 흔히 끌어올리기라고 표현한다.

문제는 var 선언은 호이스팅이 강제로 발생해 변수를 선언하기도 전에 변수를 사용할 수 있으며, 이는 추후에 발생할 여러 오류(의도되지 않은 동작)의 주범이 된다는 것이다.
#!syntax javascript
// 코드 작성
function example() {
  console.log(test) // undefined
  var test = "Hello"
  console.log(test) // Hello
}

// JavaScript 인터프린터에 의해 자동 변환된 코드
function example() {
  var test = undefined // 호이스팅된 test 변수
  console.log(test) // undefined
  test = "Hello"
  console.log(test) // Hello
}


let 선언은 이 호이스팅 문제를 막아주는데 크게 일조하는데, 호이스팅이 안된다는 것은 아니지만 대신 ReferenceError 오류를 반환해 의도되지 않은 동작을 막을 수 있다.
#!syntax javascript
// 코드 작성
function example() {
  console.log(test) // ReferenceError: test is not defined
  let test = "Hello"
}

[ 참조 범위(유효 범위, scope)의 차이 ]

var 선언은 함수 범위, 전역 범위이다. 따라서 블록 범위에 있는 변수를 바깥 범위에서 침범할 수 있다.
#!syntax javascript
function example() {
    if (true) {
        var foo = 1;
        console.log(foo); // 1
    }
    console.log(foo); // 1
    // if(){} 블록 내에 있든지 함수 범위에서 var 선언은 유효하기 때문에 바깥에서도 접근할 수 있다.
}
console.log(foo); // ReferenceError: foo is not defined
// var 선언된 변수 foo는 함수 범위이기 때문에 전역 범위에는 침범되지 않는다.

하지만, let 선언은 블록 범위로, 함수 안이더라도 var과 달리 while(){ ... }, if(){ ... }, function(){ ... } 등 코드 블록에서 선언한 변수는 블록 내에서만 유효한 변수이며, 바깥에서 접근하려고 하면 ReferenceError가 반환되면서 선언되지 않았다고 뜬다.
#!syntax javascript
function example() {
  if (true) {
    let foo = 1;
    console.log(foo); // 1
  }
  console.log(foo); // ReferenceError: foo is not defined
  // let 선언된 변수 foo는 if ~ else 블록 내에서만 유효하므로 침범되지 않는다.
}
console.log(foo); // ReferenceError: foo is not defined

5.5. const 선언

const 선언
const 선언은 const 키워드를 사용해 선언하는 변수이며, let과 마찬가지로 블록 범위(function-scoped) 변수이다. let과 함께 2015년 ECMAScript 6에 신규 도입된 문법으로, let과는 다르게 재할당이 불가능하며, let과는 마찬가지로 중복선언이 불가능하다.
#!syntax javascript const a = 1;
let은 중복선언으로 값 업데이트가 가능하지만, const는 중복 선언 시 TypeError가 나면서 업데이트 되지 않는다. 그리고 명시적으로 변하지 않는 값이라는 것을 밝혀주어 용도를 명확히 할 수 있다.
#!syntax javascript
let a = 1;
a = 3; // 가능함

const a = 1;
a = 3; // TypeError: Assignment to constant variable.

6. 함수

#!syntax javascript
// a, b 매개변수를 더하는 함수
function sum(a, b) {
    return a + b;    
}

// sum 함수 호출
console.log("1 + 2 = ": sum(1, 2)) // 1 + 2 = 3
  • 여기서는 sum 함수가 a와 b를 매개변수로 받고, a + b 값을 반환한다. 그리고 sum 함수가 호출될 때, sum(1, 2)에서 인수로 1과 2를 주었으므로 반환값은 1 + 2로 3이 된다. 아래의 설명 참조.

6.1. 함수의 선언

#!syntax javascript
function 함수이름(매개변수1, 매개변수2, ...) {
    // <코드 내용>
}
  • 함수는 function 키워드 + 이름 + 소괄호 ( ) 순으로 선언되며, 소괄호 안에는 매개변수들이 쉼표로 구분되어 나열된다.
  • 그리고 함수가 호출되었을 때 실행할 내용은 중괄호 { } 안에 위치한다.

[ 여러가지 함수 선언 ]
위의 방법 외에도 몇 가지 선언 방법이 더 있다.

익명 함수(Anonymous function)
function(){} 형태를 객체처럼 이용하는 것이며, 변수에 대입하는 등으로 사용할 수 있다.
#!syntax javascript
const 함수이름 = function(매개변수1, 매개변수2, ...) {
  // <코드 내용>
}


화살표 함수(Arrow function)
() => {} 형태이며, 위와 같이 객체처럼 이용한다. 익명 함수와 마찬가지로 변수에 대입하는 등으로 사용할 수 있다.
#!syntax javascript
const 함수이름 = (매개변수1, 매개변수2, ...) => {
  // <코드 내용>
}

6.2. 함수의 호출

함수이름(인수1, 인수2, ...)
호출할 땐 함수 이름 + 소괄호 안 매개변수가 있는 자리에 인수값을 넣어 실행한다.

6.3. 함수의 반환

return <반환값>
함수에서 값을 반환할 때는 return 키워드를 사용한다.

7. 반복문

비슷한 코드를 계속해서 써야할 때는 아래와 같이 쓸 수도 있다.
#!syntax javascript
const num = ["1", "2", "3", "4"];
let text = "";

text += num[0]
text += num[1]
text += num[2]
text += num[3]

console.log(text) // 1234

하지만 이걸 몇 천 번 반복해야 한다면 반복문을 쓰는게 더 상식적이다.
#!syntax javascript
const num = ["1", "2", "3", "4", ..., "999", "1000"]
let text = "";

for (let i = 0; i < num.length; i++) {
    text += num[i]
}

console.log(text) // 12345...1000

7.1. for 반복문

for (표현식1; 표현식2; 표현식3;) {
    <코드 내용>
} 
  • 표현식1은 인터프리터가 for문에 진입하면 단 한번만 실행된다.
  • 표현식2는 코드 내용이 다시 반복될 지 여부 조건을 지정한다.
  • 표현식3은 코드 내용이 끝난 이후에 실행된다.

이제 표현식을 차례대로 살펴보자.
  • 표현식1

    • {{{#!syntax javascript
for (let i = 0, length = num.length; i < length; i++) {
text += num[i];
}
}}}
  • 여기서 let i = 0, length = num.length 부분이 표현식1 부분이다.
  • 표현식1 부분은 주로 for문 내에서 쓰일 변수를 선언하는 부분이며 처음 단 한번만 실행된다.
  • 아래와 같이 생략 가능하다.
    {{{#!syntax javascript
let i = 0;
let length = num.length;

// 표현식1 생략
for (; i < length; i++) {
text += num[i];
}
}}}
  • 표현식2

    • {{{#!syntax javascript
for (let i = 0, length = num.length; i < length; i++) {
text += num[i];
}
}}}
  • 여기서 i < length 부분이 표현식2 부분이다.
  • 표현식2 부분은 for문 내의 코드 실행이 끝나면 바로 실행되며 이후 반복 여부를 결정한다.
  • 표현식2를 계산한 결과값이 true면 반복하고 false면 for문을 끝낸다.
  • 생략 가능하다.
  • 표현식3
    {{{#!syntax javascript
for (let i = 0, length = num.length; i < length; i++) {
text += num[i];
}
}}}
  • 여기서 i++ 부분이 표현식3 부분이다.
  • 표현식3 부분은 코드 실행이 끝나면 바로 실행되며, 주로 표현식1에서 선언된 변수를 늘리는 코드를 넣는다.
  • 생략 가능하다.

7.2. while 반복문

while 반복문은 아래와 같은 형식으로 작성한다.
while (실행조건) {
  <코드 내용>
} 

while 반복문의 실행 조건 설명은 아래와 같다.
#!syntax javascript
let i = 0;
let array = [];
while (i < 5) {
    array.push(i);
    i++;
}
console.log(array) // [0, 1, 2, 3, 4]
위 예제는 반복문이 돌면서 그 반복 주기의 i를 array에 추가한다.

여기서 while문은 실행조건인 i < 5를 처음 시작할 때와 코드 내용이 끝나면 검사하고 참(true)이라면 계속 반복한다.
#!syntax javascript
while (true) {
    console.log("foo")
}

만약 실행조건이 계속 true라면 무한 반복도 또한 가능하다.

7.3. do-while 반복문

do {
  <코드 내용>
} while (실행조건)
위의 while 반복문과는 달리 처음에 do 안의 코드를 실행한 후 실행조건을 검사한다.

따라서 아래와 같은 코드도 가능하다.
#!syntax javascript
while (false) {
    console.log("hello")
} // hello가 뜨지 않는다.

do {
    console.log("hello")
} while (false) // hello가 실행된다.

while문에서는 처음 실행조건이 항상 false이므로 코드를 건너뛰게 된다.

하지만 do-while문에서는 실행조건이 항상 false더라도 do를 먼저 실행한 후 검사하기 때문에 한 번 실행된 후 반복문이 종료된다.

8. 클래스

#!syntax javascript
class 클래스명 {
    constructor(매개변수1, 매개변수2, ...) {
        // 생성자 코드
    }
    메소드명() {
        // 메소드 코드
    }
}
  • 기본적으로 class 클래스명 + 중괄호, 그리고 안에 생성자(constructor)와 메소드들이 들어간다.
  • 처음 인스턴스를 생성했을때 생성자 내에 있는 코드가 실행된다.

ES6이 들어서면서 JavaScript에도 클래스라는 개념이 생겼다. ES5까지는 객체의 프로토타입이란 걸 클래스 대용으로 썼었다 그러나 엔진 차원에서는 ES5식의 프로토타입으로 변환되어 처리되기에 클래스는 프로토타입의 추상화로 볼 수 있다. 따라서 문법적 설탕(Syntax sugar)이라는 비판도 받는다.

8.1. 객체의 프로토타입

프로토타입(Prototype)
다른 객체에 대한 연결을 나타내는 객체의 비공개 속성

클래스를 알기 전에 JavaScript의 프로토타입이라는 개념을 알아야 한다. 이는 객체 지향 프로그래밍의 상속과 관련이 있다. 여기에는 프로토타입 체인(Prototype chain)이라는 개념이 들어가는데, 서로 다른 객체가 체인으로 묶여있는 상황을 상상해보면 된다.

[속성 상속](Property inheritance)
객체의 속성을 상속하는 것이다. 상속은 다음과 같이 이뤄진다.
#!syntax javascript
const 부모 = { 나: 3, 다: 4 };
// 프로토타입 체인을 이용해서 부모가 상속되었다.
const 자식 = { 가: 1, 나: 2, __proto__: 부모 };

console.log(자식.다) // 4 (부모의 속성 "다"의 값)

더 확장해서 알아보자. 다음과 같은 코드를 참고하자.
#!syntax javascript
const 객체 = {
    가: 1,
    나: 2,
    // __proto__는 [[Prototype]]을 설정한다.
    __proto__: {
        나: 3
        다: 4
    }
}

console.log(객체.가) // 1
console.log(객체.나) // 2
console.log(객체.다) // 4
console.log(객체.라) // undefined
  • 객체에서 가를 꺼냈을때는 객체 자신에게 "가"라는 속성이 있기 때문에 자신의 속성에서 "가"의 값인 1을 꺼내온다.
  • 객체에서 나를 꺼냈을때도 역시 자신에게 "나"라는 속성이 있기 때문에 자신의 속성에서 "나"의 값인 2를 꺼내온다. 이 상황에서는 객체.[[Prototype]]에 있는 "나"는 꺼내오지 않는다. (우선순위)
  • 객체에서 다를 꺼내려고 할 때 자신에게 "다"라는 속성이 있는지 찾는다. 하지만 객체에는 "다"라는 속성이 없기에, 이번엔 객체.[[Prototype]]으로 접근한다. 여기에는 "다"라는 속성이 있다. 따라서 객체.[[Prototype]]에 있는 "다"의 값인 4를 꺼내온다.
  • 객체에서 라를 꺼내려고 할 때 자신에게 "라"라는 속성이 있는지 찾는다. 하지만 객체에는 "라"라는 속성이 없다. 따라서 객체.[[Prototype]]으로 접근했지만, 여기에도 "라"라는 속성을 찾을 수 없다. 이 프로토타입의 프로토타입(객체.[[Prototype]].[[Prototype]])에 접근하려고 하지만 이제는 프로토타입 자체가 null prototype이기 때문에 프로토타입 체인이 끊겨 더 이상 속성을 찾을 수 없다. 따라서 undefined를 반환한다.

이처럼 객체 내부에 프로토타입을 설정할 수 있으며, 이 프로토타입은 체인으로 연결되어, 프로토타입으로 null을 가진 객체에 도달할때까지 계속된다.[6] 위에서는 다음과 같은 체인이 사용되었다.
<rowcolor=#fff> 구분 객체 객체.[[Prototype]] 객체.[[Prototype]].[[Prototype]] 객체.[[Prototype]].[[Prototype]].[[Prototype]]
<colcolor=#fff><colbgcolor=#c9a600> 코드
#!syntax javascript
{
    가: 1,
    나: 2,
    __proto__: {
        나: 3
        다: 4
    }
}
#!syntax javascript
{
    나: 3
    다: 4
    // 실제로는 __proto__를 명시하지 않는다.
    __proto__: Object.prototype
}
Object.prototype[7] null[8]
객체의 속성 { 가: 1, 나: 2 } { 나: 3, 다: 4 } { } null

[생성자](Constructor)
위에 설명한 강력한 프로토타입 기능을 이용해 생성자를 이용한 클래스를 구현할 수 있었다.(~ES5) JavaScript에서는 원시 값을 제외한 모든 데이터가 객체로 분류되기 때문에, 객체인 함수를 이용해서 클래스를 구현할 수 있다.
#!syntax javascript
function 사람(이름) {
    this.이름 = 이름
}
사람.prototype.자기소개 = function(){
    console.log("안녕하세요! 저는", this.이름, "입니다!");
}
const 홍길동 = new 사람("홍길동");
홍길동.자기소개() // 안녕하세요! 저는 홍길동 입니다!

이렇게 new를 붙여 함수를 실행하면, 생성자가 실행되어 실제로 홍길동이라는 상수는 사람이라는 "클래스"의 "인스턴스"가 된 듯 동작한다. 그리고 prototype의 속성인 자기소개는 "메소드"처럼 작동된다.
여기서 특이한 점은 인스턴스의 프로토타입은 모두 공유되어 생성자로 인스턴스가 생성된 후에도 프로토타입이 변하면 그 변경 사항이 반영된다.
#!syntax javascript
function 사람(이름, 나이) {
    this.이름 = 이름;
    this.나이 = 나이;
}
사람.prototype.말하기 = function(){
    console.log("이름:", this.이름);
}
// 인스턴스 생성
const 홍길동 = new 사람("홍길동", 21);
// 말하기 프로토타입 속성이 덮어씌워짐
사람.prototype.말하기 = function(){
    console.log("나이:", this.나이)
}
// 생성 후에 변경되었음에도 변경 사항이 반영됨.
홍길동.말하기() // 나이: 21

8.2. 클래스의 구성

생성자(Constructor)
#!syntax javascript
class 클래스 {
    constructor(매개변수1, 매개변수2, ...) {
        // 생성자 코드
    }
}

생성자는 인스턴스를 생성하고 클래스 필드를 초기화하기 위한 특수한 메서드이다. new 키워드를 앞에 사용하면 생성자가 실행된다. 그리고 클래스 당 1개의 생성자만이 존재할 수 있다.

속성(Property)
#!syntax javascript
class 사람 {
    이름="홍길동" // A
    constructor(이름, 나이) {
        // B
        this.이름 = 이름;
        this.나이 = 나이;
    }
}
  • A처럼 이름="홍길동"의 형태로 클래스 내부에서 직접 속성을 선언할 수 있다.
  • B처럼 인스턴스를 지칭하는 this.속성 꼴의 형태를 사용해 직접 속성을 집어넣는 방식이 있다.

메서드(Method)
#!syntax javascript
class 사람 {
    constructor(이름) {
        // B
        this.이름 = 이름;
    }
    자기소개() {
        console.log("제 이름은", this.name)
    }
    ["테스트"]() {
        console.log("Hello World!");
    }
}
new 사람("홍길동").자기소개() // 제 이름은 홍길동

function 없는 함수의 형태로 메서드를 선언할 수 있다. 이때 객체 리터럴 문법을 사용해 문자열을 이용해 메서드 이름을 지정해 선언할 수 있다.

8.3. 객체 지향

8.3.1. Getter/Setter

Getter/Setter
#!syntax javascript
class 사람 {
    constructor(이름) {
        this._이름 = 이름;
    }
    set 이름(값) {
        this._이름 = 값
    }
    get 이름() {
        return this._이름
    }
}
const 홍길동 = new 사람("홍길동")
홍길동.이름 = "김길동" // setter인 이름 호출
홍길동.이름 // getter인 이름 호출, 김길동 출력

메서드 이름 옆에 set과 get을 붙여주는 것으로 getter와 setter를 사용할 수 있다. 대신 동시에 사용해야 하며, getter와 setter는 같은 이름이여야 하고, setter는 변경하려는 속성 이름이 setter의 이름과 같으면 안된다. 예를 들어, 다음과 같은 코드를 보자.
#!syntax javascript
class 사람 {
    constructor(이름) {
        this.이름 = 이름;
    }
    set 이름(값) {
        this.이름 = 값 // setter인 이름 호출 (무한 반복) (B)
    }
    get 이름() {
        return this.이름
    }
}
const 홍길동 = new 사람("홍길동")
홍길동.이름 = "김길동" // setter인 이름 호출 (A)

위 코드에서는 속성과 setter의 이름을 같게 했다. 하지만 이는 무한 반복을 일으키게 되는데,
  • A에서는 setter인 "이름"을 호출해 "김길동"을 매개변수인 값으로 보냈다.
  • B에서 값인 "김길동"을 이름으로 설정하려고 했는데, 이 this.이름 = 값의 형태는 다시 setter인 "이름"을 호출하는 형태이며, B를 무한히 반복하게 된다.

8.3.2. 정적 메서드

정적 메서드(Static method)
클래스의 인스턴스화 없이 사용할 수 있는 메서드이다. 가령 Math.random()과 같은 메서드는 아래와 같이 구현된 정적 메서드이다. 정적 메서드는 생성자를 호출할 필요가 없으며 클래스명.메서드명으로 사용할 수 있다. 그리고 인스턴스에선 정적 메서드를 불러오지 못한다.

#!syntax javascript
// 표준 내장 객체인 Math
class Math {
    static random() {
        // 랜덤 생성
    }
}

8.3.3. Private 메서드

Private 메서드(Private method)
클래스의 은닉 기능을 사용할 수 있다. 앞에 #을 붙이면 private화된다. 바깥에서는 클래스 내부의 private 속성/메서드에 접근하지 못하고, 안에서는 접근 가능하다.
#!syntax javascript
class Potato {
    #isPoison = true;

    constructor() {}
    #checkPoison() {
        return this.#isPoison
    }
    publicCheckPoison() {
        return this.#checkPoison()
    }
}
const potato = new Potato();
console.log(potato.isPoison) // undefined
console.log(potato.checkPoison()) // Uncaught TypeError: potato.checkPoison is not a function
console.log(potato.publicCheckPoison()) // true
  • potato.isPoison은 private 속성이다. 따라서 접근하지 못했으므로 undefined.
  • potato.checkPoison()은 private 메서드이다. 따라서 접근하지 못했으므로 undefined인데, undefined를 호출했으므로 TypeError가 뜬다.
  • potato.publicCheckPoison()은 public 메서드이다. 따라서 정상적으로 작동한다.

8.3.4. 상속

상속(Inheritance)
상속을 통해 한 클래스의 기능을 다른 클래스에서 재사용할 수 있다. class 클래스명 extends (상속할 클래스명) 꼴로 선언한다.
#!syntax javascript 
class 부모 {
    // ...
}

class 자식 extends 부모 {
    // ...
}


super()

9. 논리연산자

아래와 같은 논리 연산자가 있다.
  • &&: Logical AND
  • ||: Logical OR
  • !: not
  • ==: equal

10. 표준 내장 객체

파일:상세 내용 아이콘.svg   자세한 내용은 JavaScript/문법/표준 내장 객체 문서
번 문단을
부분을
참고하십시오.

11. 관련 문서


[1] 원시 자료형(Primitive type)이라고 불리기도 한다. [2] 이 이유로 Null만 유일하게 typeof 연산자로 타입을 테스트할 수 없다. [3] 밑에서 언급할 undefined와의 차이점일 수 있다. [4] if ~ else, while, for 등 [5] ±([math(2^{-1074})]~[math(2^{1024})]) [6] 최종 링크의 역할을 한다. [7] 객체의 기본 프로토타입 값으로, 프로토타입이지만 아무 속성도 없다는 뜻이다. 즉 속성 없는 객체이며 null prototype이라고 불린다. [8] 체인이 끊겼다.