3장 언어의 기초

문법

ECMAScript 의 문법은 대부분 C언어, 자바나 펄 등 C와 비슷한 언어에서 차용한 것이다.

대소문자 구분

가장 먼저 이해해야 할 개념은 어디서든 대소문자를 구분한다. 변수나 함수 이름, 연산자 모두 대소문자를 구분한다.

식별자

‘식별자’란 변수나 함수, 프로퍼티, 함수 매개변수의 이름이다. 식별자는 다음 형식에 따라 한 개 이상의 문자로 표기한다.
첫 번째 문자는 반드시 글자나 밑줄( _ ), 달러 기호($)중 하나여야 한다.
다른 문자에는 글자나 밑줄, 달러 기호, 숫자를 자유롭게 쓸 수 있다.

ECMAScript 식별자는 관습적으로 카멜 케이스로 쓴다. 카멜 케이스란 다음과 같이 첫 번째 글자는 소문자로 쓰고 단어가 바뀔 때는 바뀐 단어의 첫 글자를 대문자로 쓰는 표기법이다.
(우리나라에서는 낙타표기법이라고도 한다.)
firstSecond
myCar
doSomethingImportant

단, 키워드와 예약어 및 true, false, null은 식별자로 사용할 수 없다.

주석

// 한줄 주석
/*
* 이런 형식을 써서
*주석을 어려 줄로 쓸 수 있다.
*/

스트릭트 모드

ECMAScript 5에서는 ‘스트릭트 모드’라는 개념을 도입했다. 스트릭트 모드는 기존과는 다른 방식으로 자바스크립트를 파싱하고 실행하라고 지시하는 것이다.
안전하지 않은 동작에는 에러를 반환하도록 한다.
전체 스크립트에 스트릭트 모드를 적용하려면 “use strict”; 맨위에 추가하면 된다.
스트릭트모드는 변ㄴ수에 저장하지는 않는 문자열처럼 보이지만, 스트릭트 모드를 지원하는 자바스크립트 엔진은 이를 인식하고 스트릭트 모드로 전환한다. 이 문법은 ECMAScript 3 문법과 호환되도록 만든 것이다.
function doSomething(){
“use strict”;
//함수 본문
}

인터넷익스플로러 10+, 파이어폭스 4+, 사파리 5.1+, 오페라12+, 크롬에서 스트릭트 모드를 지원한다.

문장

각 문장은 세미콜론으로 종료한다. 세미콜론을 생략하면 다음 예제처럼 자바스크립트 엔진에서 문장이 끝나는 위치를 판단한다.

var sum = a + b // 세미콜론이 없어도 유효하지만 권장하지 않는다.
var diff = a – b; //이렇게 쓰길 권장
문장 마지막에 세미콜론을 꼭 써야 하는건 아니지만 항상 세미콜론을 쓰길 권장한다. 세미콜론을 쓰는 습관을 들이면 타이핑하다가 멈췄던 부분을 깜박 잊는 등의 에러를 쉽게 발견할 수 있으며 여분의 공백을 제거해서 코드를 압축할 수도 있다.

if 문 같은 제어문에서 실행하는 문장이 하나뿐이라면 코드 블록을 쓰지 않아도 되지만 코드블록을 쓰면 의도를 더 명확하게 표현 할 수 있고 나중에 수정할 때 에러가 생길 가능성이 적다.

키워드와 예약어

키워드와 예약어는 식별자가 있다.
키워드는 제어문의 시작과 끝을 나타낸다거나 특정한 좍 모적으로 쓰인다. 키워드는 식별자나 프로퍼티 이름에 쓸 수 없다.
* 붙은 키워드는 5판에서 추가된 키워드이다.

  • break
  • do
  • instanceof
  • typeof
  • case
  • else
  • new
  • var
  • continue
  • for
  • switch
  • while
  • debugger*
  • function
  • this
  • with
  • default
  • if
  • throw
  • ow
  • delete
  • in
  • try

예약어 역시 식별자나 프로퍼티 이름에 쓸 수 없다. 예약어는 아직은 특별한 쓰임새가 없지만 미래에 키워드로 쓸 가능성이 있으므로 예약해 둔 것이다.

변수

변수에 어떤 타입의 데이터라도 저장할 수 있다는 의미이다.
변수를 정의할 때는 다음과 같이 var 연사자 다음에 변수 이름을 쓴다.

var message = “hi”;

위 코드는 message 변수가 문자열 값 “hi”를 저장한 것으로 정의 했다.

