자바스크립트 완벽가이드 5장 (문장)

문장(statement), 즉 ‘문’은 자바스크립트 문장, 다시 말해 명령이다. 자바스크립트 문장은 세미콜론(;)으로 끝난다. 표현식은 어떤 값을 생성하기 위해 평가되지만, 구문은 어떤 일을 하기위해 실행되는 것이다.

5.2 복합문과 빈 문장

문장 블록은 여러 문장을 하나의 복합문으로 묶는다. 자바스크립트에는 블록 단위의 유효범위(scope)가 존재하지 않기 때문에, 구문 블록 안에 선언된 변수는 블록뿐 아니라 블록 밖에서도 접근할 수 있다.

자바스크립트 문법은 대체로 하나의 하위문을 허용한다. 예를 들어, while 루프 문법은 루프 몸체로 하나의 문장을 허용한다. 문장 블록을 사용하면 문법이 허용하는 하나의 하위문 자리에 얼마든지 많은 문장을 넣을 수 있다.

결과적으로 복합문은 자바스크립트 문법에서 하나의 문장이 있어야 할 곳에 여러 문장을 사용할 수 있게 한다. 빈문장은 정 반대다. 하나의 문장이 있어야 할 곳에 아무런 문장도 두지 않을 수 있도록 한다. 빈 문장은 ;을 사용하여 표현한다. 임의로 빈 문장을 사용할 경우에는, 코드에 고의로 사용했다는 설명을 주석으로 표시하는 것이 좋다.

5.3 선언문

5.3.1 var

var문은 하나 또는 그 이상의 변수를 선언한다. var문에서 변수에 초기 값을 지정하지 않으면 변수의 초기 값은 undefined가 된다. 스크립트나 함수 안에서 선언된 변수는 해당 스크립트나 함수 전체에 걸쳐 유효하다. 하지만 초기화된 var문이 선언된 시점에서 발생하고, 그 전까지는 변수 값은 undefined가 된다.

5.3.2 function

함수 선언문은 자바스크립트 최상위 단계 코드에서 나타날 수도 있고, 다른 함수 내에 중첩될 수도 있다. 하지만 함수가 다른 함수 속에 중첩될 때는, 중첩된 함수 내에서 최상위 단계에 위치해야 한다. 즉, 함수 선언은 if문이나 while문 등의 다른 문장 안에 있을 수 없다.

**함수 선언문**은 함수 이름을 포함한다는 점에서 **함수 정의표현식**과는 차이가 있다. 둘 다 새 함수 객체를 만들지만, 함수 선언문은 함수 이름을 변수로 선언한 후 이 변수에 함수 객체를 할당한다는 차이가 있다. var로 선언한 변수와 같이, 함수 선언문으로 정의된 함수는 스크립트나 함수 유효범위 최상단에 위치하게 되어(hoisted) 해당 유효범위 내에서 사용할 수 있다. var 문을 이용하면 변수 선언만 유효범위 최상단으로 끌어올려지지만(변수 초기화 코드는 원래 위치에 그대로 유지), 함수 선언문을 이용하면 함수의 이름과 본문 모두 유효범위 최상단으로 끌어올려진다. 이때 스크립트 내의 모든 함수 또는 함수의 중첩 함수는 다른 코드가 실행되기 전에 선언된다. 이는 자바스크립트 함수를 호출하는 코드가 선언문이 나오기 전에도 올 수 있다는 뜻이다.

5.4 조건문

5.4.1 if

대다수의 프로그래밍 언어와 마찬가지로 자바스크립트 규칙에 의하면 else 절은 기본적으로 가장 가까운 if문에 속한다. 모하함을 없애고 읽기 쉽고 이해하기 쉬운 동시에 유지보수와 디버깅을 쉽게 하려면 반드시 중괄호를 사용해야 한다.

5.4.3 switch

switch문은 if문에서처럼 동일한 표현식이 여러 번 반복되는 문제점을 확실히 해결한다. 다음은 실용적인 switch 문의 예제이다. 이 예제에서는 어떤 값을 문자열로 바꾸는데, 그 값의 타입에 따라 각기 다른 방법을 적용해 문자열로 변환한다.

1
2
3
4
5
6
7
8
9
10
function convert(x) {
switch(typeof x) {
case 'number': // 주어진 숫자를 16진수 정수로 변경한다.
return x.toString(16);
case 'string': // 문자열을 큰따옴표로 묶어서 반환한다.
return '"' + x + '"';
default: // 이 외의 타입은 문자열로 변환한다.
return String(x);
}
}

switch문이 실행될 때마다 모든 case 표현식이 매번 평가되지는 않기 때문에, case 표현식에 함수 호출이나 값 할당과 같이 부수 효과를 일으킬 수 있는 표현식을 사용해서는 안된다. 가장 안전한 방법은 case 표현식을 상수 표현식만으로 제한하는 것이다. case를 판별할 때는 동치 연산자 ==가 아닌 **일치 연산자 ===**가 사용된다.

5.5 루프

자바스크립트에는 네 개의 루프문이 있다.

  1. while
  2. do/while
  3. for
  4. for/in

5.5.4 for/in

