본문 바로가기

웹/공부

YOU DON`T KNOW JS(타입과 문법, 스코프와 클로저) : 3

반응형

해당 글은 'YOU DON`T KNOW JS(타입과 문법, 스코프와 클로저)' 라는 책을 읽으며

나름의 정리를 하는 글입니다.

 

 

 

 

 

* 배열, 문자열, 숫자는 모든 프로그램의 가장 기본적인 구성 요소지만 자바스크립트에서는 독특한 특성을 갖고 있음.

 

* 자바스크립의 배열은 문자열, 숫자, 객체, 심지어 다른 배열(이런 식으로 다차원 배열 생성)이나

  어떤 타입의 값이라도 담을 수 있음.

var a = [1, "2", [3]];
a.length; // 3
a[0] === 1; // true
a[2][0] === 3; // true

 

  배열 크기는 미리 정하지 않고도 선언할 수 있으며 원하는 값을 나중에 추가할 수 있음.

var a = [];
a.length; // 0
a[0] = 1;
a[1] = "2";
a[2] = [3];
a.length; // 3

 

  '구멍 난(sparse)' 배열을 다룰 때는 주의 필요.

var a = [];
a[0] = 1;

// [1] 슬롯은 건너 뜀

a[2] = [3];

a[1]; // undefined
a.length; // 3

  실행은 되지만 이런 '빈 슬롯'은 혼란을 야기시킴.

  a[1] 슬롯 값은 undefined가 될 것 같지만, 명시적으로 a[1] = undefined로 설정한 것과 같지는 않음.

 

  배열 인덱스는 숫자인데, 배열 자체도 하나의 객체여서 키/프로퍼티 문자열을 추가할 수 있다

  (하지만 배열 length가 증가하지는 않음)는 점이 다소 까다로움.

var a = [];
a[0] = 1;
a["foobar"] = 2;

a.length; // 1

a["foobar"]; // 2
a.foobar; // 2

 

  그런데 키로 넣은 문자열 값을 표준 10진수 숫자로 하는 경우, 마치 숫자로 키값을 사용한 것 같은 결과가 초래된다는

  점은 매우 주의 요함.

var a = [];
a["13"] = 42;
a.length; // 14

 

  일반적으로 배열에 문자열 타입의 키/프로퍼티 사용은 추천하지 않음.

  만약 그렇게 해야 한다면 객체를 대응하고 배열 원소의 인덱스는 확실히 숫자로 쓰는걸 추천.

 

* 문자열은 배열과 겉모습이 닮았음(유사배열).

  문자열과 배열은 length 프로퍼티, indexOf(), concat() 메서드 등을 가짐.

var a = "foo";
var b = ["f", "o", "o"];

a.length; // 3
b.length; // 3

a.indexOf("o"); // 1
b.indexOf("o"); // 1

var c = a.concat("bar"); // "foobar"
var d = b.concat(["b", "a", "r"]); // ["f", "o", "o", "b", "a", "r"]

a === c; // false
b === d; // false

a; // "foo"
b; // ["f", "o", "o"]

 

  문자열은 불변 값(Immutable), 배열은 가변 값(Mutable) 임.

  문자열은 불변 값이므로 문자열 메서드는 그 내용을 바로 변경하지 않고 항상 새로운 문자열을 생성한 후 반환.

  배열은 그 자리에서 곧바로 원소를 수정.

c = a.toUpperCase();
a === c; // false
a; // "foo"
c; // "FOO"

b.push("!");
b; // ["f", "o", "o", "!"]

 

  대부분의 배열 메서드는 사실상 문자열에 쓸 수 없지만, 문자열에 대해 불변 배열 메서드를 빌려 쓸 수는 있음.

a.join; // undefined
a.map; // undefined

var c = Array.prototype.join.call(a, "-");
var d = Array.prototype.map.call(a, function(v){
    return v.toUpperCase() + ".";
}).join("");

c; // "f-o-o"
d; // "F.O.O."

 

  하지만 reverse() 메서드와 같이 가변 메서드는 문자열이 불변 값이므로 통하지도 않고, 빌려 쓸 수도 없음.

a.reverse; // undefined

b.reverse(); // ["!", "o", "o", "f"]
b; // ["!", "o", "o", "f"]

Array.prototype.reverse.call(a); // Uncaught TypeError: Cannot assign to read only property '0' of object

  하여 꼼수(전문 용어로는 핵(Hack)이라고 함)로 할 수 있는 방법이 있음.

var c = a
    .split("") // 문자의 배열로 분할
    .reverse() // 배열 역정렬
    .join(""); // 배열을 문자열로 변환
c; // "oof"
더보기

하지만 조심하라!
복잡한(유니코드) 문자가 섞여 있는 경우(특수 문자, 멀티바이트(Multibyte) 문자 등) 이 방법은 통하지 않는다.
제대로 처리하려면 유니코드를 인식하는 정교한 라이브러리 유틸리티가 필요하다.
마티아스 바이넨(Mahtias Bynens)이 만든 에스레베르(Esrever)를 참고하자

더보기

에스레베르(Esrever)는 리버스(Reverse)를 거꾸로 한 것입니다.
프로그램 이름만 보아도 무슨 기능을 하는지 알 수 있도록 재미있게 명명한 것입니다.
https://github.com/mathiasbynens/esrever

반응형