[비고] 상시 추가중
0. about:blank
아무것도 없는 빈 페이지.
콘솔에서 간단하게 테스트 하고 싶을 때, 빈 html에 엘리먼트 생으로 넣어보면서 테스트 하고 싶을 때 사용하면 좋다.
1. 즉시실행함수 (IIFE, Immediately Invoked Function Expression)
(function(){
// statements
})();
익명함수를 정의와 동시에 즉시 실행
안전한 스코핑을 위해 사용 - 내부에서 외부로 변수 등록 방지(전역변수 등록x), 외부에서 내부로 접근 방지
2. console.log
[로그가 찍히는 시점에 주의할 것]
console.log로 디버깅을 하는 것은 좋지만 로그를 맹신하면 안된다.
가장 치명적인 문제는 console.log가 객체(Array, Object)를 로깅할 때는 로그를 찍은 시점의 객체가 아니라 로그를 확인하는 시점에서 업데이트된 객체를 참조한다는 점이다.
무슨 말인가 하면 다음의 두 경우를 보자
둘 모두 배열에 값을 할당하거나 오브젝트의 밸류값을 변경해 주기 전에 log1을 찍었고, 실제로도 그렇게 찍힌듯 보인다.
그러나 자세한 로그값을 열어보면 로그를 남긴 시점의 값 대신 그 후에 변경된 값이 찍히는 것을 볼 수 있다.
두번째 사진에서 빨간 동그라미를 친 부분을 보면 그 이유를 알 수 있다.
바로 Value below was evaluated just now의 함정이다.
찍히는 값은 지금 막 최신의 상태를 반영한다. 불필요한 친절...이라기 보다는 call by reference 인스턴스이기 때문이다.
메모리 아끼자고 레퍼런스를 참조하는데 로그를 남길때마다 그 '값'을 복사해서 찍어준다면? 미친짓이다.
따라서 레퍼런스를 참조하는 값을 로깅할 때는 로그를 남긴 시점의 값을 보장하지 않는다는 점에 주의해야 한다.
당장은 이 문제가 크게 와닿지 않을 수 있지만 실제로 비동기 통신으로 받아온 데이터를 처리하는 과정에서 이 함정에 많이들 빠진다.
callback 함수나 Promise 객체나 async/await를 제대로 사용하지 않은 상태로 통신한 데이터에 접근하면 복불복 게임이 시작된다. 운이 좋게 접근 시점에 통신이 완료되어 data 변수에 잘 저장되었다면 문제가 없겠지만 대부분의 경우에는 Cannot ~~ of null/undefined 등의 오류를 뱉을 것이다. 통신이 끝나기도 전에 데이터에 접근하려 했기 때문이다.
그런데 이상하다. 혹시나 해서 요청 직후 console.log로 data를 찍는 라인을 넣었는데 콘솔창에서 이 로그를 확인하면 데이터가 항상 무사히 들어와 있다. 로그가 찍히는 것만 믿고 통신 처리 훅에 문제가 없다고 생각했는데 왜 접근하면 null이나 undefined가 뜨는걸까?
바로 로깅의 함정에 걸린 것이다.
3. 변수 선언 호이스팅
호이스팅 hoisting? 어디서 변수를 선언하든 변수 선언이 모두 최상위로 끌올됨.
1) 값이 선언되지 않으면 not defined 에러를 발생시킨다.
2) var로 후선언문을 적으면 호이스팅에 의해 선언 시점 이전에 값에 억세스해도 undefined 값으로 인식하지 에러를 발생하지 않는다. (값이 할당되지 않음)
3) let과 const또한 호이스팅이 이루어진다. 따라서 is not defined에러가 발생하지 않는다.
다만 TDZ(Temporal Dead Zone)가 생성되어 실제로 값이 선언된 시점에 도달하기 전까지 Cannot access before initialization에러를 발생한다. (메모리가 할당되지 않음)
즉, var, let, const 모두 호이스팅에 의해 선언단계가 우선실행 되지만 (변수? 그런 애가 있기는 있음!),
var는 선언과 동시에 undefined로 메모리를 할당하는 초기화 단계가 함께 일어나는 반면 (변수? 걔 undifined 일걸?)
let과 const는 메모리 초기화는 일어나지는 않는다는 차이가 있다. (변수? 있었는데요 (메모리 공간은)없었습니다)
볼드모트 같은 느낌이다. 이름이 있지만 그의 이름을 불러서는 안 돼!
4. sort
[js의 sort() 이용시 주의사항]
- 원본배열이 바뀜
- 소팅 대상의 유니코드 값에 따라 정렬 ☞ 숫자 정렬 크기순으로 안됨
[compareFunction]
sort((a,b)=>{ ... }) sort함수의 compare func을 사용해 원하는 기준으로 정렬 가능
compare func의 리턴값 기준
- 양수 : a>b로 인식 (b,a 순으로 정렬)
- 0 : 변경하지 않고 넘어간다
- 음수 : a<b로 인식 (a,b 순으로 정렬)
숫자 오름차순, 내림차순 정렬 팁 ((Infinity 및 NaN이 포함되어 있지 않은 경우)
sort((a,b)=>a-b); 오름차순
sort((a,b)=>b-a); 내림차순
5. 이차원 배열 생성
[new Array]
길이가 n인 빈 배열을 생성할 때는 new Array(n);
초깃값을 k를 넣어서 생성할 때는 new Array(n).fill(k);
이걸 고대로 사용해 n x m 의 이차원 배열을 다음과 같이 만들 수 있을까?
new Array(n).fill(new Array(m).fill(k));
결론은 안된다. 만들어지긴 하는데 다음과 같이 예상하지 못했던 일이 벌어진다.
arr 상위 배열의 0번째 요소인 하위배열에만 접근해 1번 인덱스의 값을 바꿨는데 하위배열들 전체에 적용이 된다.
new Array(m).fill(0)으로 생성한 하위 배열의 레퍼런스만 복사되어 상위 배열의 요소에 들어가기 때문이다.
[2차원 배열 생성]
따라서 다음과 같이 Array.from을 사용해 생성한다. ES6기준으로 추가된 문법이다.
Array.from(Array(n), () => new Array(m).fill(0));
6. 오브젝트 복사
[1단계 - Object.assign(), spread]
5번과 연관된 내용이다.
javascript에서 오브젝트를 복사하다보면 생각지 못 한 난관에 봉착하게 된다.
오브젝트는 call by reference 인스턴스이다.
따라서 아무 생각없이 원본 객체를 그대로 할당해주면 이런 해프닝이 발생한다.
사실 이정도 쯤이야 Object.assign()이나 spread 연산자로 쉽게 물리칠 수 있다.
[n단계]
하지만 실제 사용되는 데이터는 다음과 같이 중첩된 놈들이 수두룩하다는게 문제다.
let layout = {
title: 'original layout',
xaxis: {
title: 'time'
},
yaxis : {
title : 'price',
showline : false
}
}
plotly.js라는 차트 라이브러리의 레이아웃을 정의하는 속성을 가져와봤다. 이정도만 해도 굉장히 심플한 형태이다.
저 레이아웃 객체를 디폴트 변수로 저장해 두고 차트를 만들 때 마다 디폴트 값을 복사한 뒤 커스텀하여 사용하고 싶다.
그러나 assign과 spread도 중첩된 하위 오브젝트들에 대해서는 참조값을 원본과 공유하게끔 복사한다.
최상위 레벨 프로퍼티만 참조 없이 복사되는 얕은 복사(shallow copy)를 지원하기 때문이다.
따라서 layout 오브젝트의 최상위 프로퍼티인 title은 독립적으로 복사가 되었지만,
하위 오브젝트인 xaxis와 yaxis는 참조가 공유되는데에 그쳐 복사된 layout2와 layout3에서 값에 변경을 가하자 원본에 영향을 미친다.
[대안책]
이에 대한 해결방안으로는
- JSON.parse(JSON.stringify( Object ))
- 외부 라이브러리 사용
- 딥 카피가 가능한 커스텀 모듈 제작
등이 있다.
1. JSON.parse(JSON.stringify( ~~ )) 사용은 별로 추천하지 않는다.
인자로 받은 오브젝트를 JSON 문자열로 변환한 후 다시 문자열의 구문을 분석해 JSON 객체를 생성하는 방법이다.
모든 참조를 확실하게 끊어버릴 수 있지만 성능이 저조하고, 오브젝트의 함수 프로퍼티는 사라진다는 단점이 있다.
(함수 뿐만 아니라 Dates, undefined, Infinity, RegExps, Maps, Sets, Blobs, FileLists, ImageDatas, sparse Arrays, Typed Arrays 모두 카피 불가능하다)
2. 외부 라이브러리는
Ladash 라이브러리의 cloneDeep 메서드나 (참조 : lodash.com/docs/#cloneDeep)
노드 모듈을 사용한다면 deepcopy.js 패키지가 있다.(참조 : www.npmjs.com/package/deepcopy)
lodash는 그 외에도 데이터 가공을 위한 다양한 기능을 제공하는 라이브러리라 deepcopy만 사용할 목적이라면 후자를 추천한다.
3. custom function은 만들게되면 추가
7. 정규식
정규식 시각화해 보여주는 사이트 regexper.com/
Regexper
regexper.com
'프론트엔드 > 기타' 카테고리의 다른 글
[git] 브랜치 네이밍, 웹호스팅 (0) | 2020.12.22 |
---|---|
vscode에 git 연동해 사용하기 (0) | 2020.11.20 |
프론트엔드 개발환경의 이해 (중) - 바벨, 린트 (0) | 2020.11.16 |
프론트엔드 개발환경의 이해 (상) - npm, 웹팩 (0) | 2020.11.10 |
[javascript] 객체지향 - 함수&프로토타입과 클래스 (0) | 2020.11.09 |