for/in문은 for 키워드를 사용하지만, 일반적인 for 루프와는 전혀 다른 종류다.

1
2
for (변수 in 객체)
문장

‘변수’는 보통 변수 이름이지만 좌변 값으로 평가되는 표현식이거나, 단일 변수를 선언하는 var문일 수도 있다. ‘객체’는 객체로 평가되는 표현식이어야 한다. ‘문장’은 루프 몸체를 구성하는 문장 또는 문장 블록이다.
일반적인 for 루프를 사용하면 다음과 같이 배열의 원소를 쉽게 순회할 수 있다.

1
2
for(var i = 0; i < a.length; i++)
console.log(a[i]);

이와 비슷하게 for/in 루프를 사용하면 객체가 가진 프로퍼티들을 쉽게 순회할 수 있다.

1
2
3
for(var p in o) {       // 변수 p에 객체 o가 가진 프로퍼티 이름을 할당한다.
console.log(o[p]);
}

for/in문을 실행하기 위해서 자바스크립트 인터프리터는 먼저 객체 표현식을 평가한다. 이때 표현식이 null이나 undefined로 평가되면 인터프리터는 해당 루프를 중단하고 다음 문장을 실행한다. 만약 표현식이 원시 값으로 평가되면 해당 값은, 값과 상응하는 Wrapper 객체로 바뀐다. 이 외에 표현식은 객체로 평가된다.

for/in 루프에서 사용하는 ‘변수’로는 할당 표현식의 좌변에 적합한 무언가로 평가되는 임의의 표현식을 사용할 수 있다. 이 표현식은 루프가 돌 때마다 평가되는데, 이때 매번 다르게 평가될 수 있다. 다음과 같은 코드를 사용하면 주어진 객체의 모든 프로퍼티 이름을 배열에 복사할 수 있다.

1
2
3
var o = {x:1, y:2, z:3};
var a = [?], i = 0;
for(a[i++] in o) /* 비어 있음 */;

자바스크립트 배열은 단순히 특별한 종류의 객체에 지나지 않는다. 따라서 for/in 루프는 객체의 프로퍼티와 마찬가지로 배열 인덱스 또한 하나씩 열거할 수 있다.

for/in 루프는 실제로 객체가 가진 모든 프로퍼티를 열거하지 않고 오직 ‘열거 할 수 있는 프로퍼티’만 열거한다. 자바스크립트 코어에 정의된 다양한 내장 메서드들은 일반적으로 열거할 수 없다. (예를 들면 toString() 메서드)

5.6 점프문

5.6.4 return

함수를 호출하는 것 역시 표현식이고, 모든 표현식에는 값이 있다. return문은 함수 호출 표현식의 값, 즉 함수에서 반환하는 값을 지정하는 데 쓰인다. return문은 오직 함수 몸체 내부에서만 나타날 수 있다. 다른 곳에서 사용하면 문법 에러가 발생한다. return문이 실행되면 ‘표현식’이 평가되어 그 결과가 함수의 값으로 반환된다. 함수 내에 return문이 없다면 함수 호출은 단지 함수 몸체의 끝에 도달할 때까지 모든 구문을 차례로 실행하고, 호출한 지점으로 돌아간다. 이 경우에 해당 함수 호출 표현식의 값은 undefined가 된다. return문은 주로 함수의 마지막에 위치하지만 반드시 마지막에 있어야 하는것은 아니며, 함수 몸체 내에서 return문이 실행되면 아직 남은 문장들이 있어도 함수를 호출한 지점으로 돌아간다.

5.6.5 throw

자바스크립트에서는 런타임 에러가 일어날 때마다 예외를 발생시킨다. Error 객체는 에러의 종류를 담고 있는 name 프로퍼티와 Error 클래스 생성자 함수에 넘기는 문자열 값을 담고 있는 message 프로퍼티를 갖고 있다.

예외가 발생하면 자바스크립트 인터프리터는 정상적인 프로그램 실행을 즉시 중단하고 가장 가까운 예외 처리기로 넘어간다. 예외를 발생시킨 코드 블록이 catch절과 연결되어 있지 않으면, 인터프리터는 바로 상위 단계를 감싸고 있는 코드 블록에 연결된 예외 처리기가 있는지 확인한다. 이 과정은 처리기를 찾을 때까지 계속된다. 이같은 방법으로 자바스크립트의 언어적인 구조를 따라서, 즉 호출 스택을 따라서 예외가 전파되어 올라간다. 예외 처리기를 찾을 수 없는 경우 해당 예외는 에러로 취급되고 사용자에게 보고된다.

5.6.5 try/catch/finally

  • try : 단순히 예외가 발생할지도 모르는 코드 블록을 정의하는 역할
  • catch : try 블록 내부에서 예외가 발생할 경우 호출되는 문장 블록
  • finally : try 블록에서 일어난 일에 관계없이 항상 실행이 보장되어야 할 뒷정리용 코드가 포함

정상적인 경우에, 자바스크립트 인터프리터는 try 블록의 끝까지 도달하고 난 후, finally 블록으로 이동해 무언가 필요한 뒷정리를 수행한다. 만일 인터프리터가 return, continue, break 문 등을 만나 try 블록의 제어를 벗어날 경우, 새 지점으로 이동하기 전에 finally 블록이 실행된다.

