-
클린코드 자바스크립트 강의 (1)et cetera/TIL 2021. 12. 27. 15:37반응형
■ 임시변수 줄이기
function getDateTime(targetDate) { let month = targetDate.getMonth(); let day = targetDate.getDay(); let hour = targetDate.getHour(); month = month >= 10 ? month : '0' + month; day = day >= 10 ? day : '0' + day; hour = hour >= 10 ? hour : '0' + hour; return { month, day, hour }; }
- 위 함수가 할 수 없는 추가적인 스펙을 구현해야하는 상황이 오면 우리는 두 가지 선택을 할 수 있다.
새로 함수를 만들어서 사용하느냐, 아니면 위의 함수를 유지보수/수정하느냐의 두 가지 선택.
만약 함수를 수정해서 사용하기로 결정했다고 하면,
기존에 위의 함수를 사용하던 곳들에서 예상치 못한 문제가 여럿 발생할 수 있다.
따라서 기존의 함수가 수정될 수 있는 여지를 최대한 줄이는 것이 바람직할 것.
- 임시 변수가 많아져서 특정 변수가 함수 내부의 여기저기서 재할당되고 연산되고 하면
해당 변수가 어떻게 변화하는지 그 과정을 추적하기가 어려워지게 된다.
흔히들 안좋다고 말하는 '명령형 코드'가 되어버리는 것.
그러면 임시변수를 많이 만들지말라는 맥락에서 위의 함수를 수정해보자.
강사는 let으로 변수를 만들어놓는 것은 '수정하고, 재할당 할 수 있다' 라는 약속을 암시하기 때문에
함수가 수정될 수 있는 여지를 줄여놓기 위해 const로 바꾸는 것을 권장한다.
함수 내부에 작성된 접근 로직은 바로 리턴을 해주는 형태로 바꿔주면 된다고 한다.
함수는 다음과 같이 수정될 수 있다.
function getDateTime(targetDate) { const month = targetDate.getMonth(); const day = targetDate.getDay(); const hour = targetDate.getHour(); return { month: month >= 10 ? month : '0' + month, day: day >= 10 ? day : '0' + day, hour: hour >= 10 ? hour : '0' + hour, }; }
만약 추가 스펙을 구현해야하는 상황이 생기면 새로운 함수를 만들어서 사용하되,
해당 함수의 내부에서 위 함수를 사용해주는 방식으로 재사용을 해주면 된다.
function getDateTimeString() { const currentDateTime = getDateTime(new Date()); return { month: currentDateTime.month + '달 전', day: currentDateTime.day + '일 전', hour: currentDateTime.hour + '시간 전', }; }
이렇게 하면 함수의 재사용성도 높아진다.
하나의 함수는 하나의 역할만 명확하게 하면 되는건데,
임시변수라는 유혹에 빠지면 함수 내부에서 임시변수를 계속 지지고 볶고 하는 로직이 늘어나게 되면서
하나의 함수가 하나의 역할을 명확하게 가지기 어렵게 된다.
정리하자면, 임시변수를 많이 만든다는 것은 결국에는 명령형으로 코드를 작성한다는 것과 유사하다.
특정 변수가 어디서 어떻게 사용되는지 디버깅하기가 점점 어려워지고,
누군가 추가적인 스펙을 구현해야할 때, 기존 함수가 임시변수로 가득하다면
해당 함수를 고치거나 추가적인 코드를 작성하고 싶은 유혹에 빠지기가 쉽다.
그 결과로 하나의 함수가 한 가지 역할만 하기 힘들게 되기도 하고.
결국 최종적으로는 유지보수하기 어려운 코드가 탄생하게 되는 것.
따라서, 함수 내부에서 임시 변수를 만드는 일을 최대한 줄이고(바로 return, 고차 함수 사용),
새로운 스펙을 구현해야하는 상황이 오면 기존에 존재했던 함수를 재사용하며
새로운 함수로 추상화하여 사용하라(함수를 계속 나눠라)는 것이 강사의 요지라고 할 수 있겠다.
■ 타입 검사하기
- typeof 연산자
typeof 연산자는 primitive 값은 잘 구별하는 반면, reference 값을 구별하지 못한다는 단점이 있다.
class를 function으로 판단하거나, wrapper 객체나 null도 object로 판단하는 등 완전한 구별이 불가능하다.
typeof '문자열' // 'string' typeof true // 'boolean' typeof undefined // 'undefined' typeof 123 // 'number' typeof Symbol() // 'symbol'
function myFunction() {} class MyClass {} typeof myFunction // 'function' typeof MyClass // 'function' typeof new String('문자열') // 'object' typeof null // 'object'
- instanceof 연산자
function Person(name, age) { this.name = name; this.age = age; } const person = { name: '홍길동', age: 20 }; const person2 = new Person('임꺽정', 29); person instanceof Person // false person2 instanceof Person // true
하지만, 역시나 객체(reference 값)와 관련해서는 타입 구분에 어려움이 따른다.
자바스크립트의 배열, 함수, Date 객체 등은 프로토타입 체인으로 인해
결국 최상위에는 Object 객체가 위치하고 있기 때문.
const arr = []; const func = function() {} const date = new Date(); arr instanceof Array // true func instanceof Function // true date instanceof Date // true arr instanceof Object // true func instanceof Object // true date instanceof Object // true
- Object.prototype.toString.call()
그래서 typeof와 instanceof도 잘 사용해주면 좋지만,
다음과 같이 프로토타입 체인의 최상위에 Object가 있다는 사실을 역이용한 방법을 사용할 수도 있다.
이 방법을 사용하면 wrapper 객체나 배열, 함수, Date 객체 등을 모두 구별해낼 수 있다.
Object.prototype.toString.call('문자열'); // [object String] Object.prototype.toString.call(new String('문자열')); // [object String] Object.prototype.toString.call(arr); // [object Array] Object.prototype.toString.call(func); // [object Function] Object.prototype.toString.call(date); // [object Date]
■ undefined vs null
undefined는 변수는 선언했지만 값이 정의되지 않은 것(할당되지 않음).
null은 값이 '없다' 라고 명시적으로 표현한 것.
Number(undefined) // NaN Number(null) // 0 typeof undefined // 'undefined' typeof null // 'object'
둘을 구분해서 조심히 사용할 것.
출처
반응형'et cetera > TIL' 카테고리의 다른 글
클린코드 자바스크립트 강의 (2) (0) 2021.12.29 객체지향 프로그래밍 입문 강의 (1) - 캡슐화 (0) 2021.12.27 타입스크립트 강의 내용 정리 (2) (0) 2021.12.23 타입스크립트 강의 내용 정리 (1) (0) 2021.12.22 Javascript Visualized: Promises & async/await (0) 2021.12.04