220520_ JS_S.A (TIL)

천처니·2022년 5월 20일
0

TIL

목록 보기
7/16

오늘 공부한 JavaScript(이하 JS)의 내용을 SA로 정리해 본다.


Q1. JavaScript의 자료형과 JavaScript만의 특성은 무엇일까 ?

  • JS는 다른 언어들과 다르게 상동 연산자로 == '만' 사용하지 않고, === 도 사용한다.
    === 의 경우는 타입과 값 '까지' 매칭하는, 엄격한 평가를 거치고, ==만 사용한다면 값만 비교한다.

Q2. 느슨한 타입(loosely typed)의 동적(dynamic) 언어의 문제점은 무엇이고 보완할 수 있는 방법에는 무엇이 있을지 생각해보세요.

  • 컴파일을 거친 후에 화면에 표시해 주는 '정적언어(컴파일 언어)'와는 달리 컴파일을 거치지 않는 JS(외에도 Python 등이 있다.)는 '동적언어(인터프리터 언어)'로, 전자의 경우에는 컴파일 과정에서 변수의 타입을 정하지만 후자의 경우엔 실행 시 변수의 타입이 결정 된다는 특징을 갖는다.
    이는 필연적으로 결과 값을 내놓을 때의 안정성 문제를 야기할 수 있는데, 사람의 경우에 대입해 보면, 자료를 문서로 정리해 발표하는 철수와 머리에서 바로 떠오르는 발의안을 발표하는 영수를 예로 들 수 있겠다.
    철수의 발표는 발표 도중 예상치 못한 질의 응답을 하게 되어도 발표의 흐름에 지장이 생기지 않겠지만, 영수의 경우엔 예상치 못 했던 변수가 발생하면 발표를 망치게 될 수도 있을 것이다. 이를 동적 언어와 정적 언어의 개념에 대입해 볼 수 있을 것으로 생각 된다.
    이 밖에도 동적언어와 정적언어를 비교했을 때 알 수 있는 문제점은 많겠으나, 가장 대표적으로 쉽게 알 수 있는 동적언어의 문제점을 짚어 보았다.
    다음으로 이어질 Q(question)의 내용들을 통해 데이터 객체에 대해 조금 더 이해하려는 노력을 가져보자.

Q3. JS의 형변환

  • 앞서 JS는 동적언어라고 설명했는데, Q2 항목의 설명에서 알 수 있었던 동적언어의 단점에 조금 덧뎀하자면, 이는 코드의 작성자가 JS의 데이터타입의 개념을 명확하게 인지하고 있어야만 효율적인 코딩이 가능하다는 생각이 들어, 형변환의 이야기를 꺼내게 되었다.

    JS는 동적언어 라는 말에 걸맞게 유연한 언어인데, 이는 [JS 엔진이 필요에 따라 실행하는 '암시적 변환']과 [코드 작성자의 명확한 의도가 반영 된 '명시적 변환']의 시행이 가능하기 때문이다.
    일반적으로 [암시적 변환]의 대표적인 예로는 '산술연산자'와 앞서 언급한 '상동연산자'등이 있다.

    산술연산자의 경우, +(더하기 연산)는 숫자(number)타입 보다 문자(string)타입이 우선시 되는 특징을 가져, 숫자형과 문자형의 데이터가 조합되면 문자형으로 강제 변환되어 연산 된다.
    산술 연산자를 제외한 기타 연산자'(-, / , *, %)'들의 적용은 반대로, 문자 보다 숫자 데이터가 우선시 적용되므로 기억해 두면 좋을 것 같다.
    다음으로 살펴 볼 [명시적 변환]은, 위와 달리 코드 작성자가 의도를 가지고 데이터 타입을 변환시키는 것을 말한다.
    이는 각종 parseInt()나 Number(), String() 들의 매서드를 사용해 형태를 명시함으로서 형변환이 가능하다.


Q4. JS 객체와 불변성이란?