만일 예외를 처리할 catch 블록이 없다면 인터프리터는 일단 finally 블록을 실행한 후 상위 블록으로 예외를 전파하여, 해당 예외를 처리할 수 있는 가장 가까운 catch 절로 이동한다.

5.7 기타

5.7.1 with

with문은 유효범위 체인의 첫 번째에 ‘객체’를 추가한다. 그 후에 ‘문장’을 실행한 다음, 유효범위 체인을 ‘객체’를 추가하기 전 상태로 되돌려 놓는다. with문을 사용하는 자바스크립트 코드는 최적화하기 힘들고 with문을 사용하지 않는 코드에 비해 느리기 때문에 사용하지 않는것이 좋다.

5.7.2 debugger

debugger문은 평소에는 아무것도 하지 않지만 디버거 프로그램을 사용할 수 있고 디버거가 실행 중일 때, 자바스크립트 구현체는 해당 위치에서 정의된 코드 디버깅을 수행한다. debugger문은 코드의 중단점(breakpoint)와 같이 동작한다. 자바스크립트 코드의 실행을 잠시 멈추고 디버거 프로그램을 사용해 변수의 값을 출력할 수 있고, 호출 스택등을 살펴볼 수 있다.

5.7.3 “use strict”

use strict'는 ECMAScript 5에서 처음 소개된 지시어다. ‘use strict’ 지시어를 사용하는 목적은 지시어 다음에 오는 (스크립트나 함수의) 코드들이 엄격 모드를 따르게 하기 위해서다. 스크립트의 최상단에 ‘use strict’ 지시어가 있으면 최상단(함수가 아닌) 코드는 엄격한 코드(엄격 모드를 따르는 코드)다.

엄격한 코드는 엄격 모드에서 실행된다. ECMAScript 5의 엄격 모드는 언어의 일부 기능이 제한된 부분 집합으로, 몇 가지 주용한 언어적 문제점을 수정하고 강력한 에러 검사와 향상된 보안 기능을 제공한다. 다음과 같은 부분이 일반 모드와 다르다.

  • with문은 엄격 모드에서 사용 불가능 하다.
  • 엄격 모드에서 모든 변수는 반드시 선언되어야 한다. 선언되지 않은 변수나 함수, 함수 인자, catch 절 인자, 전역 객체 프로퍼티에 값을 할당하는 경우 ReferenceError 예외가 발생한다.
  • 엄격 모드에서 함수는 메서드로 호출된 것이 아닌, 함수로 호출된 함수의 this 값은 undefined다. (표준 모드에서는 함수가 함수로 호출될 때 항상 전역 객체를 this의 값으로 넘겨주게 된다.) 또한 엄격 모드에서는 함수를 **call()**이나 **apply()**로 호출하면, this의 값은 정확히 call()이나 apply() 함수의 첫 번째 인자 값으로 설정된다. (표준 모드에서는 null과 undefined 값은 전역 객체로 대체되고, 객체가 아닌 값들은 객체로 바뀌게 된다.)
  • 엄격 모드에서 함수의 arguments 객체는 함수에 전달된 값의 정적 사본을 갖고 있지만 표준 모드에서 arguments 배열의 원소와 함수의 전달인자는 동일한 값을 참조한다.

출처 : “JavaScript: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4”

자바스크립트 완벽가이드 3장 (타입, 값, 변수)

자바스크립트의 타입은 크게 원시 타입(promitive type)객체 타입(object type)으로 나뉜다. 원시타입에는 숫자, 텍스트의 나열, 불리언 진리 값이 있다.
자바스크립트에서 null과 undefined는 원시값이긴 하지만, 숫자도 아니고, 문자열이나 불리언도 아니다. null과 undefined는 자기 자신만을 값으로 갖는 독립적인 타입이다. 숫자와 문자열, 불리언, null, undefined 외의 값은 객체다. 객체는 이름과 값을 갖는 프로퍼티의 집합이다.

자바스크립트에서는 함수도 특별한 객체이다. 함수는 값이고, 자바스크립트 프로그램은 함수를 보통 객체처럼 다룰 수 있다.

클래스는 객체 타입의 하위 타입으로 생각할 수 있다. 코어 자바스크립트에서는 Array와 Function 클래스 뿐만 아니라 세 개의 다른 유용한 클래스들을 정의하고 있다.

  • Date : 날짜를 표현하는 객체를 정의
  • RegExp : 정규 표현식을 표현하는 객체를 정의
  • Error : 자바스크립트 프로그램에서 발생할 수 있는 문법과 런타임 에러를 표현하는 객체를 정의

자바스크립트 인터프리터는 메모리 관리를 위해 자동으로 **가비지 컬렉션**을 수행한다. 프로그램이 필요할 때 객체를 생성할 수 있고, 프로그래머는 이 객체를 어떻게 해제할지 걱정할 필요가 없다. 객체에 더 이상 접근할 수 없을 때(프로그램이 더 이상 객체를 참조하지 않을 때) 인터프리터는 그 객체를 자동으로 메모리에서 해제한다.

