// 변수 x가 10보다 크고 20보다 작을 때 변수 x를 출력하는 조건식을 완성하라. if (10 < x < 20) { console.log(x); }
결과
1
15
2. for문을 사용하여 0부터 10미만의 정수 중에서 짝수만을 작은 수부터 출력하시오.
1 2 3
for (var i = 0; i < 10; i += 2) { console.log(i); }
결과
1 2 3 4 5
0 2 4 6 8
3. for문을 사용하여 0부터 10미만의 정수 중에서 짝수만을 작은 수부터 문자열로 출력하시오.
1 2 3 4 5
var result = ""; for (var i = 0; i < 10; i += 2) { result += i; } console.log(result);
결과
1
02468
4. for문을 사용하여 0부터 10미만의 정수 중에서 홀수만을 큰수부터 출력하시오.
1 2 3
for (var i = 9; i > 0; i -= 2) { console.log(i); }
결과
1 2 3 4 5
9 7 5 3 1
5. while문을 사용하여 0 부터 10 미만의 정수 중에서 짝수만을 작은 수부터 출력하시오.
1 2 3 4 5 6
var i = 0;
while (i < 10) { console.log(i); i += 2; }
결과
1 2 3 4 5
0 2 4 6 8
6. while문을 사용하여 0 부터 10 미만의 정수 중에서 홀수만을 큰수부터 출력하시오.
1 2 3 4 5 6
var i = 9;
while (i > 0) { console.log(i); i -= 2; }
결과
1 2 3 4 5
9 7 5 3 1
7. for 문을 사용하여 0부터 10미만의 정수의 합을 출력하시오.
1 2 3 4 5
var result = 0; for (var i = 0; i < 10; i++) { result += i; } console.log(result);
결과
1
45
8. 1부터 20 미만의 정수 중에서 2 또는 3의 배수가 아닌 수의 총합을 구하시오.
1 2 3 4 5 6 7
var result = 0; for (var i = 0; i < 20; i++) { if (i % 2 && i % 3) { result += i; } } console.log(result);
결과
1
73
9. 1부터 20 미만의 정수 중에서 2 또는 3의 배수인 수의 총합을 구하시오.
1 2 3 4 5 6 7
var result = 0; for (var i = 0; i < 20; i++) { if (i % 2 === 0 || i % 3 === 0) { result += i; } } console.log(result);
결과
1
117
10. 두 개의 주사위를 던졌을 때, 눈의 합이 6이 되는 모든 경우의 수를 출력하시오.
1 2 3 4 5 6 7 8
var dice1 = [1, 2, 3, 4, 5, 6]; var dice2 = [1, 2, 3, 4, 5, 6];
for (var i = 0; i < dice1.length; i++) { for (var j = 0; j < dice2.length; j++) { if (dice1[i] + dice2[j] === 6) console.log(`[${dice1[i]},${dice2[j]}]`); } }
결과
1 2 3 4 5
[1,5] [2,4] [3,3] [4,2] [5,1]
11. 삼각형 출력하기 - pattern 1
다음을 참고하여 *(별)로 높이가 5인(var line = 5) 삼각형을 문자열로 완성하라. 개행문자(‘\n’)를 사용하여 개행한다. 완성된 문자열의 마지막은 개행문자(‘\n’)로 끝나도 관계없다.
1 2 3 4 5 6 7 8 9 10 11 12 13
var result = ""; var line = 5; // line 변수 값으로 높이 조절 var i; var j;
for (i = 0; i < line; i++) { for (j = 0; j <= i; j++) { result = result.concat("*"); } result = result.concat("\n"); }
console.log(result);
결과
1 2 3 4 5
* ** *** **** *****
12. 삼각형 출력하기 - pattern 2
다음을 참고하여 *(별)로 트리를 문자열로 완성하라. 개행문자(‘\n’)를 사용하여 개행한다. 완성된 문자열의 마지막은 개행문자(‘\n’)로 끝나도 관계없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
var star = ""; var line = 5; var i = 0; var j = 0; var k;
for (i = 0; i < line; i++) { for (j = 0; j <= i; j++) { star = star.concat(" "); }
for (k = line - i; k > 0; k--) { star = star.concat("*"); }
star = star.concat("\n"); }
console.log(star);
결과
1 2 3 4 5
***** **** *** ** *
13. 삼각형 출력하기 - pattern 3
다음을 참고하여 *(별)로 트리를 문자열로 완성하라. 개행문자(‘\n’)를 사용하여 개행한다. 완성된 문자열의 마지막은 개행문자(‘\n’)로 끝나도 관계없다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
var star = ""; var line = 5; var i = 0; var j; var k = 0;
for (i; i < line; i++) { for (j = line - i; j > 0; j--) { star = star.concat("*"); } for (k; k <= i; k++) { star = star.concat(" "); } star = star.concat("\n"); }
console.log(star);
결과
1 2 3 4 5
***** **** *** ** *
14. 삼각형 출력하기 - pattern 4
다음을 참고하여 *(별)로 트리를 문자열로 완성하라. 개행문자(‘\n’)를 사용하여 개행한다. 완성된 문자열의 마지막은 개행문자(‘\n’)로 끝나도 관계없다.
// 문자열 타입 +"" + // -> 0 "0" + // -> 0 "1" + // -> 1 "string" + // -> NaN // 불리언 타입 true + // -> 1 false + // -> 0 // null 타입 null + // -> 0 // undefined 타입 undefined + // -> NaN // 심벌 타입 Symbol() + // -> ypeError: Cannot convert a Symbol value to a number // 객체 타입 // 빈 문자열(‘’), 빈 배열([]), null, false는 0으로, true는 1로 변환된다. // 객체와 빈 배열이 아닌 배열, undefined는 변환되지 않아 NaN이 된다는 것에 주의하자. {} + // -> NaN [] + // -> 0 [10, 20] + // -> NaN function () {}; // -> NaN
불리언 타입 변환
1 2 3 4 5 6 7 8 9
//if문의 조건식일 경우 true, false 값으로 암묵적 타입 변환이 이뤄짐.
if ("") console.log("1"); if (true) console.log("2"); if (0) console.log("3"); if ("str") console.log("4"); if (null) console.log("5");
// 2 4
위의 결과에서 boolean 타입 값으로 타입 변환돼서 그 중 true 값으로 평가되는 값인 2번 4번만 출력된다.
아래 값들은 false 값으로 평가된다.
false
undefined
null
0, -0
NaN
’’ (빈 문자열)
1 2 3 4 5 6 7 8
// 아래의 조건문은 모두 코드 블록을 실행한다. // ! 부정 논리 연산자로 인해 원래 false인 것이 true로 바뀌어 조건문이 실행된다. if (!false) console.log(false + " is falsy value"); if (!undefined) console.log(undefined + " is falsy value"); if (!null) console.log(null + " is falsy value"); if (!0) console.log(0 + " is falsy value"); if (!NaN) console.log(NaN + " is falsy value"); if (!"") console.log("" + " is falsy value");
명시적 타입 변환
명시적 타입 변환에는 여러가지 방법이 있다.
표준 빌트인 생성자 함수(String, Number, Boolean)를 new 연산자 없이 호출하는 방법
// 1. Boolean 생성자 함수를 new 연산자 없이 호출하는 방법 // 문자열 타입 => 불리언 타입 Boolean("x"); // -> true Boolean(""); // -> false Boolean("false"); // -> true // 숫자 타입 => 불리언 타입 // 참고로 0이 아닌 모든 숫자 타입은 `true`다. Boolean(0); // -> false Boolean(1); // -> true Boolean(NaN); // -> false Boolean(Infinity); // -> true // null 타입 => 불리언 타입 Boolean(null); // -> false // undefined 타입 => 불리언 타입 Boolean(undefined); // -> false // 객체 타입 => 불리언 타입 Boolean({}); // -> true Boolean([]); // -> true
// 2. ! 부정 논리 연산자를 두번 사용하는 방법 // 문자열 타입 => 불리언 타입 !!"x"; // -> true !!""; // -> false !!"false"; // -> true // 숫자 타입 => 불리언 타입 !!0; // -> false !!1; // -> true !!NaN; // -> false !!Infinity; // -> true // null 타입 => 불리언 타입 !!null; // -> false // undefined 타입 => 불리언 타입 !!undefined; // -> false // 객체 타입 => 불리언 타입 !!{}; // -> true !![]; // -> true
단축 평가
논리연산자를 이용한 단축평가
논리합||, 논리곱&&연산자의 계산 방향은 좌에서 우로 진행된다.
1
"Cat" || "Dog"; // -> "Cat"
|| 연산자는 좌항 우항에 존재한 피연산자 중 하나만 true라면 반환값이 true이다. 좌측에서 계산하다 좌항이 true니 뒤는 확인하지 않고 좌항의 값을 반환한다.
1
'Cat' && 'Dog' // -> "Dog"
&& 연산자는 좌항 우항에 존재한 피연산자 모두 true면 반환값이 true이다. 좌측부터 계산해서 우항도 true라면 우항의 값을 반환한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 정리하면 다음과 같은 규칙을 따른다. true || "anything"; // -> true false || "anything"; // -> anything true && "anything"; // -> anything false && "anything"; // -> false
객체를 가리키기를 기대하는 변수의 값이 객체가 아니라 null 또는 undefined인 경우 객체의 프로퍼티를 참조하면 타입 에러TypeError가 발생한다. 이때 단축 평가를 사용하면 에러를 발생시키지 않는다.
1 2 3 4 5 6 7 8 9
//객체 프로퍼티 참조 var elem = null; var value = elem.value; // TypeError: Cannot read property 'value' of null
//단축평가 사용 var elem = null; // elem이 null이나 undefined와 같은 Falsy 값이면 elem으로 평가되고 // elem이 Truthy 값이면 elem.value로 평가된다. var value = elem && elem.value; // -> null
함수를 호출할 때 인수를 전달하지 않으면 매개변수는 undefined를 갖는다. 이때 단축 평가를 사용하여 매개변수의 기본값을 설정하면 undefined로 인해 발생할 수 있는 에러를 방지할 수 있다.
제어문(control flow statement)은 주어진 조건에 따라 코드 블록을 실행(조건문)하거나 반복 실행(반복문)할 때 사용한다.
조건문
조건문은 조건식(Boolean)을 판단하여 참 거짓에 따라 실행할 코드 블록을 정한다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
// 대표적인 if else 문이다. if (조건식) { // 조건식이 참이면 이 코드 블록이 실행된다. } else { // 조건식이 거짓이면 이 코드 블록이 실행된다. }
// else if 문이 새로 등장한다. '아님 말고' 느낌으로 써준다. if (조건식1) { // 조건식1이 참이면 이 코드 블록이 실행된다. } elseif (조건식2) { // 조건식2가 참이면 이 코드 블록이 실행된다. } else { // 조건식1과 조건식2가 모두 거짓이면 이 코드 블록이 실행된다. }
if… else… else if…를 배웠다면 아래의 switch 문도 알아보자.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
switch (표현식) { case 표현식1: switch 문의 표현식과 표현식1이 일치하면 실행될 문; // break를 사용하지 않으면 표현식이 참이더라도 맨밑으로 내려간다. 의도한게 아니라면 까먹지 말자. break;
case 표현식2: switch 문의 표현식과 표현식2가 일치하면 실행될 문; break;
//default는 필수가 아닌 선택, 어차피 마지막이라 break가 필요 없다. default: switch 문의 표현식과 일치하는 표현식을 갖는 case 문이 없을 때 실행될 문; }
반복문
반복문(loop statement)은 조건식의 평가 결과가 참인 동안 코드 블록을 계속 반복 실행한다. 반복 과정에서 매번 조건식을 다시 평가히여 참인 경우 코드 블록을 반복, 거짓일 경우 끝이 난다.
for
아래 예시는 i가 0 부터 시작하여 2 보다 작은 동안 i를 매번 1씩 증가시키면서 코드블록을 반복하는 반복문이다.
1 2 3
for (var i = 0; i < 2; i++) { console.log(i); }
결과는 아래와 같다. i가 0일 때, 1일 때 두번 실행됐다.
1 2
0 1
for 문을 무한루프로 활용하는 법이다.
1 2
// 무한루프 for (;;) { ... }
while
1 2 3 4 5 6 7
var count = 0;
// count가 3보다 작을 때까지 코드 블록을 계속 반복 실행한다. while (count < 3) { console.log(count); // 0 1 2 count++; }
탈출하는 경우 break를 사용한다!
1 2 3 4 5 6 7 8 9
var count = 0;
// while의 무한루프 while (true) { console.log(count); count++; // count가 3이면 코드 블록을 탈출한다. if (count === 3) break; } // 0 1 2
do…while
do를 먼저 실행한 후 반복문으로 들어간다. 그냥 while문과 실행 순서가 다른 것을 이용할 수 있다.
1 2 3 4 5 6 7
var count = 0;
// while과 다른 점은 조건식 비교 이전에 do를 실행한 후 조건식과 비교한다. do { console.log(count); count++; } while (count < 3); // 0 1 2
break와 continue
break
break문은 엄밀하게 말하면 코드 블록 탈출이 아닌, 레이블 문, 반복문(for, for…in, for…of, while, do…while) 또는 switch 문의 코드 블록을 탈출하는 것이다.
레이블 문, 반복문, switch 문의 코드 블록 외에 break 문을 사용하면 SyntaxError(문법 에러)가 발생한다.
레이블 문은 프로그램의 실행 순서를 제어하는 데 사용한다. 사실 switch 문의 case 문과 default 문도 레이블 문이다. 레이블 문을 탈출하려면 break 문에 레이블 식별자를 지정한다.
1 2
// foo라는 레이블 식별자가 붙은 레이블 문 foo: console.log("foo");
1 2 3 4 5 6 7 8 9 10
// outer라는 식별자가 붙은 레이블 for 문 outer: for (var i = 0; i < 3; i++) { for (var j = 0; j < 3; j++) { // i + j === 3이면 outer라는 식별자가 붙은 레이블 for 문을 탈출한다. if (i + j === 3) break outer; console.log(`inner [${i}, ${j}]`); } }
console.log("Done!");
break outer를 만나면 outer 레이블이 달린 for 문을 탈출한다.
레이블 문은 중첩된 for 문 외부로 탈출할 때 유용하지만 그 밖의 경우에는권장하지 않는다.
레이블 문을 사용하면 프로그램의 흐름이 복잡해져서 가독성이 나빠지고 오류를 발생시킬 가능성이 높아지기 때문이다.
continue
continue 문은 반복문의 코드 블록 실행을 현 지점에서 중단하고 반복문의 증감식으로 실행 흐름을 이동시킨다.
반복문을 아예 탈출하는 break문과는 다르다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
// 문자열에서 특정 문자의 개수를 세는 예
var string = "Hello World."; var search = "l"; var count = 0;
// 문자열은 유사배열이므로 for 문으로 순회할 수 있다. for (var i = 0; i < string.length; i++) { // 'l'이 아니면 현 지점에서 실행을 중단하고 반복문의 증감식으로 이동한다. if (string[i] !== search) continue; count++; // continue 문이 실행되면 이 문은 실행되지 않는다. }
console.log(count); // 3
// 참고로 String.prototype.match 메서드를 사용해도 같은 동작을 한다. const regexp = newRegExp(search, "g"); console.log(string.match(regexp).length); // 3
만약 숫자 ‘10’을 메모리에 저장한다면 숫자 ‘10’에 접근할 때마다 복잡한 메모리 주소를 찾아 직접 접근해야한다. 하지만 메모리 주소에 직접 접근하는 것은 매우 위험하다. 잘 못 접근하게 되면 미지의 메모리를 변경할 수도 있기 때문이다.
위와 같은 이유로 프로그래밍 언어는 값을 메모리에 저장하고, 저장된 값을 읽어 들여 재사용하기 위해 변수라는 메커니즘을 제공한다.
변수는 값의 위치를 나타내는 상징적인 이름이며 식별자라고도 부른다.
1 2 3 4 5
// 변수는 하나의 값을 저장하기 위한 수단이다. var nyong = 10;
// 연산을 통해 생성된 값을 변수를 통해 메모리 공간에 저장할 수도 있다. var result = 10 + 20;
변수에 값을 저장하는 것을 할당(assignment), 변수에 저장된 값을 읽어 들이는 것을 참조(reference)라 한다.
안에 담긴 값의 의미를 반영하여 지은 변수 이름은 저장된 값의 의미를 명확히 할 수 있어 가독성을 높여준다.
코드는 컴퓨터에게 내리는 명령이면서 동시에 개발자를 위한 문서이기도 하다. 명확한 네이밍은 코드를 이해하기 쉽게 만들며 타인이 내 코드를 쉽게 해석할 수 있게 돕는다.
변수 선언
변수를 사용하려면 반드시 선언이 필요하다. 변수를 선언할 때는 var, let, const 키워드를 사용한다.
1 2
var score; // 변수 선언 console.log(score); //undefined
위와 같이 변수를 선언한 후 출력하면 undefined 값이 출력된다. 이는 현재 변수 안에 메모리 공간은 확보됐지만 어떤 값도 할당하지 않은 것이다.
자바스크립트에서 변수를 선언하면 다음의 절차를 거친다
선언 단계 : 변수 이름을 등록해서 자바스크립트 엔진에 변수의 존재를 알린다.
초기화 단계 : 값을 저장하기 위한 메모리 공간을 확보하고 암묵적으로 undefined를 할당해 초기화한다.
자바스크립트에서는 초기화 값으로 정의되지 않았다는 뜻인 undefined를 할당한다. 이것도 할당이라면 할당이지만 의도하지 않았다면 제대로된 값을 할당한 행위는 아니다.
호이스팅
1 2 3
console.log(score); // undefined
var score; // 변수 선언문
자바스크립트는 인터프리터 언어인 것을 저번에 설명하였다. 그렇다면 console.log(score)구문을 실행하면 var score가 실행되기 전이기 때문에 변수 참조 에러(ReferenceError)가 발생해야하지만 undefined값이 출력됐다.
그 이유는 변수 선언이 소스코드가 한 줄씩 순차적으로 실행되는 런타임(runtime)이 아니라 이전 단계에서 먼저 실행되기 때문이다.
자바스크립트 엔진은 런 타임에 진입하기 전 준비과정으로 모든 선언문(변수,함수 선언문 등)을 찾아 먼저 실행한다. 그렇기 때문에 var로 선언된 변수인 score가 먼저 실행되어 위의 현상이 나타나는 것이다.
이처럼 변수 선언문이 코드의 선두로 끌어 올려진 것처럼 동작하는 자바스크립트 고유의 특징을 변수 호이스팅(variable hoisting)이라 한다.
var, let, const, function, function*, class 키워드를 사용해서 선언하는 모든 식별자(변수, 함수, 클래스 등)는 호이스팅된다.
값 할당
1
var score = 80; // 변수 선언과 값의 할당
변수 선언은 소스코드가 순차적으로 실행되는 시점인 런타임 이전에 먼저 실행되지만 값의 할당은 소스코드가 순차적으로 실행되는 시점인 런타임에 실행된다. 아래 코드를 보자.
1 2 3 4 5 6
console.log(score); // undefined
var score; // ① 변수 선언 score = 80; // ② 값의 할당
console.log(score); // 80
참고로 변수에 값을 할당할 때는 이전 값 undefined가 저장되어 있던 메모리 공간을 지우고 그 메모리 공간에 할당 값 80을 새롭게 저장하는 것이 아니라 새로운 메모리 공간을 확보하고 그 곳에 할당 값을 저장한다.(즉, 메모리 주소가 동일하지 않다.)
그 이유는 undefined값도 할당이라면 할당이라고 위에서 말했는데 변수에 값을 제대로 할당할 경우(사실은 처음이 아닌 ‘재할당’이다.) 새로운 메모리 공간을 확보하고 그 메모리 공간에 새로운 값을 저장하기 때문이다.
그렇다면 전에 값이 저장된 메모리 공간이 불필요하게 존재한다고 걱정할 수 있는데 이는 가비지 콜렉터라는 기능에 의해 자동 삭제된다. 단, 언제 삭제될지는 모른다.
변수 네이밍 규칙
식별자는 특수문자를 제외한 문자, 숫자, 언더스코어(_), 달러 기호($)를 포함할 수 있다.
단, 식별자는 특수문자를 제외한 문자, 언더스코어(_), 달러 기호($)로 시작해야 한다. 숫자로 시작하는 것은 허용하지 않는다.
예약어는 식별자로 사용할 수 없다.(예약어는 프로그래밍 언어에서 사용되고 있거나 사용될 예정인 단어를 말한다.)
영어 이외의 문자로도 명명할 수 있지만 권장하지 않는다.
자바스크립트는 대소문자를 구별한다.
주석이 필요없어도 의미를 알 수 있는 이름으로 짓자.
네이밍 컨벤션을 활용하자.
1 2 3 4 5 6 7 8 9 10 11 12 13
// 카멜 케이스 (camelCase) var firstName;
// 스네이크 케이스 (snake_case) var first_name;
// 파스칼 케이스 (PascalCase) var FirstName;
// 헝가리언 케이스 (typeHungarianCase) var strFirstName; // type + identifier var $elem = document.getElementById("myId"); // DOM 노드 var observable$ = fromEvent(document, "click"); // RxJS 옵저버블
리터럴
리터럴(literal)은 약속된 ‘기호를 사용해 값을 생성’하는 표기 방식(notaion)을 말한다.
이해할 수 있는 문자(아라비아 숫자, 알파벳, 한글 등) 또는 미리 약속된 기호(‘’, “”, ., [], {}, // 등)로 표기한 코드다.
// 50 + 50은 리터럴과 연산자로 이뤄져 있다. 하지만 50 + 50도 평가되어 숫자 값 100을 생성하므로 표현식이다. var score = 50 + 50;
// 변수 식별자를 참조하면 변수 값으로 평가된다. score; // -> 100
// 다음과 같이 다양한 표현식이 있지만 값으로 평가된다는 점에서 모두 동일하다. 즉, 값으로 평가되는 문은 모두 표현식이다. // 문법적으로 값이 위치할 수 있는 자리에는 표현식도 위치할 수 있다는 것을 의미한다. 표현식은 다른 표현식의 일부가 되어 새로운 값을 만들어낼 수 있다. // 리터럴 표현식 10; ("Hello");
// 식별자 표현식(선언이 이미 존재한다고 가정) sum; person.name; arr[1];
// 연산자 표현식 10 + 20; sum = 10; sum !== 10;
// 함수/메서드 호출 표현식(선언이 이미 존재한다고 가정) square(); person.getName();
문
문(statement)은 프로그램을 구성하는 기본 단위이자 최소 실행 단위이다. 문의 집합으로 이뤄진 것이 프로그램이며, 문을 작성하고 순서에 맞게 나열하는 것이 프로그래밍이다.
문은 여러 토큰으로 구성된다. 토큰(token)이란 문법적인 의미를 가지며, 더 이상 나눌 수 없는 코드의 기본 요소다. 예를 들어, 키워드, 식별자, 연산자, 리터럴, 세미콜론(;)이나 마침표(.) 등의 특수 기호는 문법적인 의미를 가지며, 문법적으로 더 이상 나눌 수 없는 코드의 기본 요소이므로 모두 토큰이다.
표현식은 문의 일부일 수도 있고 그 자체로 문이 될 수도 있다.
1 2 3 4 5 6 7 8 9 10 11 12
// 변수 선언문은 값으로 평가될 수 없으므로 표현식이 아니다. var x;
// 1, 2, 1 + 2, x = 1 + 2는 모두 표현식이다. // x = 1 + 2는 표현식이면서 완전한 문이기도 하다. x = 1 + 2;
// 표현식이 아닌 문은 값처럼 사용할 수 없다. var foo = var x; // SyntaxError: Unexpected token var
// 표현식인 문은 값처럼 사용할 수 있다 var foo = x = 100;
표현식인 문과 표현식이 아닌 문을 구별하는 가장 간단하고 명료한 방법은 변수에 할당해 보는 것이다. 표현식인 문은 값으로 평가되므로 변수에 할당할 수 있다.
데이터 타입
자바스크립트(ES6)는 7개의 데이터 타입을 제공한다.
원시 타입(primitive type)
숫자(number) 타입: 숫자. 정수와 실수 구분 없이 하나의 숫자 타입만 존재
문자열(string) 타입: 문자열
불리언(boolean) 타입: 논리적 참(true)과 거짓(false)
undefined 타입: var 키워드로 선언된 변수에 암묵적으로 할당되는 값
null 타입: 값이 없다는 것을 의도적으로 명시할 때 사용하는 값
심벌(symbol) 타입: ES6에서 추가된 7번째 타입
객체 타입 (object/reference type): 객체, 함수, 배열 등
숫자 타입
자바스크립트는 하나의 숫자 타입만 존재한다.
ECMAScript 사양에 따르면 숫자 타입의 값은 모든 수를 실수로 처리하며, 정수만 표현하기 위한 데이터 타입(integer type)이 별도로 존재하지 않는다.
1 2 3 4
// 숫자 타입은 모두 실수로 처리된다. console.log(1 === 1.0); // true console.log(4 / 2); // 2 console.log(3 / 2); // 1.5
2진수, 8진수, 16진수는 아래와 같이 표기한다.
1 2 3 4 5 6 7
var binary = 0b01000001; // 2진수 var octal = 0o101; // 8진수 var hex = 0x41; // 16진수
1995년 웹페이지의 보조적인 기능을 수행(웹서버 실행, HTML/CSS 랜더링 등)하기 위한 브라우저에서 동작하는 경량 프로그래밍 언어로 탄생하였다.
처음 이름은 ‘모카’에서 ‘라이브스크립트’로 변경했다가 1996년 12월 최종적으로 ‘JavaScript’로 명명되었다.
1996년 8월 마이크로소프트의 JScript가 IE 3.0에 탑재되면서 JavaScript와의 표준화에 실패하고 자사 브라우저 사장 점유율 높이려고 치킨게임을 시작했고 이로 인해 크로스 브라우징 이슈가 끝없이 발생했다.
1996년 11월 모든 브라우저 정상 작동을 위한 ECMA 인터내셔널에 JavaScript의 표준화를 요청하며 1997년 7월 ECMA-262라는 JavaScript 초판(ECMAScript 1)사양이 완성되었고, 1999년 ECMAScript3, 2009년 ECMAScript5가 HTML5와 함께 출현하며 표준 사양이 되었다.
2015년 출시한 ECMAScript 6에는 화살표 함수, 클래스, 모듈 같은 범용 프로그래밍 언어에 적합한 기능들이 추가되며 큰 변화가 생겼다.
현재 JavaScript는 모든 브라우저의 표준 프로그래밍 언어가 되었다.
ECMAScript 2020가 현재 표준 사양이다. javaScript에 대한 표준이다. 브라우저에서 지원하는 alert() 같은 함수는 포함되지 않는 브라우저 node.js에서 모두 동작하는 순수한 엔진에 대한 표준이다.
1999년, 자바스크립트를 이용해 서버와 브라우저가 비동기(asynchronous) 방식으로 데이터를 교환할 수 있는 통신 기능인 Ajax(Asynchronous Javascript And XML)가 등장했다.
비동기통신 발명 이전에는 완전한 HTML 코드 자체를 서버로부터 받아 웹페이지 전체를 랜더링하고 이후 화면 전환이 필요하면 다시 완전한 HTML 코드 자체를 받아 웹페이지 전체를 새로 랜더링했다.
위와 같은 방식으로 랜더링을 하게 되면 변경할 필요가 없는 부분까지 전송 받아 다시 랜더링했기 때문에 불필요한 데이터 통신이 발생하였고 이로 인해 화면 전환 시 화면이 깜빡거리는 현상이 발생한다. 하지만 이는 어쩔 수 없는 웹페이지의 한계로 받아들여졌었다.
Ajax는 웹페이지에서 화면전환이 필요한 부분만 서버로부터 받아 부분만 랜더링하는 방식이다. 이로서 빠른 성능과 부드러운 화면 전환이 가능해졌다.
V8 JavaScript 엔진
2008년 웹 애플리케이션을 구축하려는 요구에 부합하는 빠른 성능을 가진 구글의 V8 JavaScript 엔진이 등장했다.
V8 엔진은 JavaScript로 데스크톱 애플리케이션과 유사한 UX를 제공할 수 있는 가능성을 보여주며 웹 애플리케이션 프로그래밍 언어로 정착하였다.
Node.js
node.js는 2009년 브라우저의 JavaScript 엔진에서만 동작하던 JavaScript 이외의 환경에서도 동작할 수 있도록 독립시킨 JavaScript 실행 환경이다.
JavaScript는 Node.js를 통해 서버 사이드 애플리케이션 개발에서도 사용할 수 있는 범용 프로그래밍 언어가 되었다. JavaScript는 프런트엔드 영역은 물론 백엔드 영역까지 아우르는 웹 프로그래밍 언어의 표준으로 자리 잡고 있다.
SPA (Single Page Application)
SPA는 한번의 전체 페이지 로드 이후에는 데이터 요청만으로 부분을 변경하여 사용하는 Application을 뜻한다.
언뜻보면 Ajax 같은 비동기 방식과의 다른점을 찾아 볼 수 없지만 ‘라우팅’이란 개념으로 다르게 된다. 기존 Ajax의 경우 화면을 구성해도 동일한 페이지에서 구성했기 때문에 히스토리가 남지 않고 뒤로가기나 해당 페이지 즐겨찾기가 불가능하다. 하지만 ‘라우팅’을 이용하는 SPA는 index#menu1#submenu1 같이 해쉬태그와 해쉬값에 맞는 페이지를 실행하기 때문에 한페이지 내에서 여러 페이지 구성이 가능하다.
SPA가 대중화되면서 Angular, React, Vue.js, Svelte 등 다양한 SPA 프레임워크/라이브러리가 많이 사용되고 있다.
하지만 초기 구동 속도가 상대적으로 느리며 SEO(검색최적화)에 취약한 것이 단점이다.
기타
interpreter vs compile
프로그래밍 언어에는 interpreter 언어와 compile 언어가 있다.
참고로 자바스크립트 엔진은 원래 interpreter 언어지만 일부 소스 코드는 컴파일하고 실행한다. 두 언어의 장점을 결합해 비교적 처리 속도가 느린 인터프리터의 단점을 해결했다.
현재는 컴파일러와 인터프리터의 기술적 구분이 점차 모호해져 가는 추세다.
interpreter
interpreter 언어는 코드가 실행되는 단계인 런타임에 문 단위로 바이트코드(가상 머신에서 실행하도록 만드는 바이너리 코드)로 변환 후 실행한다.
위와 같은 이유로 실행 파일이 생성되지 않는다. 때문에 코드가 실행될 때마다 인터프리트 과정이 반복 수행된다.
언어 특징 때문에 실행 중 에러 발생 시 더 이상 실행이 이뤄지지 않는다.
구문에 대한 해석과 실행이 동시에 이뤄지기 때문에 별도의 실행파일이 존재하지 않는다.
컴파일이 없기 때문에 신속하게 동작한다.
대표적으로 HTML, CSS, JavaScript, Python 등이 있다.
compile
compile 언어는 interpreter 언어와 다르게 소스코드를 전부 해석하고 수집한 후 머신 코드(CPU가 바로 실행할 수 있는 기계어)로 재구성하여 실행한다.
실행 파일이 생성된다. 때문에 컴파일은 실행에 앞서 단 한번만 수행된다.
전체 코드를 변환 후 에러를 보고한다. 이렇기 때문에 보안측에서는 interpreter 언어보다 취약하다.
컴파일 언어는 한번 컴파일하게 되면 실행 파일이 생성되며 실행파일은 interpreter 언어보다 빠르다.
대표적으로 C, C++, JAVA 등이 있다.
픽셀 절대 단위일까, 상대 단위일까?
픽셀은 viewport에서 표현 가능한 최소 단위이다. 픽셀은 그렇다면 절대 단위인가?
하지만 같은 최대 해상도(픽셀 수가 척도인 출력 정도)를 가진 다른 크기의 디바이스 1px의 값의 절대적인 수치는 다르다. 다르게 말하면 픽셀은 디바이스 해상도에 따라 상대적인 크기를 갖는다.
1픽셀은 모든 디바이스에서 1픽셀이지만 디바이스마다 갖는 1픽셀의 크기는 다르다.
모니터의 1px과 빔프로젝트로 보는 1px을 생각하면 감이 잡힐지 모른다. 모니터에서 10px 크기의 상자와 모니터와 연결된 빔프로젝트로 보는 10px 크기의 상자는 분명 다를 것이다.
위처럼 디바이스 별로 픽셀의 크기는 제각각이기 때문에 픽셀을 기준으로 하는 단위는 명확하지 않다. 따라서 대부분의 브라우저는 1px을 1/96 인치의 절대단위로 인식한다.
오늘 느낀 것
사상누각 되지 말자. 모든 것은 기본기가 탄탄해야한다. 결과만 보고 달리다가 기본기를 잃으면 무너지는 것은 시간 문제다.
팀장으로 참여하여 참 많은 우여곡절을 겪었다. 그래도 팀장이어서 더 책임감을 느끼고 보람찼다. 결과적으로 시간분배부터 팀장으로서의 git 사용, 더 많은 분량 등 최대의 노력을 쏟아낼 수 있었던 좋은 기회였다.
merge하다가 꼬여서 고생했다. 앞으로 진짜 신중하게 검토해야하는 습관을 들여야한다.
git bash에서 명령어 입력할 때 생각을 하고 하자. 잘 못 입력해서 이미지 파일을 다 날렸다.
방금 말한 것과 같이 git 과 git hub를 처음 사용해보면서 위와 같은 시행착오를 겪으며 어렵고 불편했지만 갈 수록 널리 쓰이는 이유를 알게됐다.
시멘틱 마크업을 알게되니 div와 span을 쓰면 불안해진다. 하지만 시멘틱 마크업도 중요하지만 쓸 때는 쓰는 결단력이 필요하다.
절대값으로 레이아웃을 구성하면 너무 찝찝해서 최대한 안 쓰려고 했는데 능력의 한계로 쓸 수 밖에 없을 때 좀 더 깊은 레이아웃 구성 방법에 대해 간절함을 느꼈다.
이번 프로젝트에서 css를 적용할 때 스타일 적용하면서도 더 효율적인 방법이 있을 텐데를 고민할때가 괴롭지만 참 재밌었다.
시간이 더 있었다면 퀄리티가 더 높았겠지만 그건 변명이다. 결국 정해진 기한 내에 하는 것도 실력이다.
크로스 브라우징은 너무 어려워서 거의 진행하지 못하였다. 좀 더 섬세한 부분도 완성하고 싶었지만 시간관계상 못 하지 못해 많이 아쉬웠다. 별개로 앞으로 IE를 사용하는 사람이 있으면 도시락 싸들고 말려야겠다는 결심을 했다.
결과는 과정의 노력을 확인하는 수단일 뿐, 집착하고 얽매일 필요가 없다. 때때로 힘들었지만 점점 결과를 보여갈 때 느꼈던 기분과, 과정을 통해 얻은 새로운 지식과 경험이 중요하다고 생각한다. 잘하는 것도 중요하지만 과정을 통해 전보다 나아졌다는 것이 중점이라고 생각하며 프로젝트를 마친다.