ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 자바스크립트는 왜 그 모양일까? 8장 ~ 10장
    Books/자바스크립트는 왜 그 모양일까? 2022. 6. 14. 08:28

    { " number " : 8 , " chapter " : " 객체 " }

    - 자바스크립트는 객체라는 단어를 오버로드( overload )합니다.

    - 자바스크립트는 두 개의 빈값, 즉 null과 undefined를 제외한 모든 것을 객체로 취급한다.

     

    - 객체는 자바스크립트의 기본 데이터 구조

    - 객체의 각 속성에는 이름과 값이 있다

    - 다른 언어에서는 이런 객체를 해시 테이블, 맵, 레코드, 구조체, 연관( associative array ), 딕셔너리 그리고 dict 라고 불린다.

     

    - 객체 리터럴의 범위는 중괄호 { } 로 결정

    - 객체 리터럴의 속성

    1. 문자열 뒤에는 콜론( : ) 기호가 오고 그 뒤에 표현식이 오는 경우. 속성의 이름은 문자열이며, 속성의 값은 표현식이다.

    2. 이름 뒤에 콜론( : ) 기호가 오고 그 뒤에 표현식이 오는 경우. 속성의 이름은 문자열로 변환된 이름이며, 속성의 값은 표현식이다.

    3. 이름. 속성의 이름은 문자열로 변환된 이름이다. 속성의 값은 동일한 이름을 가지는 변수 혹은 매개변수의 값이다.

    4. 이름 뒤에 ' () 소괄호 '로 둘러싸인 매개변수 목록, 그 뒤에 함수 몸체가 ' {} 중괄호 ' 로 둘러 쌓인 경우. 이는 이름 뒤에 콜론 기호가 오고 그 뒤에 함수 표현식을 표시하는 것을 축약한 형태이다. 이 방식으로 : function 을 쓰는 것을 생략할 수 있지만, 코드 가독성을 생각했을 때 그만한 가치는 없어 보인다.

    let bar = "a long rod or rigid piece of wood or metal";
    let my_little_object = {
        "0/0" : 0,
        foo : bar,
        bar,
        my_little_method() {
            return "So small.";
        }
    }
    my_little_object.foo === my_little_object.bar	// true

    - 객체의 속성은 이름과 점( . ) 표기법으로 접근 가능

    my_little_object["0/0"] === 0		// true

    - 객체의 속성은 대괄호로도 접근 가능

    my_little_object.rainbow			//undefined
    my_little_object[0]				//undefined

    - 객체에게 찾을 수 없는 속성 값을 요청하면, 객체는 undefined 라는 빈 값을 반환

    my_little_object.age = 39;
    my_little_object.foo = "slightly frilly or fancy";

    - 할당문을 통해 객체에 새로운 속성을 추가 가능, 이미 존재한다면 새로운 값으로 변경

     

    - 객체에는 undefined를 저장하지 않는 것이 좋다.

    delete my_little_object["0/0"]

    - 속성을 제거하려면 delete 연산자를 사용

    typeof my_little_object === "object"		//true

    - typeof 연산자는 객체에 대해서 " object " 라는 문자열을 반환

     

    복사

    - Object.assign 함수로 객체의 속성들을 다른 객체로 복사 가능

    - 객체를 복사하고 싶다면 빈 객체에 대입하면 된다

    let my_copy = Object.assign({}, my_little_object);

     

    상속

    - 자바스크립트에서 객체는 다른 객체를 상속받을 수 있다

    - 자바스크립트의 상속은 데이터만 연결되므로 애플리케이션 구조를 취약하게 만들 가능성을 줄여준다.

    - Object.create(prototype) 은 이미 있는 객체를 전달받아서 이를 상속받는 새로운 객체를 반환

        ㆍ즉, 기존의 객체가 새로운 객체의 prototype이 되는 것

        ㆍ모든 객체가 프로토타입이 될 수 있다

        ㆍ프로토타입을 상속받은 객체 역시 다른 새로운 객체의 프로토타입이 될 수 있다.

        ㆍ프로토타입 체인의 길이에 제한은 없지만, 짧은 것이 당연히 좋다.

    - 개체에 없는 속성을 참조하려 할 때, undefined를 반환하기 전에 시스템을 해당 객체의 프로토타입을 확인하고, 프로토타입의 프로토타입을 확인하는 식으로 거슬러 올라간다. 프로토타입 체인 중에 같은 이름의 속성을 발견하면, 마치 해당 객체가 가지고 있던 속성인 것처럼 값을 반환한다

    let my_clone = Objectl.create(my_little_object);
    my_clone.age;				// 39
    my_clone.age += 1;
    my_clone.age;				// 40
    delete my_clone.age;
    my_clone.age;				// 39

    - 프로토타입을 쓰는 주된 용도 중 하나는 함수를 저장하는 공간으로 사용하는 것이다.

    - 객체가 객체 리터럴로 만들어지면 그 객체는 Object.prototype을 상속 받는다

        ㆍ비슷하게 배열은 Array.prototype의 메서드를 상속받는다
        ㆍ숫자 역시 Number.prototype 메서드들을 상속받는다.

        ㆍ함수조차도 Function.prototype 메서드를 상속받는다.]

    - 배열이나 문자열의 메서드는 상당히 유용한 반면, Object.prototype의 메서드들은 거의 쓸모가 없다.

     

    - Object.create(null)을 써서 객체가 아무것도 상속받지 않게 만들 수 있다.

        ㆍ원하지 않는 상속이나, 상속받는 값 때문에 헷갈리는 경우가 없다.

     

    - Object .keys(object) : 상속받은 속성을 제외한 객체의 나머지 모든 속성의 이름을 문자열의 배열로 반환한다

     

    동결

    - Object.freeze(object) : 객체를 전달 받아서 동결한다

        ㆍ즉, 변경할 수 없게 만든다.

        ㆍ불변성은 시스템을 더 신뢰할 수 있게 만든다.

    - Object.freeze(object) 와 const문은 아주 다른 일을 한다.

        ㆍObject.freeze 는 값에 적용

        ㆍ반면에 const는 변수에 적용

        ㆍconst 변수는 변경 가능한 객체를 저장해도 그 객체는 여전히 수정 가능,

             그 대신 const 변수에 다른 객체를 저장할 수 없다.

        ㆍ반면 Object.freeze 는 일반 변수에 불변 객체를 지정해도 객체를 변경할 수 없다.

             그 대신 변수에 다른 값을 저장할 수 있다.

    Object.freeze(my_copy);
    const my_little_constant = my_little_object;
    
    my_little_constant.foo = 7;			// allowed
    my_little_constant = 7;				// SYNTAX ERROR!
    my_copy.foo = 7;				// EXCEPTION!
    my_copy = 7;					// allowed

     

    프로토타입과 동결을 같이 쓰지마세요

    - 객체가 동결되어 있다면 , 즉, 프로토타입의 속성이 불변이라면 상속받은 객체는 해당 속성을 자신만의 버전으로 가질 수 없습니다.

     

    WeakMap

    - WeakMap은 문자열을 제외한 다른 객체를 키로 쓴다. 객체와는 완전히 다른 인터페이스다.

    Object WeakMap
    object = Object.create(null); weakmap = new WeakMap();
    object[key] weakmap.get(key)
    object[key] = value; weakmap.set(key, value);
    delete object[key] weakmap.delete(key);

    - 객체는 키로 문자열만 허용, WeakMap은 키로 객체만을 허용

    const secret_key = new WeakMap();
    secret_key.set(object, secret);
    
    secret = secret_key.get(object);

     

    - 봉인자 ( sealer ) : 객체를 전달하면 열 수 없는 상자를 반환

    - 개봉자 ( unsealer ) : 객체로 복구하려면 일치하는 상자

    function sealer_factory() {
        const weakmap = new WeakMap();
        return {
            sealer(object) {
                const box = Object.freeze(Object.create(null));
                weakmap.set(box,object)
                return box;
            }
            unsealer(box) {
                return weakmap.get(box);
            }
        }
    }

    - WeakMap은 자바스크립트의 가비지 컬렉터와 잘 맞는다.

        ㆍ존재하는 키의 사본이 더 이상 없다면, 해당 키의 속성은 자동 삭제

        ㆍ메모리 누수를 막을 수 있다.


    { " number " : 9 , " chapter " : " 문자열 " }

    기초

    const my_little_array = [99,111,114,110];
    const my_little_string = String.fromCharCode(...my_little_array);	// 'corn'
    my_little_string.charCodeAt(0) === 99;					// true
    my_little_string.length;						// 4
    typeof my_little_string							// "string"
    my_little_string.indexOf(String.fromCharCode(111, 104))		// 1
    my_little_string.indexOf(String.fromCharCode(111, 110))		// -1 ( 존재하지 않기에 )
    my_little_array === my_little_array					//true	
    my_little_array === [99, 111, 114, 110]					//false
    my_little_string === String.fromCharCode(99, 111, 114, 110)		// true

    - 문자열은 그 값이 같을 경우 === 연산자에 의해 동일하다고 판단된다.

    - 하지만 배열은 그 값이 같아도, 배열이 서로 다르면 다르다

    - 문자열의 동등성 검사는 아주 강력한 기능으로 값이 같으면 같은 객체라고 취급할 수 있기 때문에 심벌형이 필요가 없다.

     

    유니코드

    my_little_string === "corn"		// true
    "uni" + my_little_string		// "unicorn"
    3 + 4					// 7
    String(3) + 4				// 34
    3 + String(4)				// 34

    - 자바스크립트에는 문자(character) 형이 없다.

    - 문자열은 만들어지면 동결된다. ( 변경 x )

     

    템플릿 문자열 리터럴

    const old_form = (
        "Can you"
        + "\nbelieve how"
        + "\nincredibly"
        + "\nlong this"
        + "\nstring literal"
        + "\nis?"
    );
    
    const new_form = ` Can you
    believe how
    incredibly
    long this
    string literal
    is?`;
    
    old_form === new_form		// true

    - 템플릿 문자열 리터럴은 여러 줄에 걸쳐 쓸 수 있는 문자열 리터럴

    - 백틱( backtick ) 으로 더 많이 알려진 ` 가 구분자로 사용된다.

    - 기존의 형식으로 저장하고 프로그램은 자원의 일부로서 텍스트에 접근하고 사용

                        → 이런 새로운 문법은 좋지 않은 습관을 유발

     

    let fear = "monsters";
    
    const old_way = "The only thing we have to fear is " + fear + ".";
    const new_way = `The only thing we have to fear is ${fear}.`;
    
    old_way === new_way		// true

    - 템플릿 문자열 리터럴의 이점 중 하나는 문자 보간(interpolation)을 제공한다는 것

    - 템플릿 문자열 리터럴 안에 ${ }를 써서 올바른 표현식을 넣을 수 있다.

     

    - 문자 보간을 제공하는 템플릿 문자열 리터럴처럼 템플릿은 기본적으로 안전하지 않다

    - 보안 위험성을 완화시킬 수 있는 방법은 태그(tag) 함수라는 특별한 함수 적용

        ㆍ템플릿 문자열 리터럴 바로 앞에 함수 표현식을 쓰면 해당 함수가 호출되는데

                                       해당 함수에 대한 인자로 템플릿 문자열과 표현식의 값들이 전달된다.

        ㆍ태그는 이렇게 전달된 값들에 대해서 필터링하고, 인코딩하고 조립한 다음 반환

    function dump(strings, ...values) {
        return JSON.stringify({
            strings,
            value
        }, undefined, 4);
    }
    
    const what = "ram";
    const where = "rama lama ding dong";
    
    const result = dump`Who put the ${what} in the ${where}?`;
    // The result is `{
    //     "strings": [
    //         "Who put the ",
    //         " in the ",
    //         "?"
    //     ],
    //     "values": [
    //         "ram",
    //         "rama lama ding dong"
    //     ]
    // }`

    - 태그 함수를 제대로 만들고 제대로 쓴다면 XSS나 그 외에 보안 취약점을 막을 수 있다

    - 하지만 기본적으로 템플릿은 위험하다는 사실을 명심할 것

     

    정규표현식

    - String의 match, replace, search, split 함수는 인자로 정규표현식 객체를 받는다.

    - 정규 표현식 객체는 또한 그만의 고유한 메서드인 exec, test를 가집니다.

    - 정규 표현식 객체는 문자열에 대해서 일치하는 패턴이 있는지 찾는다. 패턴을 표현하는 강력한 방법

     

    토큰화

    - 컴파일러는 컴파일 과정에서 소스코드를 토큰화한다.

    - 안타깝게도 자바스크립트는 토큰화하기에는 아주 어려운 언어다. 

     

    Fulfill

    - 템플릿 문자열의 문자 보간 대신 쓸만한 것이 바로 fulfill 이라는 함수이다.

    - Fulfill은 심벌릭 변수가 포함된 문자열, 그리고 심벌릭 변수를 대체할 수 있는 값이 포함된 객체나 배열을 인자로 받는다. 또한 값을 대체할 때 인코딩할 수 있는 함수나 함수 객체를 추가로 전달할 수 있다.

     

    const template = "<p>Lucky {name.first} {name.last} won ${amount}.</p>";
    
    const person = {
        first: "Da5id"
        last: "<script src=https://enemy.evil/pwn.js/>"
    }
    
    fulfill(
        template,
        {
            name: person,
            amount: 10
        },
        entityify			
    )
    // "<p>Lucky Da5id &lt;script src=enemy.evil/pwn.js/&gt; won $10.</p>"

    - entityify 인코더는 아주 나쁜 스크립트를 위험하지 않은 HTML 태그로 대신 표현


    { " number " : 10 , " chapter " : " 빈 값 " }

    - 빈값( bottom value )은 재귀적 데이터 구조의 끝을 가리키거나 값이 없음을 뜻하는 특수한 값

    - 프로그래밍 언어에서 빈 값은 null, none, nothing, null과 같은 이름을 가집니다.

     

    - NaN 역시 숫자가 아님을 뜻하니 빈 값이라고 볼 수도 있다

    - 자바스크립트는 두 개의 빈 값, 즉 null과 undefined를 가지고 있다.

     

    - 자바스크립트는 let이나 var 구문으로 변수를 정의하고 초기화하지 않으면, 자바스크립트는 묵시적으로 이 변수 값을 undefined로 초기화한다.

    - 함수에 추분한 수의 인자를 넘겨 주지 못하면, 남는 매개변수의 값은 undefined로 설정

    - 객체에 특정 속성 값을 요청했는데 객체가 그 속성을 가지고 있지 않다면 undefined를 반환

    - 배열에 특정 요소를 요청했는데 그 요소가 배열에 없다면 undefined를 반환

     

    - typeof null이 "null" 아닌 "object"를 반환한다.

     

    - undefined는 엄밀히 말하면 null을 쓰는 것보다는 낫지만, 경로 문제라는 골칫거리가 있다

    - undefined는 객체가 아니기 때문에 undefined에서 속성 값을 읽으려고 시도하면 예외가 발생한다.

    my_little_first_name = my_little_person.name.first;

    - my_little_person에 name속성이 없거나, my_little_person이 undefined라면 예외 발생

    my_little_first nmae = (
        my_little_person
        && my_little_person.name
        && my_little_person.name.first
    );

    - 우스꽝스런 코드지만 예외를 일으키지 않는다.

    댓글

Designed by Tistory.