- 코딩을 하게 되면 필연적으로 변수를 '선언'하게 되는데, 이 때 변수에 값을 '할당'했다고 말한다. 그리고 내가 '할당'한 이 값은 '메모리의 주소'를 가리키게 되는데, 이를 '참조'라고 한다.

(아래의 모든 코드는 자료 조사 과정에서 [티스토리 / 배움이 즐거운 개발자] 블로그를 참조하여 작성하였음을 알려 드립니다. https://galid1.tistory.com/663)

간단한 변수 선언을 통한 예를 들자면,
 let JS = 'so tough'

라는 선언을 했을 때, 메모리에는 'so tough' 라는 값이 생성되고, JS라는 변수가 이 메모리의 주소를 '참조' 하고 있다.
여기까지는 간단한 선언에서의 메모리 작동 기전이지만, 키와 벨류 값이 주어지는 오브젝트(객체) 에서는 어떨까.

 let study1 = {
 	js : 'tough'
    HTML : 'loose'
    CSS : 'interesting'
    ...  // 더욱 많은 프로퍼티가 존재한다고 가정함.
 }
 
 const StudyHard = function(study, newLanguage){
	let newstudy = study;
    newstudy.js = newLanguage;
    return newstudy;
 }
    
 let study2 = studyhard(study1, 'crazy');
 let study3 = studyhard(study1, 'holy');
 let study4 = studyhard(study1, 'deadly');
 let study5 = studyhard(study1, 'god');
 

이 코드는 틀렸다. 이러한 문제가 발생한 이유는 study 1번에서 5번 까지가 모두 같은 주소 공간을 향하고 있고, 그 주소 공간 중 js 라는 프로퍼티가 참조하는 데이터를 변경하였기 때문에 모든 변수에 담긴 js 프로퍼티의 값이 일괄적으로 변경 되버린 거다. 따라서 문제를 해결하기 위해서는 원본 객체 내부의 프로퍼티들을 복사한 새로운 객체를 생성하여 변수에 할당해 줘야 한다. 해당 코드를 올바르게 작성하면 아래와 같다.
let study1 = {
    js: 'tough',
    HTML: 'loose',
    CSS: 'interesting'
}

const StudyHard = function (study, newLanguage) {
    return {
        js: newLanguage,
        HTML: study.HTML,
        CSS: study.CSS
    }
}

study2 = StudyHard(study1, 'crazy');
study3 = StudyHard(study1, 'holy');
study4 = StudyHard(study1, 'deadly');
study5 = StudyHard(study1, 'god');


console.log(study1. js)
console.log(study2. js)
console.log(study3. js)
console.log(study4. js)
console.log(study5. js) 
해당 코드를 실행하면 나오는 값은 이렇다.

변경 된 코드를 살펴보면, 이번엔 변수를 선언하고, 매개변수로 전달 된 study 변수를, study 변수가 참조하는 주소 공간에 할당하지 않고, 새로운 객체를 생성하여 study 내부 프로퍼티들을 담아주고 있다.
해당 사례를 통해 불변객체의 필요성을 전달하고자 하였으나 한번에 쉽게 이해되는 개념이 아닌 것 같아 여러 차례 반복 학습과 체득 학습의 필요성을 크게 느낀다.

참고) Immutability(변경불가성)는 객체가 생성된 이후 그 상태를 변경할 수 없는 디자인 패턴을 의미한다. Immutability은 함수형 프로그래밍의 핵심 원리이다.

객체는 참조(reference) 형태로 전달하고 전달 받는다. 객체가 참조를 통해 공유되어 있다면 그 상태가 언제든지 변경될 수 있기 때문에 문제가 될 가능성도 커지게 된다. 이는 객체의 참조를 가지고 있는 어떤 장소에서 객체를 변경하면 참조를 공유하는 모든 장소에서 그 영향을 받기 때문인데 이것이 의도한 동작이 아니라면 참조를 가지고 있는 다른 장소에 변경 사실을 통지하고 대처하는 추가 대응이 필요하다.

