오늘 공부한 JavaScript(이하 JS)의 내용을 SA로 정리해 본다.
앞서 JS는 동적언어라고 설명했는데, Q2 항목의 설명에서 알 수 있었던 동적언어의 단점에 조금 덧뎀하자면, 이는 코드의 작성자가 JS의 데이터타입의 개념을 명확하게 인지하고 있어야만 효율적인 코딩이 가능하다는 생각이 들어, 형변환의 이야기를 꺼내게 되었다.
JS는 동적언어 라는 말에 걸맞게 유연한 언어인데, 이는 [JS 엔진이 필요에 따라 실행하는 '암시적 변환']과 [코드 작성자의 명확한 의도가 반영 된 '명시적 변환']의 시행이 가능하기 때문이다.
일반적으로 [암시적 변환]의 대표적인 예로는 '산술연산자'와 앞서 언급한 '상동연산자'등이 있다.
산술연산자의 경우, +(더하기 연산)는 숫자(number)타입 보다 문자(string)타입이 우선시 되는 특징을 가져, 숫자형과 문자형의 데이터가 조합되면 문자형으로 강제 변환되어 연산 된다.
산술 연산자를 제외한 기타 연산자'(-, / , *, %)'들의 적용은 반대로, 문자 보다 숫자 데이터가 우선시 적용되므로 기억해 두면 좋을 것 같다.
다음으로 살펴 볼 [명시적 변환]은, 위와 달리 코드 작성자가 의도를 가지고 데이터 타입을 변환시키는 것을 말한다.
이는 각종 parseInt()나 Number(), String() 들의 매서드를 사용해 형태를 명시함으로서 형변환이 가능하다.
(아래의 모든 코드는 자료 조사 과정에서 [티스토리 / 배움이 즐거운 개발자] 블로그를 참조하여 작성하였음을 알려 드립니다. 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');
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 내부 프로퍼티들을 담아주고 있다.
해당 사례를 통해 불변객체의 필요성을 전달하고자 하였으나 한번에 쉽게 이해되는 개념이 아닌 것 같아 여러 차례 반복 학습과 체득 학습의 필요성을 크게 느낀다.
객체는 참조(reference) 형태로 전달하고 전달 받는다. 객체가 참조를 통해 공유되어 있다면 그 상태가 언제든지 변경될 수 있기 때문에 문제가 될 가능성도 커지게 된다. 이는 객체의 참조를 가지고 있는 어떤 장소에서 객체를 변경하면 참조를 공유하는 모든 장소에서 그 영향을 받기 때문인데 이것이 의도한 동작이 아니라면 참조를 가지고 있는 다른 장소에 변경 사실을 통지하고 대처하는 추가 대응이 필요하다.
의도하지 않은 객체의 변경이 발생하는 원인의 대다수는 “레퍼런스를 참조한 다른 객체에서 객체를 변경”하기 때문이다. 이 문제의 해결 방법은 비용은 조금 들지만 객체를 불변객체로 만들어 프로퍼티의 변경을 방지하며 객체의 변경이 필요한 경우에는 참조가 아닌 객체의 방어적 복사(defensive copy)를 통해 새로운 객체를 생성한 후 변경한다. 또는 Observer 패턴으로 객체의 변경에 대처할 수도 있다.
불변 객체를 사용하면 복제나 비교를 위한 조작을 단순화 할 수 있고 성능 개선에도 도움이 된다. 하지만 객체가 변경 가능한 데이터를 많이 가지고 있는 경우 오히려 부적절한 경우가 있다.
ES6에서는 불변 데이터 패턴(immutable data pattern)을 쉽게 구현할 수 있는 새로운 기능이 추가되었다.
모던 자바스크립트 Deep Dive / 위키북스 펴냄 / 11장 [원시 값과 객체비교 p.137 ~ 153 참고]
여기까지 공부를 통해 정리해 보고 나니, TDZ에서는 const님의 허락을 얻기 전 까지 호부호형을 할 수 없다는 사실을 알 수 있었다.
비로소 이국의 낯선 땅에서 태어난 JS에서 유사 조선의 노스텔지아가 물씬 느껴지는 것 같다.