자바스크립트는 객체 지향 언어다. 다양한 타입의 값을 다루는 전역 함수를 정의해두기보다, 어떠한 값과 작동하는 메서드를 그 값의 타입에 정의해둔다는 말이다. 예를 들면, 배열의 원소들을 정렬할 때는 배열 a를 sort() 함수에 인자로 전달하는 것이 아니라 a의 sort() 메서드를 호출하여 정렬하는 것이다. null과 undefined를 제외하고는 모두 메서드를 가질 수 있다.

3.1 숫자

다른 프로그래밍 언어들과는 다르게 자바스크립트는 정수 값과 실수 값을 구분하지 않는다. 자바스크립트에서는 모든 숫자를 실수로 표현한다.

3.1.3 산술 연산

자바스크립트의 산술 연산은 오버플로와 언더플로, 0으로 나누는 에러를 발생시키지 않는다. 산술 연산의 결과가 표현할 수 있는 가장 큰 수보다 더 크다면(오버플로) Infinity라고 표현하는 무한대의 값을 출력한다. 음의 무한대가 되면 이 값을 -Infinity로 출력한다. 언더플로는 산술 연산의 결과가 표현할 수 있는 가장 작은 값보다 더 0에 가까울 때 발생한다. 이런 경우 자바스크립트는 0을 돌려준다.

자바스크립트에서 0으로 나누는 연산은 에러가 아니다. 이런 경우 무한대 또는 음의 무한대가 반환된다. 그러나 0을 0으로 나누는 것은 정의되지 않은 값을 갖고, 그 결과로 숫자가 아닌 특수한 값을 가진다. 자바스크립트에서는 이러한 값을 NaN으로 출력한다. (ECMAScript 5에서는 Infinity와 NaN을 읽기 전용 값으로 정의한다.) Number객체에는 Inifiny와 NaN이 따로 상수로 정의되어 있다.

자바스크립트에서 NaN은 그 자신뿐만 아니라 다른 값과 같은지 비교 할 수 없다. 변수 x가 NaN인지 판단하기 위해 x === NaN 문을 작성할 수 없고, 대신 x != x 라고 작성해야 한다. isNaN() 함수가 이러한 경우에 유용하게 사용할 수 있다. 이 함수는 인자가 NaN이거나, 문자열이나 객체처럼 숫자가 아니라면 참을 반환한다.

3.1.4 이진 부동소수점과 반올림 오류

무한히 많은 실수가 있지만 자바스크립트에서는 한정된 숫자만 부동소수점 형태로 표현할 수 있다. 자바스크립트에서 사용하는 IEEE-754 부동소수점 표현 방식은 1/2, 1/8, 1/1024 같은 분수를 정확하게 표현 할 수 있는 이진 표현법이다. 하지만 가장 많이 사용하는 분수는 10진수 분수인데, 이진 표현법으로는 0.1과 같은 간단한 값도 정확하게 표현 할 수 없다.
따라서 다음과 같은 상황이 발생한다.

1
2
3
4
5
var x = .3 - .2;        // 0.3 - 0.2
var y = .2 - .1; // 0.2 - 0.1
x == y // => false: 두 값은 같지 않다.
x == .1 // => false: 0.3 - 0.2는 0.1이 아니다.
y == .1 // => true: 0.2 - 0.1은 0.1과 같다.

이진 부동소수점 숫자를 사용하기 때문에 발생하는 현상이다. 계산된 값은 대부분 적절하지만, 값들을 동등 비교할 경우에 문제가 발생한다.

3.1.5 날짜와 시간

날짜와 시간을 표현하는 Date 객체를 사용한다. Date 객체는 숫자 같은 원시 타입이 아니다.

3.2 텍스트

문자열(string)은 16비트 값들이 연속적으로 나열된 변경이 불가능한 값으로, 각 문자는 유니코드 문자로 표현된다. 문자열의 길이 값은 문자열에 들어 있는 16비트 값의 개수다.

자바스크립트는 유니코드 문자열 집합으로 UTF-16을 사용한다. 유니코드 문자는 16비트에 적합한 코드 포인트를 갖고 있고, 문자열의 한 문자로 표현할 수 있다. 16비트로 표현할 수 없는 유니코드는 UTF-16 규칙에 따라 두 개의 16비트 값으로 인코딩한다. 따라서, 자바스크립트에서는 길이가 2인 문자열이 하나의 유니코드 문자를 표현하는 경우도 있다.
문자열을 다루는 다양한 메서드는 문자를 다루는게 아니라 문자의 16비트 값을 다룬다.

3.2.3 문자열 다루기

자바스크립트에서 문자열은 변경되지 않는다. replace()와 toUpperCase() 같은 메서드는 기존 문자열을 변경하지 않고 새문자열을 반환한다. 즉, 문자열 관련 메서드는 호출 시에 기존 문자열을 수정하지 않는다. ECMAScript5에서 문자열은 읽기 전용 배열처럼 취급될 수 있고, 대괄호 대신 charAt() 메서드를 사용해도 문자열의 개별 문자(16비트 값)에 접근할 수 있다.

3.2.4 패턴 매칭

