In computer science, syntactic sugar is syntax within a programming language that is designed to make things easier to read or to express. 컴퓨터 과학 분야에서 ‘편리한 구문 용법’이란 읽기 쉽고 표현하기 쉽도록 구성된 프로그래밍 언어 내의 구문이다.
즉, 달콤한 초콜릿처럼 손이 자주 가는 구문이라고 볼 수 있을 것 같다.
자바스크립트는 처음부터 모든 기능을 갖고 태어나지 않았으므로 ES 버전으로 대표되는 추가 기능은 기존의 문법으로 구현된 것이 많다.
class 또한 기존의 OOP에서 차용한 개념을 자바스크립트에서 구현한 것으로 구현 방식은 자바스크립트의 문법을 벗어나지 않는다.
따라서 사용자가 선언하고 사용하는 방식은 다르지만 다음에서 확인할 두 코드의 작동 방식은 동일하다.
function으로 선언된 부분이 기본 동작 방식이며 class가 선언되면 이 function과 완전히 동일한 방식으로 구현된다.
같은 기능을 구현할 때 function과 class 중 어떤 것에 더 선뜻 손이 가는지를 묻는다면 설탕의 의미를 생각해볼 수 있다.
function 사용
function createGame( user, point ) {
this.user = user;
this.point = point;
}
createGame.prototype.addPoint = function() { this.point++; };
const myGame = new createGame("Yoon", 0);
myGame.addPoint();
전체 화면 설정 메서드 document.documentElement.requestFullscreen() 전체 화면 해제 메서드 document.exitFullscreen()
전체화면 설정/해제 버튼에 이벤트를 걸어서 사용할 수 있으며, 반환형은 Promise이다.
만약 allowfullscreen 속성이 없는 iframe에서 해당 메서드를 호출하면 어떻게 될까?disallowed by permissions policy 에러로 사람을 당황시킨다.
이 때는 allowfullscreen 속성의 존재 여부(true)를 체크해주면 되는데, 해당 속성은 document.fullscreenEnabled 속성을 사용해 true/false로 확인한다.
만약 iframe에 allowfullscreen 속성이 없을 때 전체 화면 버튼을 비활성화하고 싶을 때는 어떻게 할까?
document.fullscreenEnabled를 체크해서 활성/비활성을 결정하면 되는데 document is not defined와 같은 에러를 피하기 위해서는 useEffect 내부에서 해당 작업을 처리하여 렌더링이 완료된 시점에 document에 접근하도록 해야 한다.
let을 사용하면 0, 1, 2, 3, 4가 약 1초 뒤 한번에 출력되는 것을 확인할 수 있고 var를 사용하면 5가 다섯 번 출력되는 것을 확인할 수 있습니다.
우선 var는 왜 5를 다섯 번 출력할까요?
이는 이벤트 루프의 처리에 따라 setTimeout 메서드가 호출 스택에서 백그라운드를 거쳐 태스크 큐로 이동했다가 다시 콜 스택으로 돌아오는 동안 for 문이 모두 종료(콜 스택이 비어 있어야 태스크 큐에서 콜 스택으로 이동)되어 출력할 데이터는 i=5인 클로저를 참조하기 때문입니다.
그렇다면 var와 달리 let은 왜 순서대로 숫자가 출력될까요?
이는 스코프와 관련이 있습니다.
var는 함수 스코프를 가지므로 for 루프마다 같은 참조를 바인딩하고 let은 블록 스코프이므로 for 루프마다 새로운 참조를 바인딩하게 됩니다.
그렇다면 var를 사용하더라도 for 루프마다 새로운 참조를 바인딩하면 결과가 달라지지 않을까요?
배열 관련하여 각 요소별로 순회하는 반복문 작업을 할 때 가장 익숙한 방법을 사용하거나 때로는 가장 먼저 떠오르는 방법을 사용하기도 합니다.
배열의 크기가 작으면 상관이 없지만 배열의 크기가 커지면 작은 차이가 큰 차이를 만들어낼 수 있습니다.
문득 연산 속도가 가장 빠른 반복문이 무엇일까라는 궁금증이 생겨 간단하게 하나의 배열 데이터를 다른 배열로 옮기는 연산을 통해 속도를 테스트해보고자 합니다.
크기에 상관없이 반복문 별로 같은 효율을 보여주리라 생각했지만 배열의 크기에 따라 각각 다른 속도를 보여주는 점이 흥미로웠습니다.
1. 테스트 방법
먼저 일정 크기를 갖는 배열 array을 생성합니다.
console.time 메서드를 사용해 이 배열의 데이터를 다른 배열로 복사하는 작업을 진행하고 이 작업 시간을 측정합니다.
테스트는 map, for, while, for…in, for…of의 다섯 가지 반복문을 사용합니다.
// 배열 데이터 생성
const array = [];
for(let i=0;i<10000;i++){
array.push(i);
}
// 데이터가 복사될 배열
let arraymap = [];
console.time('map'); //타이머 시작
arraymap = array.map(list=>list);
console.timeEnd('map'); //타이머 종료
위와 같은 방식으로 3회씩 테스트를 진행하며 배열의 크기를 조절하여 반복문 별로 상대적인 작업 속도의 변화를 확인합니다.
2. 테스트
먼저 배열의 크기가 아주 작을 때는 모두 큰 차이를 보이지 않습니다.
다음은 배열의 크기가 100일 때 결과입니다.
작업을 세 번 진행한 결과 map과 for…of가 엎치락뒤치락하지만 항상 가장 빠른 속도를 보여줍니다.
for, while, for…in도 세번 모두 결과가 엎치락뒤치락하지만 위의 두 반복문보단 느린 속도를 보여줍니다.
그럼 배열의 크기를 1000으로 올려보겠습니다.
크기가 1000일 때는 대체적으로 비슷한 속도를 보여줍니다.
for…in만 다른 반복문보다 느린 것이 확인됩니다.
이제 확연하게 유의미한 차이를 느낄 수 있는 크기인 10000으로 올려보겠습니다.
10000에서는 map이 가장 우수한 속도를 보여줍니다.
눈에 띄는 부분은 작은 사이즈에서는 map과 대등한 속도를 보이던 for…of가 여기서는 가장 느린 속도를 기록합니다.
또한 for…in은 오히려 for…of보다 빠른 속도를 보여줍니다.
그럼 1000000으로 확인해 보겠습니다.
배열이 매우 커지니 작업 속도는 for문이 가장 준수합니다.
map, while도 큰 차이를 보이지 않고 준수한 성능을 보여줍니다.
for…of는 확연하게 조금 느린 속도를 보여주고 for…in은 이제 인사를 해야할 것 같습니다.
그럼 마지막으로 10000000(천만)으로 테스트를 해보겠습니다.
세 번 테스트한 결과 모두 for 문이 가장 빠른 속도를 보여주었으며, map, while도 의미있는 속도를 보여줍니다.
확실히 for…of는 위의 세 반복문보다 느린 속도를 보여주었으며 for…in은 10배가 넘는 느린 속도의 차이를 보여줍니다.
3. 결과 정리
배열 테이터의 크기가 작을 때는 의미있는 차이가 없지만 배열이 커질수록 map, for, while의 속도가 우수하고 for…in, for…of는 속도 저하를 보이는 결과를 나타냅니다.
어디까지나 단순한 작업인 배열 데이터 복사 기능만을 사용한 테스트이므로 작업 내용에 따라 다른 결과를 보일 가능성이 있어 단순 참고용으로 삼으면 좋을 것 같습니다.
다음은 테스트에 사용한 코드 전체입니다.
console.log('-------------start----------------')
const array = [];
for(let i=0;i<10000;i++){ //크기 변경
array.push(i);
}
console.log("arraysize:"+array.length);
console.log('--------------------------------');
let arraymap = [];
console.log('arraymap start:'+arraymap.length);
console.time('map');
arraymap = array.map(list=>list);
console.log('arraymap end:'+arraymap.length);
console.timeEnd('map');
console.log('--------------------------------');
let arrayfor = [];
console.log('arrayfor start:'+arrayfor.length);
console.time('for');
for(let i=0; i<array.length;i++){
arrayfor.push(array[i]);
};
console.log('arrayfor end:'+arrayfor.length);
console.timeEnd('for');
console.log('--------------------------------');
let arraywhile = [];
let whilenum = 0;
console.log('arraywhile start:'+arraywhile.length);
console.time('while');
while(whilenum<array.length){
arraywhile.push(array[whilenum]);
whilenum++;
};
console.log('arraywhile end:'+arraywhile.length);
console.timeEnd('while');
console.log('--------------------------------');
const arrayforof = [];
console.log('arrayforof start:'+arrayforof.length);
console.time('forof');
for(const num of array){
arrayforof.push(num)
};
console.log('arrayfor end:'+arrayforof.length);
console.timeEnd('forof');
console.log('--------------------------------');
let arrayforin = [];
console.log('arrayforin start:'+arrayforin.length);
console.time('forin');
for(const num in array){
arrayforin.push(array[num]);
};
console.log('arrayforin end:'+arrayforin.length);
console.timeEnd('forin');
console.log('---------------end-----------------');
text/plain으로 파싱하여 모든 요소를 반환합니다. <script>, <style> 요소를 포함해 CSS를 사용해 숨겨진 요소도 함께 반환하며 요소의 원시 텍스트를 사용하므로 성능이 좋습니다.
innerText
text/plain으로 파싱하여 렌더링 후의 요소를 반환합니다. <script>, <style> 요소는 반환하지 않으며 숨겨진 요소도 반환하지 않습니다. 자식 노드를 모두 제거하고 하나의 텍스트로 반환되며 성능은 보통입니다.
innerHTML
text/html로 파싱하여 요소의 html, xml 전체를 반환합니다. html을 다루므로 보안 이슈 중 하나인 XSS(Cross Site Scripting)에 취약합니다. HTML5에서는 innerHTML에 삽입된 <script> 태그는 실행되지 않도록 변경되었지만 <img>등 다른 태그를 통해 접근하면 여전히 취약점이 남습니다. 따라서 innerHTML은 별도로 문제 방지를 위한 설정이 없다면 사용을 권장하지 않습니다.
구현도 중요하지만 상황에 맞고 적절한 방식을 통해 구현한 시스템에 문제가 생기지 않도록 사전에 방지하는 것이 더 중요한 것 같습니다. 적절한 방식을 선택하는 것은 결국 각 기능의 이해를 통해서야 비로소 가능한 부분이므로 필요할 때 정리를 해두면 도움이 될 것 같습니다.
템플릿 리터럴은 시작과 끝에 반드시 `(backtick)을 붙여야 하며, ‘(홑따옴표), “(쌍따옴표)와 반드시 구분해야 합니다.
const name = 'clint Eastwood';
const age = '92';
const city = 'San Francisco';
const occupation = 'director';
// 표현식
console.log('His name is '+name+ '\n' + 'and '+age+'.');
// 템플릿 리터럴
console.log(`He was born in ${city}
and he is a ${occupation}`);
템플릿 리터럴에서 ${ }를 사용하면 블록 내 변수 또는 함수에 접근이 가능하며, \n 등 이스케이프를 사용하지 않고도 입력한대로 출력할 수 있습니다.