var 연산자는 변수를 로컬 스코프에서 정의한다는 점을 반드시 기억해야 한다. 예를 들어 함수 안에서 var 키워드 써서 변수를 정의하면 해당 변수는 다음과 같이 함수를 종료하는 즉시 파괴된다.
로컬 스코프: 안에서 변수를 선언할 때 var 연사자를 생략해서 전역 변수를 정의할 수 있긴 하지만 가급적 이런 패턴은 피하길 권한다. 전역 변수를 로컬에서 정의하면 관리하기도 어렵고 var 키워드를 의도적으로 생락한 것인지 실수인지 바로 알 수 없어서 혼란스럽기 때문이다.
스트릭트 모드에서는 변수를 선언하지 않고 값을 할당하려 하면 ReferenceError 에러를 반환한다.

function test(){
var message = “hi”; //지역변수
}
test();
alert(message); //에러

여기에서 messag 변수는 함수 내부에 정의되었다. test() 함수를 호출하면 변수를 생성하고 값을 할당한다. 그 직후 변수는 파괴되므로 이 예제의 마지막 줄은 에러를 일으킨다.
var 연산자를 생략하면 변수를 전역으로 정의 할수 있다.

function test(){
message = “hi”; //지역변수
}
test();
alert(message); // hi

 

var 연산자를 제거함으로서 message 변수는 전역 변수가 되었다. test() 함수를 호출하는 즉시 변수가 정의되며 함수 외부에서도 이 변수에 접근할 수 있다.

주의: var 연산자를 생략해서 전역변수를 정의할 수 있긴 하지만 가급적 이런 패턴은 피하길 권장한다. 전역 변수를 로컬에서 정의하면 관리하기도 어렵고 var 키워드를 의도적으로 생략한 것인지 실수인지 바로 알 수 없어서 혼란스럽기 때문이다.

var message = “hi”,
found = false,
age = 29;

 

변수 세개를 정의하고 초기화했다.

데이터 타입

ECMAScript에는 다섯 가지 기본적인 데이터 타입이 있습니다. 이를 ‘원시primitive 데이터 타입’이라 부르기도 하는데 Undefined, Null, 불리언Boolean, 숫자, 문자열이 이에 해당한다.
객체라 불리는 복잡한 데이터 타입도 있다. 객체는 이름-값 쌍의 순서 없는 목록이다.

typeof연산자

변수의 데이터 타입을 알아내야할 때가 있는데 typeof 연산자를 통해 데이터 타입을 알 수가 있다. 값(변수)에 typeof 연산자를 적용하면 다음 문자열 중 하나를 반환한다.

  • 정의되지 않은 변수 : “undefined”
  • 불리언: “boolean”
  • 문자열: “string”
  • 숫자: “number”
  • 함수를 제외한 객체 또는 null: “object”
  • 함수: “function”

typeof 연산자는 다음과 같이 사용한다.

var message = "some string";
alert(typeof message); //"string"
alert(typeof(message)); //"string"
alert(typeof 95); //number

이 예제에서는 변수(message)와 숫자 리터럴을 typeof 연산자에 전달했다. typeof는 함수가 아니라 연산자이므로 괄호는 쓰지 않아도 된다.
리터널: ‘값 그 자체’를 의미한다.
보통 리터널이라는 표현은 ‘저자가 값 그 자체에 무게를 두면서 말하고 있다’라고 생각하면 된다.

Point:기술적으로 말해 ECMAScript의 함수는 객체로 간주된다. 하지만 함수에는 다른 객체에 없는 특별한 프로퍼티가 존재하므로 typeof 연산자가 함수를 다른 객체와 구별해 반환하는 것이 합리적이다.

undefined 타입

undefined라는 값은 특별한 값이다. var를 써서 변수를 정의했지만 초기화되지 않았다면 해당 변수에는 다음과 같이 undefined가 할당된다.
Point:리터럴 값 undefined는 빈 객체를 가리키는 포인터인 null과 초기화되지 않은 변수를 비교할 목적으로 ECMA-262 3판에 추가 되었다.

var message //이 변수는 선언되었지만 값은 undefined이다.

//이 변수는 선언되지 않았다.
//var age

alert(message); // "undefined"
alert(age); //에러를 일으킨다.

이 예제에서 첫 번째 alert()은 값이 “undefined”인 변수 message를 표시한다. 두 번째 alert()에는 아직 정의한적 없는 변수 age를 넘겼으므로 에러가 일어난다. 정의하지 않은 변수에 실행할 수 있는 유의미한 조작은 typeof뿐이다.