자바스크립트는 문자 패턴을 나타내는 객체를 생성하기 위해 RegExp() 생성자를 정의한다. 이 패턴은 정규 표현식이라 부르며, 자바스크립트는 정규 표현식을 위해 펄(Perl)의 구문을 따른다. 문자열과 RegExp 객체는 모두 패턴 매칭과 ‘검색 후 바꾸기’기능을 수행하는 메서드를 갖고 있다. RegExp는 자바스크립트의 원시 타입이 아니다. Date 객체처럼 RegExp는 유용한 API를 갖고 있는 특별한 종류의 객체다.
한 쌍의 슬래시 사이에 있는 문자열은 정규 표현식 리터럴을 구성하고, 한 쌍의 슬래시 중 두 번째 슬래시 뒤에는 하나 혹은 그 이상의 문자가 뒤따라 올 수 있는데, 이것은 패턴의 의미를 수정할 수 있다.

RegExp 객체에는 유용한 메서드들이 정의되어 있다. 또한 문자열은 RegExp 객체를 인자로 갖는 메서드들을 갖고 있다.

1
2
3
4
5
6
7
var text = "testing: 1, 2, 3";      // 간단한 문자열
var pattern = /\b+/g // 하나 이상의 모든 숫자와 일치
pattern.test(text); // => true: 일치하는 문자열이 존재
text.search(pattern); // => 9: 첫 번째로 매치하는 문자열의 위치
text.match(pattern); // => ["1", "2", "3"]: 일치된 항목의 배열
text.replace(pattern, "#"); // => "testing: #, #, #"
text.split(/\D+/); // => ["", "1", "2", "3"]: 숫자가 아닌 문자(열)를 기준으로 분할

3.3 불리언 값

자바스크립트의 어떤 값이든 불리언 값으로 변환될 수 있다. 다음은 모두 불리언 false 값으로 변한다.

  • undefined
  • null
  • 0
  • -0
  • NAN
  • “” // 빈 문자열

불리언 값은 문자열 “true” 혹은 “false”로 변환할 수 있는 toString() 메서드를 갖고 있지만 그 밖의 메서드는 갖고있지 않다.

3.4 null과 undefined

null은 보통 아무 값도 갖지 않음을 가리킬 때 사용한다. typeof 연산자를 null에 사용하면 문자열 “object”를 반환한다. 그 결과로 볼 때, null은 ‘객체가 없음’을 뜻하는 특수한 객체 값으로 생각할 수 있다. 하지만 실무에서 null은 값이 null 하나뿐인 어떤 고유한 자료형에 속한 것으로 간주하여, 객체뿐 아니라 수나 문자열 “값이 없음”을 나타내는 데도 쓰인다.

자바스크립트에는 값이 없음을 나타내는 또 다른 값, undefined가 있다. undefined는 null보다 심한 부재 상태를 나타낸다. undefined는 초기화되어 있지 않는 변수나, 존재하지 않는 객체 프로퍼티나 배열의 원소 값에 접근하려고 할 때 얻는 값이다. 또한 undefined는 반환값이 없는 함수의 반환값이고, 실 인자가 전달되지 않은 형식인자의 값이다. ECMAScript 5에서 undefined는 읽기 전용이며, typeof 연산자의 결과로 “undefined”가 반환된다. 이는 undefined가 특별한 고유의 값임을 말한다.

이러한 차이에도 불구하고 nullundefined는 둘다 값이 없음을 가리키고, 사용할 때 서로 바꿔 사용할 수도 있다. 동치 연산자 ==를 null과 undefined에 사용하면 두 값이 같다고 간주하며 엄격한 동치 연산자 ===는 다르다고 판단한다.

시스템 수준에서 예기치 않은 상황에 발생한, 오류성 값 부재를 표현할 때는 주로 undefined를 사용하고, 일반적인 프로그램 수준에서 일반적으로, 또는 예상 가능한 값 부재 상황을 표현하고 싶을 때는 null을 사용한다. 만약 이들 값 중 하나를 변수나 프로퍼티에 할당할 필요가 있거나 함수에 인자로 전달할 필요가 있다면, undefined보다는 null을 사용하는게 적절하다.

3.6 래퍼(wrapper) 객체

자바스크립트 객체는 복합적인 값이다. 객체는 프로퍼티 또는 이름 있는 값들의 집합이다. 프로퍼티의 값이 함수일 때, 그 함수를 메서드라 부른다.

문자열의 프로퍼티를 참조하려 할 때, 자바스크립트는 new String()를 호출한 것처럼 문자열 값을 객체로 변환한다. 이 객체는 문자열 메서드를 상속하며, 프로퍼티 참조를 살펴보는 데 사용한다. 일단 프로퍼티 참조가 해제되면 새로 생성된 임시 객체는 메모리에서 회수된다.

숫자와 불리언은 문자열과 같은 이유로 메서드를 갖고 있다. 임시 객체는 Number() 혹은 Boolean() 생성자를 통해 만들어지고, 메서드는 임시 객체를 통해 호출된다.

1
2
3
var s = "test";
s.len = 4;
var t = s.len;

위의 코드를 실행시 t의 값은 undefined이다. 2행은 생성된 임시 String 객체의 len 프로퍼티에 4를 할당한다. 그리고 임시 객체는 바로 삭제된다. 3행은 기존 문자열 값과 같은 값을 가진 새로운 String 객체를 생성하고 len 프로퍼티를 읽으려고 하지만 존재하지 않아 undefined를 출력한다. 값을 할당하는 것은 임시 객체에서 수행되며, 지속되지 않는다.

