Skip to content

Kyunghwa Yoo

자바스크립트의 좋은 점들

javascript7 min read

자바스크립트의 좋은 문법

공백

  • 공백은 문자를 구분하는 형태나 주석의 형태를 취할 수 있다.
  • 블록주석(/* ... */) 은 정규 표현식 리터럴과 충돌할 수 있기 때문에 안전하지 않다. 한 줄 주석(// ...)을 사용하는 것이 더 좋다.
1/*
2var rm_a = /a*/.match(5);
3*/

이름

  • 이름은 하나의 문자나 그 뒤를 이어서 하나 이상의 문자, 숫자, _ 가 붙는 문자열이다.
  • 예약어로 지정된 키워드는 이름이 될 수 없다.
1abstract
2boolean break byte
3case catch char class const continue
4debugger default delete do double
5else enum export extends
6false final finally float for function
7goto
8if implements import in instanceof int interface
9long
10native new null
11package private protected public
12return
13short static super switch synchronized
14this throw throws transient true try typeof
15var volatile void
16while with
  • undefined, NaN, Infinity 등은 예약어가 아니다.

숫자

  • 자바스크립트는 64비트 부동 소수점 형식(자바의 double 형과 같다) 하나만 가진다. 덕분에 short 형을 사용해서 오버플로우가 발생하는 일 등이 전혀 없다.
  • NaN 인지 비교할 때는 isNaN() 함수를 사용한다.
  • 1.76769313486231570e+308 보다 큰 값은 Infinity 로 나타낸다.
1var maximum = 1.76769313486231570e+308;
2var infinity = 1.76769313486231570e+309;
3
4console.log(maximum);
5console.log(infinity); // Infinity 가 출력된다.

문자열

  • 자바스크립트의 모든 문자는 16비트 유니코드이다.
  • \u로 시작하는 표기법은 유니코드 숫자값으로 문자를 나타낼 수 있다.
1var alphabet = 'A';
2var unicode = '\u0041';
3
4console.log(unicode);
5console.log(alphabet === unicode);

문장

  • 웹 브라우저에서 각각의 <script> 태그는 컴파일되어 즉시 실행되는 하나의 컴파일 단위이다.
  • 링커(linker) 가 없기 때문에 자바스크립트는 전역 네임스페이스에 모든 문장을 몰아 넣는다.
  • 자바스크립트에서 블록은 새로운 스코프를 생성하지 않는다.
  • return 문에서 return 과 표현식 부분 사이에 줄 바꿈을 허용하지 않는다.
  • break 문에서 break 뒤에 라벨을 붙일 수 있다. 라벨이 있으면 라벨에 해당하는 위치로 이동한다. 참고

표현식

  • ! 연산자의 피연산자 값이 참이면 결과값은 거짓이며, 그 반대면 결과값은 참이다.
  • + 연산자는 수를 더하거나 문자열을 연결한다.
  • && 연산자는 첫 번째 피연산자가 거짓일 경우 첫 번째 피연산자의 값을 취하고, 그렇지 않은 경우에는 두 번째 피연산자 값을 결과값으로 취한다.
  • || 연산자는 &&와 반대다.

객체

속성값 읽기

  • 존재하지 않는 속성, 즉 undefined 의 속성을 참조하려 할 때 TypeError 가 발생한다. 이를 방지하기 위해 && 연산자를 사용할 수 있다.
1var obj = {};
2if(obj.prop && obj.prop.prop) {
3 console.log('obj.prop.prop 가 존재합니다.');
4} else {
5 console.log('obj.prop 나 obj.prop.prop 이 존재하지 않습니다.');
6}

프로토타입

  • Object.create 를 통해서 프로토타입을 지정해서 객체를 생성할 수 있다. 참고
  • delegation (위임)
    • 프로퍼티를 찾을 때 프로토타입 체인으로 인해 마지막 프로토타입인 Object.prototype 까지 뒤져보고 없을 때 undefined 를 반환한다.

리플렉션

  • typeof 로 속성의 타입을 알 수 있다. 하지만 해당 객체의 속성이 아니라 프로토타입 체인 상에 있는 속성을 반환할 수 도 있다.
  • hasOwnProperty 메소드로 객체에 해당 프로퍼티가 있는지 확인할 수 있다.

열거

  • for in 구문으로 모든 속성의 이름을 열거할 수 있지만 프로토타입의 속성까지 나오므로 hasOwnProperty 를 곁들이는게 좋다.
1var obj = {
2 first: 1,
3 second: 'two'
4};
5
6for (var prop in obj) {
7 if (obj.hasOwnProperty(prop)) {
8 console.log(prop + ' : ' + obj[prop]);
9 }
10}

삭제

  • delete 는 프로토타입의 속성을 삭제하지는 않는다.

최소한의 전역변수 사용

  • 전역변수 사용을 최소화하는 방법 중 하나는 전역변수 하나를 만들어 다른 전역변수를 위한 컨테이너로 사용하는 것이다.
  • 이 방법으로 애플리케이션에 필요한 전역변수를 이름 하나로 관리할 수 있고, 명시적으로 전역변수라는 것을 나타내기 때문에 가독성도 높아진다.

함수

함수 객체

  • 자바스크립트에서 함수는 객체다.
  • 함수 객체는 Function.prototype 과 연결되어 있다.
  • 함수 객체는 prototype 속성을 가지는데 함수 자체를 값으로 갖는 constructor 속성을 포함하고 있는 객체이다.
  • 함수는 객체이기 때문에 다른 값들처럼 변수나 객체, 배열에 저장된다.

함수 리터럴

  • 클로저: 함수 리터럴로 생성한 함수 객체에서 외부 문맥으로의 연결

호출

  • 함수를 호출하면 추가로 this 와 arguments 두 개의 매개변수를 받는다.
  • this 는 호출 패턴에 따라 다른 값이 들어간다.
    • 메소드 호출 패턴: 메소드가 포함된 객체 (자신의 객체 문맥을 this로 얻는 메소드를 public method 라고 한다.)
    • 함수 호출 패턴: 전역 객체. (메소드의 this 와 메소드 내부함수의 this 가 달라지기 때문에 필요 시 메소드의 this 를 저장해야 한다.)
    • 생성자 호출 패턴: 새로 생성될 객체
    • apply, call 호출 패턴: 함수 매개변수로 this 를 직접 주입할 수 있다.

인수 배열 (arguments)

  • arguments 는 배열이 아니다. length 는 있지만 배열이 가지고 있는 메소드들이 없다.

유효범위(scope)

  • 자바스크립트는 함수 scope 만 지원하기 때문에 함수에서 사용하는 변수를 함수 첫 부분에서 선언하는 것을 권고하고 있다.

클로저

  • 함수가 자신이 생성된 함수, 즉 자신을 내포하는 함수의 문맥에 접근할 수 있는 것.
  • 이를 통해서 자신을 생성한 함수의 변수에 접근할 수 있다.

연속 호출

  • 반환값이 없는 메소드일 경우 this 를 반환할 경우 연속적으로 메소드를 호출할 수 있습니다.
1// 예시
2getElement('myBoxDiv')
3 .move(350, 150)
4 .width(100)
5 .height(100)
6 .color('red')
7 .border('10px outset');

메모이제이션

  • 이전에 연산한 결과를 저장하고 있는 객체를 사용해서 반복된 작업을 최적화하는 기법
1var count1 = 0;
2var fibonacci = function(n) {
3 count1++;
4 return n < 2 ? n: fibonacci(n - 1) + fibonacci(n - 2);
5};
6
7for (var i = 0; i <= 10; i += 1) {
8 console.log(i + " = " + fibonacci(i));
9}
10console.log("count1 = " + count1);
11
12var count2 = 0;
13var fibonacci2 = function(){
14 var memo = [0, 1]; // 메모이제이션을 할 객체
15
16 var fib = function(n) {
17 count2++;
18 var result = memo[n];
19 if (typeof result !== 'number') {
20 result = fib(n-1) + fib(n-2);
21 memo[n] = result; // 연산한 결과를 객체에 저장한다.
22 }
23 return result;
24 };
25 return fib;
26}();
27
28for (var i = 0; i <= 10; i += 1) {
29 console.log(i + " = " + fibonacci2(i));
30}
31
32console.log("count2 = " + count2)

상속

의사 클래스 방식

  • 생성자 함수와 new 키워드를 이용해서 클래스 상속을 비슷하게 구현

객체를 기술하는 객체

  • 매개변수가 매우 많을 때 사용하면 좋은 방식
  • 객체를 기술하는 하나의 객체를 매개변수로 받는다.
1var myObj1 = maker(f, l, s, c); // 매개변수가 많다.
2var myObj2 = maker({
3 first: f,
4 last: l,
5 state: s,
6 city: c
7});

프로토타입 방식

  • Object.create() 를 통해서 유사한 객체들을 만들 수 있습니다.
  • 프로토타입 방식은 private 속성을 사용할 수 없다는 단점이 있다.
1var myMammal = {
2 name: 'Mammal',
3 getName: function() {
4 return this.name;
5 }
6};
7
8var myCat = Object.create(myMammal); // 객체 상속

함수를 사용한 방식

  • 먼저 객체를 생성하는 함수를 만든다.
    1. 새로운 객체를 생성한다. 객체 리터럴로 만들 수도 있고, new 연산자를 사용해서 생성자 함수를 호출할 수도 있고, 기존의 객체에서 새로운 인스턴스를 만들어주는 Object.create 메소드를 사용할 수 도 있고, 객체를 반환하는 함수를 호출할 수도 있다.
    2. 필요한 private 변수와 메소드를 정의한다. 이것들은 함수의 일반적인 변수이다.
    3. that 에 새로운 객체를 할당하고 메소드를 추가한다. 이 때 추가되는 메소드들은 함수의 매개변수와 2단계에서 정의한 변수들에 접근할 수 있는 권한을 갖는다.
    4. 새로운 객체 that 을 반환한다.
1// pseudocode
2// spec 객체는 constructor가 인스턴스를 만드는데 필요한 정보가 들어 있다.
3// my 객체는 상속 연결상에서 생성자와 공유하게 되는 비밀들을 담는 컨테이너다.
4var constructor = function (spec, my) {
5 var that;
6 // 필요한 private 변수들 추가
7
8 var my = my || {};
9 // 공유할 변수와 함수를 my에 추가
10
11 that = {}; // that에 새로운 객체 할당
12
13 // 앞서 정의한 변수들에 접근할 권한이 있는 메소드들을 that 에 추가
14
15 return that; // that 반환
16}
  • pseudocode 에 대한 예제는 다음과 같다.
1var mammal = function (spec) {
2 var that = {};
3
4 that.getName = function() {
5 return spec.name;
6 };
7
8 that.says = function() {
9 return spec.saying || '';
10 };
11
12 return that;
13};
14
15var myMammal = mammal({
16 name: 'Herb'
17});
18
19console.log(myMammal.getName());
20console.log(myMammal.says());
21
22var cat = function (spec) {
23 spec.saying = spec.saying || 'meow';
24
25 var that = mammal(spec);
26
27 that.purr = function(n) {
28 var s = '';
29
30 for (var i = 0; i < n; i += 1) {
31 if (s) {
32 s += '-';
33 }
34 s += 'r';
35 }
36 return s;
37 };
38
39 that.getName = function() {
40 return that.says() + ' ' + spec.name + ' ' + that.says();
41 };
42
43 return that;
44};
45
46var myCat = cat({
47 name: 'Henrietta'
48});
49
50console.log(myCat.getName());
51console.log(myCat.says());
52console.log(myCat.purr(5));
53
54// super 메소드를 다룰 수 있는 방법도 있다.
55Object.prototype.superior = function (name) {
56 var that = this;
57 var method = that[name];
58
59 return function() {
60 return method.apply(that, arguments);
61 }
62};
63
64var coolcat = function (spec) {
65 var that = cat(spec);
66 var superGetName = that.superior('getName');
67
68 that.getName = function (n) {
69 return 'like ' + superGetName() + 'baby';
70 };
71
72 return that;
73};
74
75var myCoolCat = coolcat({
76 name: 'Bix'
77});
78var name = myCoolCat.getName();
79
80console.log(name);

배열

  • 배열은 해당 항목의 오프셋을 계산할 수 있는 정수를 통해 각 항목들을 접근할 수 있는 연속적인 메모리 할당으로 매우 빠른 데이터 구조이다.
  • 자바스크립트는 이러한 배열이 존재하지 않고 배열같은 특성을 지닌 객체를 제공한다.
  • 이는 실제 배열보다 느리지만 사용하는데는 더 편리할 수 있다.

배열 리터럴

  • 배열 리터럴로 쉽게 배열을 만들 수 있다.
  • 프로퍼티가 0, 1, 2 ... 인 객체와 거의 유사하다.
  • 차이점은 배열은 Array.prototype 을 상속받지만 객체는 Object.prototype 을 상속받는다. 그래서 Array 에서 제공하는 메소드들을 객체는 사용할 수 없다.
  • 또 하나의 차이점은 length 프로퍼티다. 객체는 length 프로퍼티가 없다.

length 속성

  • length 속성은 배열의 가장 큰 정수 속성 이름보다 하나 더 큰 값이다. 때문에 length 의 값이 배열의 개수와 반드시 일치하지는 않는다.
1var arr = [];
2console.log(arr.length);
3
4arr[100000] = 1;
5console.log(arr.length);
  • length 값을 크게 설정해도 배열을 위해 더 많은 공간이 할당되지는 않는다.
  • length 값을 작게 설정하면 설정한 값보다 크거나 같은 값에 해당하는 속성은 모두 삭제된다.

삭제

  • 자바스크립트에서 배열도 객체이기 때문에 delete 키워드로 속성을 삭제할 수 있다. 하지만 그 위치에 구멍이 생긴다.
  • Array.splice 를 사용하면 빈 공간 없이 삭제할 수 있다. 뒤의 값들의 인덱스가 하나 씩 앞당겨지는 과정이 발생하게 배열이 아주 큰 경우 성능이 느려질 수 있다.

열거

  • 자바스크립트에서 배열도 객체이기 때문에 for in 으로 배열을 열거할 수 있다. 하지만 for in 은 순서를 보장하지 않으며 prototype chain으로 예상치 못한 속성도 열거될 수 있다.
  • 가장 기본적인 for 문으로 length만큼 반복하면 배열을 열거할 수 있다.

객체와 배열의 혼동

  • 객체를 써야될지 배열을 써야될지 헷갈린다면, 속성 이름이 작은 크기의 연속된 정수이면 배열을 사용하고 그렇지 않으면 객체를 사용하는 것이다.
  • 자바스크립트에서 객체와 배열을 구분할 수 있는 적절한 메커니즘이 없다. (심지어 배열을 typeof 해보면 'array'가 아닌 'object'가 나온다.)
  • 배열인지 구분할 수 있는 함수 중에서 필자가 찾아낸 가장 신뢰할 만한 방법은 다음과 같다.
1var isArray = function(value) {
2 return value &&
3 typeof value === 'object' &&
4 typeof value.length === 'number' &&
5 typeof value.splice === 'function' &&
6 !(value.propertyIsEnumerable('length'));
7};

정규 표현식

  • 정규 표현식은 보통 같은 문자열에 대해 반복해서 연산을 수행할 떄 성능상의 이점이 있다.

예제

1var parse_url = /^(?:([A-Za-z]+):)?(\/{0,3})([0-9.\-A-Za-z]+)(?::(\d+))?(?:\/([^?#]*))?(?:\?([^#]*))?(?:#(.*))?$/;
2// / 정규표현식 시작
3// ^ 문자열 시작
4// (?:([A-Za-z]+):)? A~Z 또는 a~z 사이의 문자가 반복되며 이 문자열은 캡쳐된다. 하지만 맨 뒤에 콜론(:)이 붙은 문자열은 캡쳐되지 않는다.
5// (\/{0,3}) 슬래시 0번에서 3번 반복
6// ([0-9.\-A-Za-z]+) 숫자나 문자, 점(.)과 대쉬(-) 가 가능한 문자의 반복. 대쉬(-)는 이스케이프가 필요하다.
7// (?::(\d+))? 콜론(:) 뒤에 하나 이상의 숫자의 연속. 숫자의 연속은 캡쳐된다.
8// (?:\/([^?#]*))? 슬래시(/)로 시작하며 ?와 #를 제외한 모든 문자가 반복할 수 있다.
9// (?:\?([^#]*))? 물음표(?)로 시작하며 #을 제외한 모든 문자가 반복할 수 있다.
10// (?:#(.*))? #으로 시작하며 마침표(.)는 라인 종료 문자를 제외한 어떤 문자나 가능하다는 뜻이다.
11// $ 문자열의 끝
12// /;
13var url = 'http://www.ora.com:80/goodparts?q#fragment';
14
15var result = parse_url.exec(url);
16console.log(result);
17
18var names = ['url', 'scheme', 'slash', 'host', 'port', 'path', 'query', 'hash'];
19
20var blanks = ' ';
21
22var i;
23
24for (i = 0; i < names.length; i++) {
25 console.log(names[i] + ':' + blanks.substring(names[i].length) + result[i]);
26}
  • ^: 문자열의 시작
  • (?:([A-Za-z]+):)?: 프로토콜 이름
    • (?:...): 캡쳐하지 않는 그룹
    • 캡쳐는 결과배열에 넣는 기능을 뜻한다.
    • 끝에 붙는 ?는 옵션이라는 뜻이다. 없거나 한 번 반복된다.
    • (...)는 캡쳐하는 그룹이다.
    • 캡쳐하는 그룹은 일치하는 텍스트를 복사하여 결과 배열에 넣는다.
    • 원본이 0번째 인덱스를 차지하고, 캡쳐한 텍스트는 순서대로 1부터 인덱스를 가진다.
    • 문자 클래스 [] 뒤에 붙는 접미사 +는 문자 클래스가 한 번 이상 일치한다는 것을 나타낸다.
  • (\/{0,3}): /(슬래시)가 0에서 3번 일치
  • ([0-9.\-A-Za-z]+): 숫자나 문자, 점(.)과 대쉬(-) 가 가능한 문자의 반복. 대쉬(-)는 이스케이프가 필요하다.
  • (?::(\d+))?: 콜론(:) 뒤에 하나 이상의 숫자의 연속. 숫자의 연속은 캡쳐된다.
  • (?:\/([^?#]*))?: 슬래시(/)로 시작하며 ?와 #를 제외한 모든 문자가 반복할 수 있다.
  • (?:\?([^#]*))?: 물음표(?)로 시작하며 #을 제외한 모든 문자가 반복할 수 있다.
  • (?:#(.*))? #으로 시작하며 마침표(.)는 라인 종료 문자를 제외한 어떤 문자나 가능하다는 뜻이다.
  • $: 문자열의 끝
1var parse_number = /^-?\d+(?:\.\d*)?(?:e[+\-]?\d+)?$/i;
2
3console.log(parse_number.test('1'));
4console.log(parse_number.test('number'));
5console.log(parse_number.test('98.6'));
6console.log(parse_number.test('132.21.86.100'));
7console.log(parse_number.test('123.45E-67'));
8console.log(parse_number.test('123.45D-67'));
  • ^, $ 가 사용되면 모든 문자가 정규표현식에 대응해서 일치해야 한다는 뜻이다.
    • 두 문자를 제외하면 숫자가 포함된 문자열을 알려주는 정규표현식이 된다.
    • ^만을 사용하면 숫자로 시작하는 문자열에 대응하게 된다.
    • $만을 사용하면 숫자로 끝나는 문자열에 대응하게 된다.
  • 맨 마지막 i 플래그를 사용하면 검사할 때 대소문자를 구분하지 않는다.
  • -?: 음수를 표현하는 -는 옵셔널하다.
  • \d+: 숫자가 하나 이상 가능하다는 의미이다.
  • (?:\.\d*)?: 소수점(이스케이프 필요)과 그 뒤에 올 수 있는 0개 이상의 숫자에 대응한다. 이 값 역시 옵셔널하다.
  • (?:e[+\-]?\d+)?: e나 E와 선택적인 부호(+/-) 그리고 하나 이상의 숫자에 대응한다. 이 값 역시 옵셔널하다.

정규 표현식 객체 생성

정규 표현식 리터럴

  • 정규 표현식 리터럴은 /로 묶인다. /는 주석이나 나누기 에도 사용되므로 주의가 필요하다.
  • 정규 표현식 리터럴로 만들어진 RegExp 객체는 모두 하나의 인스턴스를 공유한다.

RegExp 생성자

  • new RegExp('', ''); 로 사용된다.
  • 첫 번째 매개변수로 문자열이 들어가는데 이 때 이스케이프 할 때 역슬래시가 두 번 들어가야 하며 따옴표도 이스케이프 시켜야 한다.
  • 두 번째 매개변수는 플래그 지졍 문자열이다.
    • g: 여러 번 일치함
    • i: 대소문자 구분안함
    • m: 여러 줄을 줄 단위로 정규표현식을 검색한다.

구성 요소

선택

  • | 를 키워드로 하나 이상의 정규 표현식 시퀀스가 포함된다.
  • "into".match(/in|int/): into는 앞서 나온 in과 일치하기 때문에 뒤에 int 와 비교하지 않고 완료된다.

시퀀스

  • 정규 표현식 시퀀스는 하나 이상의 정규 표현식 요소를 포함한다.
  • 수량자(*, + 등)가 없으면 그 요소는 한번만 일치한다.

정규 표현식 요소

  • \ / [ ] ( ) { } ? + * | . ^ $: 이 문자들을 사용하기 위해서는 반드시 이스케이프(\) 해야 한다.

이스케이프

  • \는 문자열과 정규 표현식 요소에서 모두 이스케이프 됐다는 것을 나타낸다. 대부분 같은 의미를 가지지만 \b 는 역스페이스 문자가 아니다.

그룹

캡처

  • 괄호로 묶인 정규 표현식 선택
  • 그룹에 일치하는 문자들이 캡처된다.
  • 첫 번째 캡처 그룹이 1, 다음 캡쳐 그룹이 2 이런 식으로 주어진다.

비캡처

  • (?: ... ) 로 묶이는 그룹
  • 일치하는지만 확인하며 텍스트를 캡쳐하지는 않는다.
  • 캡쳐보다 성능이 약간 더 빠르다고 한다.

긍정형 룩어헤드(positive lookahead)

  • (?= ... ) 로 묶이는 그룹
  • 비캡쳐 그룹과 유사한데 찾은 후에 텍스트를 그룹이 시작하는 지점으로 다시 돌린다.

부정형 룩어헤드(negative lookahead)

  • (?! ... ) 로 묶이는 그룹
  • 긍정형 룩어헤드와 비슷한데 찾지 못했을 때가 일치하는 경우이다.
  • 잘 몰라도 될 것 같다.. 더글라스 크락포드가 책을 잘 쓰는 사람은 아니구나 라는 걸 느꼈다.

클래스

  • 특정 문자 집합 하나를 지정하는 방법
  • 문자의 범위를 - 키워드를 이용해서 지정할 수 있다. ex) [A-Za-z]
  • 부정형을 만들기 쉽다. ex) A-Z

클래스 내의 이스케이프

  • 문자 클래스 안에서 이스케이프 되는 특수문자는 다음과 같다.
1- / [ \ ] ^
  • 정규 표현식과 조금 다른 점은 [\b] 는 단어 경계가 아니고, 역스페이스 문자이다.

수량자 (Quantifier)

  • 정규 표현식 요소가 몇 번 일치해야 하는지를 결정한다.
  • {숫자,숫자} 로 구성되며 숫자를 하나만 입력하면 일치하는 부분을 최대한 많이 찾으려고 한다.
  • /w{0,1}/ w가 0개 에서 1개 까지 찾는다.

메소드

  • 많은 수의 문자를 하나로 합칠 때 Array에 담아서 join 하는 것이 + 로 합치는 것보다 성능이 좋다.

부록A: 나쁘지만 사용해야 하는 부분들

전역변수

  • 자바스크립트는 언어가 전역변수에 기반하고 있기 때문에 모든 스코프에서 접근이 가능하다.

유효범위(scope)

  • 자바스크립트는 블록 스코프를 제공하지 않는다.
  • 함수에서 사용하는 모든 변수를 함수의 첫 부분에 선언하는 것이 좋다.

세미콜론 삽입

  • 자바스크립트는 자동으로 세미콜론을 삽입하여 잘못된 프로그램을 교정하려는 메커니즘이 존재한다.
1return
2{
3 status: true
4};

위 코드는 객체가 아닌 undefined 를 반환한다.

1return {
2 status: true
3};

다음과 같이 해야 정상적으로 객체를 반환한다.

유니코드

  • 자바스크립트에서 문자는 16비트 다.
  • 여기에 포함되지 않는 유니코드 문자들은 \u 표기 두 개를 연속으로 붙여서 사용한다.

typeof

  • 정규 표현식 객체에 대한 타입 값은 자바스크립트 실행환경에 따라 다르게 나타난다.

parseInt

  • parseInt 를 사용할 때는 항상 기수 매개변수를 지정할 것을 권장한다.

+ 연산자

    • 연산자를 덧셈이나 문자열 연결에 사용할 수 있다.
  • 덧셈의 용도로 사용할 경우 피 연산자가 모두 숫자인지 확인하는 것이 좋다.

NaN

  • typeof NaN // 'number'
  • NaN === NaN // false
  • NaN !== NaN // true
  • NaN 인지 확인이 필요한 경우 isNaN() 함수를 사용하라
  • isFinite() 함수는 NaN 과 Infinity 를 거부하기 때문에 숫자인지 구분하기 좋지만 숫자가 아닌 경우 숫자로 변환하려고 한다.

배열

  • typeof 로 배열과 객체를 구분할 수 없다. 구분하기 위해서는 constructor 속성이 Array 인지 확인해야 한다.

부록B: 나쁜 점들

==, !=

  • 예측할 수 없는 결과가 나올 수 있기 때문에 == != 는 반드시 피한다.
1'' == '0' // false
20 == '' // true
30 == '0' // true
4
5false == 'false' // false
6false == '0' // true
7
8false == undefined // false
9false == null // flase
10null == undefined // true
11
12' \t\r\n ' == 0 // true

with 문

  • 객체 하나에 속한 속성들을 접근할 때 간편함을 제공할 목적으로 등장
  • 하지만 예측할 수 없는 결과가 나올 가능성이 높으며 성능적인 문제도 있기 때문에 절대 사용 금지

eval

  • 문자열을 자바스크립트 컴파일러에 넘긴 후 그 결과를 실행시키는 함수
  • 읽기 어렵고 속도도 느리며 보안에 취약하다.

++ --

  • 증감 연산자를 사용하면 코드가 간결해 질 순 있지만 심각한 보안 취약점을 만드는 버퍼 오버런 버그들은 이와 같은 스타일에서 발생한다.

비트연산자

  • 자바스크립트에서 비트연산자는 하드웨어에 매우 동떨어져있으며 속도도 매우 느리다. 그러므로 사용을 자제하는 것이 좋다.

함수 문장 vs 함수 표현식

  • 함수 문장은 var 문장과 함수값 조합의 축약형이다.
  • function foo() {}var foo = function foo() {}; 로 표현하는 것이 더 좋다.
  • foo 가 함수값을 가진 변수라는 것을 명확히 나타내기 때문이다.
  • 함수 문장은 hoisting 의 대상이 되기 때문에 함수를 사용하기 전에 반드시 선언해야 한다는 요구사항을 경감시켜 구조를 엉성하게 만들 수 있다.

데이터 타입 래퍼

  • new String(), new Boolean(), new Number() 등은 불필요할 때가 많으며 혼란을 줄 수 있기 때문에 리터럴을 사용해라.
  • new Object(), new Array(){}, [] 를 사용하는 것이 좋다.

new

  • new 를 빼먹지 않게 new 뒤에 올 객체명의 첫글자를 대문자로 하는 것이 좋다.

void

  • 자바스크립트에서 void 는 피연산자를 취한 후 undefined 를 반환하는 연산자인데 유용하지도 않고 혼동만 줄 뿐이므로 사용하지 않는 것이 좋다.
© 2020 by Kyunghwa Yoo.