의도하지 않은 객체의 변경이 발생하는 원인의 대다수는 “레퍼런스를 참조한 다른 객체에서 객체를 변경”하기 때문이다. 이 문제의 해결 방법은 비용은 조금 들지만 객체를 불변객체로 만들어 프로퍼티의 변경을 방지하며 객체의 변경이 필요한 경우에는 참조가 아닌 객체의 방어적 복사(defensive copy)를 통해 새로운 객체를 생성한 후 변경한다. 또는 Observer 패턴으로 객체의 변경에 대처할 수도 있다.

불변 객체를 사용하면 복제나 비교를 위한 조작을 단순화 할 수 있고 성능 개선에도 도움이 된다. 하지만 객체가 변경 가능한 데이터를 많이 가지고 있는 경우 오히려 부적절한 경우가 있다.

ES6에서는 불변 데이터 패턴(immutable data pattern)을 쉽게 구현할 수 있는 새로운 기능이 추가되었다.

모던 자바스크립트 Deep Dive / 위키북스 펴냄 / 11장 [원시 값과 객체비교 p.137 ~ 153 참고]



Q5. 스코프, 호이스팅, TDZ

- 앞선 문단에서는 객체와 메모리간의 관계를 비롯하여 방대한 JS지식의 일편을 살펴봤으니 마지막으로는 호이스팅과 스코프, TDZ의 개념을 공부했다. 호이스팅(hoisting)은, 변수와 함수의 메모리 공간을 선언 전에 미리 할당하는 것으로, 실제 기술예제에서는 평소에 의식하지 않고 막연하게 '여기서 변수를 선언해야지'라고만 알고있던 개념을 설명하고 있었다. 이는 스코프(scope)의 개념을 설명할 수 있게 해주는데, JS에서의 스코프는 '유효범위'를 말한다. 조금 더 자세하게 설명하면, 변수를 선언할 수 있는 [let, var, const]의 차이를 좀 더 명확하게 설명할 수 있는 개념으로, var의 경우 변수를 초기화 하는 특징을 가진 반면, let과 const는 호이스팅 시, 변수를 초기화 하지 않는다는 개념을 숙지하고 가야 한다. 일반적으로 함수(반복문과 조건문 외...)의 매개변수는 중괄호를 사용해 묶어 둔 함수의 body 내부에서만 참조가 가능하고 그 밖에서는 참조할 수 없었는데 이 이유가 스코프(유효범위) 때문이다. 마지막으로, Temporal Dead Zone(이하 TDZ)은 let, const, class 구문의 유효성을 관리한다. 영단어가 길어 굉장히 어려운 개념이라고 우려했던 처음의 예상과 달리, 앞선 스코프와 포이스팅을 좀 더 포괄적으로 아우르는 개념이다. 스코프는 중괄호 바디 안의 영역을 설명할 수 있었다면 TDZ는 스크립트가 실행되는 영역 전반에 걸쳐 '변수를 변수로 선언하기 전 까지는 사용하지 않는 영역'을 말하는 '호부호형'의 개념으로 볼 수 있겠다.

여기까지 공부를 통해 정리해 보고 나니, TDZ에서는 const님의 허락을 얻기 전 까지 호부호형을 할 수 없다는 사실을 알 수 있었다.
비로소 이국의 낯선 땅에서 태어난 JS에서 유사 조선의 노스텔지아가 물씬 느껴지는 것 같다.



Q6. 실습 과제



이 밖에도 본격적으로 리액트 주간에 들어서며 기초 JS 문법에서는 배우지 않고 넘어갔던 객체(Object)와 데이터 타입에 대한 강의가 새로 등장하는데, 리액트에서는 이 객체와 데이터 타입의 개념이 상당히 중요한 개념이라고 미루어 짐작하고, 학습 방향 설정을 도모해 봐야겠다.

0개의 댓글