문자열, 숫자, 불리언의 프로퍼티에 접근하려고 할 때 생성되는 임시 객체래퍼(wrapper) 객체로 알려져 있다. 문자열과 숫자, 불리언 값의 프로퍼티는 읽기 전용이고, 이 값들에 새로운 프로퍼티를 정의할 수 없다는 점에서 이 값들이 객체와 다르다는 사실을 알아야 한다.

String()과 Number(), Boolean() 생성자를 사용해 명시적으로 래퍼 객체를 생성할 수도 있다. 자바스크립트는 래퍼 객체를 필요에 따라 기본 타입으로 변환한다. == 동치 연산자는 값과 그 값의 래퍼 객체를 동등하게 다루지만 === 엄격한 동치 연산자로 이를 구별할 수 있다. (typeof 연산자는 기본 타입과 래퍼 객체의 차이점을 보여줄 수 있다.)

#3.7 변경 불가능한 원시 타입 값과 변경 가능 객체 참조
자바스크립트에서 원시 타입(undefined, null, 불리언, 숫자, 문자열) 값객체(배열과 함수를 포함한) 사이에는 근본적인 차이점이 있다. 원시 타입의 값은 수정할 수 없다는것이다. 문자열 같은 경우 문자열을 수정하는 모든 문자열 메서드는 새로운 문자열을 반환한다. 원시 타입은 값으로 비교된다. 두 값은 같은 값이어야만 같다. 문자열 같은 경우 서로 다른 문자열 값을 비교할 때, 자바스크립트는 두 문자열의 길이가 같고 각 인덱스에 있는 문자들이 같다면 두 문자열을 같다고 판단한다.

객체는 원시 타입과는 다르다. 객체는 자신의 값을 변경할 수 있다. 객체는 값으로 비교되지 않는다. 두 객체가 같은 프로퍼티와 값을 가지고 있어도 두 객체는 같지 않다. 그리고 두 배열은 같은 순서로 같은 원소를 갖고 있어도 같지 않다.

객체는 참조 타입(reference type)으로 불리는데, 이는 자바스크립트의 원시 타입과 구별하기 위해서다. 객체의 값은 참조다. 객체는 참조로 비교될 수 있다. 두 객체 값은 그들이 같은 객체를 참조하면 같다. 객체는 새로운 복사본을 생성하지 않기 때문에 객체 혹은 배열의 새로운 복사본을 만들고 싶다면 명시적으로 객체의 프로퍼티 또는 배열의 원소를 복사해야 한다.

1
2
3
4
5
var a = ['a', 'b', 'c'];                  // 복사하고자 하는 배열
var b = []; // 복사하고자 하는 배열
for(var i = 0; i < a.length; i++) { // 배열 a의 각 인덱스
b[i] = a[i]; // a의 원소를 b로 복사한다.
}

두 다른 객체 또는 배열을 서로 비교하고 싶다면 그들의 프로퍼티 또는 원소를 비교해야 한다.

3.8 타입 변환

자바스크립트는 타입에 매우 유연하다. 자바스크립트가 문자열을 원한다면, 문자열이 올 자리에 어떤 값을 전달하더라도 문자열로 변환될 것이고, 숫자를 원한다면 숫자가 올 자리에 다른 어떤 값이 오더라도 숫자로 변환될 것이다.(또는 의미 있는 변환을 할 수 없다면 NaN으로 변환된다.)

3.8.1 변환과 동치

자바스크립트는 값의 타입을 유연하게 변환시킬 수 있다. 따라서, 동치 연산자 ==도 유연하게 동작한다. 다음은 모두 true를 반환한다.

1
2
3
4
null == undefined     // 이 두 값은 같다고 판단된다.
"0" == 0 // 비교하기 전에 숫자로 변환된다.
0 == false // 불리언은 비교하기 전에 숫자로 변환한다.
"0" == false // 두 피연선자는 비교하기 전에 숫자로 변환된다.

서로 변환 가능한 값이라고 해서 동치는 아니다. undefined가 불리언 값이 올 자리에 사용되면 false로 변환된다. 하지만 이것이 undefined == false 임을 의미하지는 않는다. if문은 undefined를 false로 변환하지만, == 연산자는 undefined를 불리언으로 변환하지 않는다.

3.8.2 명시적 변환

자바스크립트는 많은 형 변환을 자동으로 수행하지만, 명시적 변환이 필요할 때가 있다. 명시적으로 타입변환을 수행하는 가장 간단한 방법은 Boolean(), Number(), String(), Object() 함수를 사용하는 것이다. new 연산자 없이 호출되면, 이 함수들은 변환 함수로 작동한다.

3.8.3 객체에서 원시 타입으로 변환

모든 객체는 두 개의 타입 변환 메서드를 상속한다.

  • toString() : 객체를 문자열로 표현하여 반환한다.
  • valueOf() : 기본적으로 원시 타입을 반환하지 않고 단순히 객체 그 자신을 반환한다.