Null 타입

Null타입 역시 값 하나만을 갖는다. Null 타입의 값은 특별한 값인 null이다. null은 빈 객체를 가리키는 포인터이므로 null에 typeof를 호출하면 다음 예제처럼 “object”를 반환한다.

var car = null;
alert(typeof car); // "object"

변수를 정의할 때 해당 변수가 객체를 가리키게 할 생각이라면 해당 변수에는 다른 값을 쓰지 말고 null로 초기화하길 권한다. 그렇게 하면 다음과 같은 코드를 써서 해당 변수가 객체를 가리키는지 명시적으로 확인할 수 있다.

if(car != null){
//car를 사용하는 코드
}

null과 undefined 사이에 있는 == 연산자는 항상 true를 반환한다. 하지만 이렇게 두 값이 같다고 나오는 이유는 == 연산자가 피연산자를 비교할 때 암시적으로 타입 변환을 하기 때문이다.

불리언 타입

불리언 타입은 script에서 가장 많이 쓰이는 데이터 타입중 하나이며, true 와 false 두 가지 리터럴 값만 가진다.

숫자 타입

NaN

숫자형 값 중에는 NaN(Not a Number)이란 특별한 값이 있다. 이 값은 숫자를 반환할 것으로 의도한 조작이 실패했을 때 반환하는 값이다. 에러를 반환하는 것이 아님에 유의해야 한다.
NaN에는 몇 가지 고유한 특징이 있다. 먼저 NaN이 포함된 조각(예를 들어 NaN/10)은 항상 NaN을 반환한다. 이런 특징은 여러 단계를 계산할 때 어느 단계에서 처음으로 NaN을 반환했는지 파악하기 어려우므로 골칫거리가 될 수 있다. 둘째, NaN은 어떤 값과도 일치하지 않으며 심지어 NaN끼리도 일치하지 않는다.
alert(NaN == NaN); // false;
이런 문제로 인해 isNaN();함수를 따로 제공한다. 이 함수는 매개변수를 하나 받으며 해당 값이 ‘숫자가 아닌 값’인지 검사한다.

alert(isNaN(NaN)) //true
alert(isNaN(10)); //falase - 10은 숫자입니다.
alert(isNaN("10")); //false - 숫자 10으로 바꿀 수 있습니다.
alert(isNaN("blue")); //true - 숫자로 바꿀 수 없습니다.
alert(isNaN(true)); //false - 숫자 1로 바꿀 수 있습니다.

숫자 변환

숫자가 아닌 값을 숫자로 바꾸는 함수는 Number(), parseInt(), parseFloat() 함수 세 가지이다.
첫 번째 함수 Number()는 어떤 데이터 타입에든 쓸 수 있으며 다른 두 함수는 문자열을 숫자로 바꾸는 용도로 만들어졌다. 각 함수는 같은 입력에 다르게 반응한다.

Number()함수는 다음 규칙에 에 기반해서 변환한다.

  • 매개변수로 불리언 값ㅇ르 넘겼다면 true와 false를 각각 1과 0으로 바꿔 반환한다.
  • 매개변수로 숫자로 넘겼다면 그대로 반환한다.
  • 매개변수로 null을 넘겼다면 0을 반환한다.
  • 매개변수로 undefined을 넘겼다면 NaN을 반환한다.
  • 매개변수로 문자열을 넘겼다면 NaN을 반환한다.

    • 문자열이 숫자만으로 구성되었다면 리딩 제로(숫자 앞에 붙이는 0을 말한다.)는 모두 버리고 나머지를 10진수로 변환한다. “011”은 11로 바뀐다.
    • 문자열이 “1.1” 같은 유효한 부동소수점 숫자 형식이라면 해당하는 부동소수점 숫자를 반환한다. 리딩제로는 버린다.
    • 문자열이 “oxf” 같은 유효한 16진수 형식이라면 그에 해당하는 정수를 반환한다.
    • 빈 문자열이라면 0을 반환한다.
    • 앞에서 설명한 형식에 맞지 않는 문자열이라면 NaN을 반환하다.

Number()에서 다양한 규칙을 사용하기 때문에 데이터 타입을 숫자로 변환하는 일은 혼자스러울 수 있습니다.

var num1 = Number("Hello world"); //NaN
var num2 = Number(""); //0
var num3 = Number("000011"); // 11
var num4 = Number(true); // 1