자바스크립트는 toString(), valueOf() 순으로 메서드를 호출하여 문자열로 변환하여 반환한다. 만약 toString() 또는 valueOf() 로부터 원시타입 값을 얻을 수 없다면 TypeError를 발생시킨다. 객체를 숫자로 전환할 때는 문자열과 같은 방식으로 전환하지만, valueOf() 메서드를 먼저 호출한다.

3.9 변수 선언

자바스크립트에서는 변수를 사용하기 전에 변수 선언을 해야 한다. var 문을 통해서 변수를 선언하는데, var 문에서 변수에 초기 값을 지정하지 않는다면, 변수는 값이 설정될 때까지 undefined 값을 갖게 된다. 자바스크립트 변수 선언에는 타입을 명시하지 않는다.

3.10 변수의 유효범위

변수의 유효범위란 프로그램에서 어떤 변수가 정의되어 있는 영역을 말한다.

3.10.1 함수 유효범위와 끌어올림(hoisting)

C 같은 프로그래밍 언어에서 블록 안에 있는 코드는 자신만의 유효범위를 가지며, 변수는 해당 변수가 선언되지 않은 블록 밖에서는 보이지 않는다. 이를 블록 유효범위라고 부른다. 자바스크립트에서는 블록 유효범위의 개념이 없고 함수 유효범위를 사용한다. 변수는 해당 변수가 정의된 함수 안에서 보일 뿐 아니라, 그 함수 안에 중첩된 함수 안에서도 보인다. 이런 자바스크립트의 특징을 비공식적으로 **끌어올림(hoisting)**이라고 한다. 자바스크립트의 코드는 함수 안에 있는 모든 변수를 함수 맨 위로 ‘끌어올린’ 것처럼 동작한다.

1
2
3
4
5
6
var scope = "global";
function f() {
console.log(scope); // "global"이 아니라 "undefined"를 출력한다.
var scope = "local"; // 여기서 초기호하지만, 정의는 다른 곳에서 이루어진다.
console.log(scope); // "local"을 출력한다.
}

위의 함수는 실제로 다음 코드와 같다.

1
2
3
4
5
6
function f() {
var scope; // 지역 변수는 함수 맨 꼭대기에서 선언한다.
console.log(scope); // scope 변수는 존재하지만 아직 "undefined" 값이다.
scope = "local"; // 이제 scope 변수가 초기화되고 제대로 된 값이 있다.
console.log(scope); // 여기서는 기대한 값이 들어있다.
}

함수의 유효범위 규칙 때문에 지역 변수는 함수 전체에 걸쳐 정의된다. 지역 변수가 함수 전체에 걸쳐 정의되었더라도 var 문이 실행되고 나서야 실제로 초기화 된다. 따라서 변수 선언은 함수 맨 위로 **’끌어올려(hoisting)’**지고 초기화는 나중에 이루어지게 된다.

블록 유효범위를 가진 프로그래밍 언어에서 일반적으로 변수를 선언하는 좋은 프로그래밍 방법은, 가능한 한 그 변수가 사용되는 가장 가까운 곳에서 선언하는 것이다. 하지만 자바스크립트는 블록 유효범위를 가지고 있지 않기 때문에 함수의 맨 위에 선언해야할지도 모른다.

3.10.3 유효범위 체인

자바스크립트는 언어적으로 유효범위를 갖고 있는 언어다. 변수의 유효범위란 정의된 변수를 사용 가능한 소스코드의 집합으로 생각할 수 있다.

지역 변수를 객체의 프로퍼티로 생각한다면, 변수 유효범위를 다른 관점으로 볼 수도 있다. 자바스크립트의 모든 코드 무더기는 그것과 연관된 유효범위 체인을 갖고 있다. 이 유효범위 체인은 해당 코드 무더기의 ‘범위 안’에 있는 변수를 정의하는 객체의 체인, 리스트다.

최상위 자바스크립트 코드의 경우, 유효범위 체인은 단 하나의 ‘전역 객체’만으로 이루어진다. 중첩되지 않은 함수의 유효 범위 체인은 두 개의 객체로 이루어진다. 하나는 함수 매개변수와 지역 변수를 정의하는 객체고, 다른 하나는 전역 객체다. 중첩된 함수에서 유효범위 체인은 세 개 이상의 객체를 갖는다. 함수가 호출될 때, 해당 함수의 지역변수를 저장하기 위해서 새로운 객체를 하나 생성하고, 해당 객체를 기존에 저장된 유효범위 체인에 추가한다. 중첩 함수의 경우에는 외부에서 함수를 호출할 때마다 중첩된 함수가 매번 선언된다.

출처 : “JavaScript: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4”

자바스크립트 완벽가이드 2장 (어휘 구조)

프로그래밍 언어의 어휘 구조는 프로그램을 어떻게 작성해야 하는지를 알려주는 기본 규칙이다. 어휘 구조는 가장 저수준 문법이다.

2.1 문자 집합

자바스크립트 프로그램은 Unicode 문자 집합을 사용해 작성된다.

2.1.1 대소문자 구분

자바스크립트는 대소문자를 구분하는 언어이다. 그러나 HTML은 대소문자를 구별하지 않는다.

2.1.2 공백, 줄바꿈 제어 문자

자바스크립트는 프로그램 코드 내의 토큰들 사이에 있는 공백들을 무시한다. 대부분의 경우, 줄바꿈 문자도 무시한다.

2.1.3 유니코드 이스케이프 시퀀스

일부 컴퓨터 하드웨어와 소프트웨어에서는 특정 유니코드 글자들을 입력받고서 화면에 출력할 수 없는데 이와 같은 경우 프로그래머가 유니코드를 사용할 수 있도록 일련의 6자리 ASCII 문자열 시퀀스를 정의하고 있다. 유니코드 이스케이프 시퀀스는 \u로 시작하고, 그 뒤에 16진수 숫자 4개가 온다. (유니코드 이스케이프는 자바스크립트 문자열 리터럴이나 정규 표현식 리터럴에서 사용가능)

1
"café" === "caf\u00e9" // true

2.3 리터럴

리터럴(literal)은 프로그램에 직접 나타나는 데이터 값이다. 숫자, 문자열, 불리언, null 모두 리터럴이다.

2.5 선택적인 세미콜론 사용

자바스크립트가 항상 모든 줄바꿈을 세미콜론으로 해석하는 것은 아니다. 일반적으로 세미콜론 없이 코드를 해석할 수 없는 경우에만 줄바꿈을 세미콜론으로 해석한다. 일반적으로, 문장이 (, [, /, +, - 로 시작하면 자바스크립트 인터프리터는 해당 문장을 이전 문장에 이어서 해석한다.
다음 줄을 첫 줄의 문장과 이어서 하나로 처리할 수 없는 경우에만 줄바꿈을 세미콜론으로 해석한다는 일반 규칙에는 두 가지 예외가 있다.

  • return, break, continue 문 바로 다음에 사용했을 경우다. 따라서 return, break, continue와 다음에 오는 키워드 사이에 줄바꿈을 하지 말아야 한다.
  • ++나 – 연산자가 포함된 경우다.
    1
    2
    3
    4
    x
    ++
    y
    // 위코드는 x++; y가 아니라 x; ++y로 해석된다.

출처 : “JavaScript: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4”

자바스크립트 완벽가이드 1장 (자바스크립트 소개)

자바스크립트는 고수준이고 동적이며 타입을 명시할 필요가 없는 인터프리터 언어로, 객체지향 프로그래밍 스타일과 함수형 프로그래밍 스타일을 모두 잘 표현하는 언어이다.

인터프리터는 프로그래밍 언어의 소스 코드를 바로 실행하는 컴퓨터 프로그램 또는 환경을 말한다. 원시 코드를 기계어로 번역하는 컴파일러와 대비된다. 인터프리터는 다음의 과정 가운데 적어도 한 가지 기능을 가진 프로그램이다. 구글의 V8엔진 이라는것은 결국 인터프리터인것이다.
출처 : 위키백과 - 인터프리터

자바스크립트는 웹 초창기에 현재 오라클이라고 불리는 썬마이크로시스템즈에서 상표권 라이센스를 갖고 있고, 언어 자체 구현은 현재 모질라라고 불리는 넷스케이프에서 담당했다. 넷스케이프는 이 언어를 표준화 하기 위해서 **ECMA(European Computer Manufacturer’s Association)**에 제출했는데, 상표권 문제로 언어의 이름을 ECMAScript라고 정했다. 깉은 이유로, 마이크로소프트가 제작한 언어의 이름은 JScript가 되었지만 사람들은 이들 모두를 자바스크립트라고 부른다.
지난 십 년 동안 모든 웹브라우저에 탑재된 자바스크립트는 ECMAScript 3 구현체였다. 최근에는 ECMAScript 5 그리고 ECMAScript 6까지 정의되었다.
자바스크립트 언어 자체만 볼 때, 실질적인 버전은 ECMAScript 3과 5, 6뿐이다. (ECMAScript 4는 기존의 자바스크립트와 다른점이 많아 세상에 나오지 못했다.)

모든 언어는 기초적인 입출력을 처리하는 데 필요한 함수 API나 기반이 되는 플랫폼 또는 표준 라이브러리를 포함하고 있지만 자바스크립트 언어의 코어는 최소한의 API만 정의하고 입출력과 관련된 기능은 포함하고 있지 않다. 입출력을 비롯해 통신과 파일 저장, 그래픽 처리와 같은 복잡한 기능들은 자바스크립트를 내장하고 있는 **’호스트 환경’**에서 담당한다. 브라우저가 자바스크립트 엔진을 내장하고 있기 때문에 클라이언트 측 자바스크립트의 호스트 환경은 웹브라우저다.

1.1 자바스크립트 코어

표현식 (expression) : 값으로 평가될 수 있는 구절, 프로그램의 상태를 바꾸지는 않는다.

1
2
3
4
5
var book = {
topic: "Javascript",
fat: true
};
book.topic // => "Javascript"

설명문 (statement) : 프로그램의 상태를 변경할 수 있다.

1
2
3
var count = 0;
count++;
count--;

출처 : “JavaScript: The Definitive Guide, by David Flanagan (O’Reilly). Copyright 2011 David Flanagan, 978-0-596-80552-4”