JavaScript 의 기본에 대해 알아봅시다.
개념, 입출력, 코드 구성, 변수와 상수, 자료형, 객체 복사 에 대해 정리되어있습니다.
객체(Object) 기반의 스크립트 프로그래밍 언어입니다.
ECMAScript 사양을 준수하는 범용 스크립팅 언어입니다.
자바와 직접적인 연관은 없으며, 웹의 동적 동작을 구현하기 위해 제작되었습니다.
Mocha --> LiveScript --> JavaScript 로 명칭이 변경되었습니다.
JavaScript는 JS 엔진 위에서 수행되며,
Google V8, Firefox SpiderMonkey, EdgeChakra 가 존재합니다.
아래 문서에서 JavaScript 의 명확한 정의를 더 볼 수 있습니다.
🦊 JavaScript | MDN
Ecma International 이 ECMA-262 기술 규격에 따라 정의하고 있는 표준화된 스크립트 프로그래밍 언어입니다.
JavaScript 를 표준화하기 위해 만들어졌으며, 액션스크립트와 J스크립트 등 다른 구현체도 포함합니다.
Ecma International : 정보 통신에 대한 표준을 제정하는 비영리 표준화 기구입니다.
ECMA-262 : Ecma International 에서 제정한 기술 규격의 이름으로, 범용 스크립트 언어 명세를 기술합니다.
97년 ES1 초판, 09년 ES5, 15년 ES2015(ES6) 로 매년 6월에 버전 갱신 중입니다.
사용자가 프로그램과 상호작용하기 위한 방법 = 입력/출력 의 개념
Input/Output 의 머리글자를 따서 I/O 로 줄여서도 표기합니다.
운영 체제에서의 대표적인 입출력은 "표준 입력/표준 출력/표준 오류 출력" 입니다.
✅ 일상생활에서 사용자는 PC 에 입력하고, PC는 모니터에 결과를 출력합니다.
일반적으로 키보드의 응답을 받아 입력합니다.
프로그램의 데이터를 추가하기 위한 입력 장치입니다.
알고리즘에서는 문제의 Testcase 입력을 위해 사용합니다.
✅ 꼭 키보드 뿐만 아니라, 마우스나 기타 여러 디바이스 등에 의해 입력을 받을수도 있습니다.
일반적으로 모니터에 문자열로 출력됩니다.
프로그램의 실행 상태 혹은 실행 결과를 보고 판단합니다.
알고리즘에서는 문제의 정답 확인, 디버깅 용으로 사용됩니다.
const fs = require("fs");
const input = fs.readFileSync(
".txt 파일의 절대경로",
"utf8"
);
console.log(input);
Error: ENOENT: no such file or directory, open './input.txt'
at Object.openSync (node:fs:585:3)
at Object.readFileSync (node:fs:453:35)
at Object.<anonymous> (/Users/flex/Desktop/zero-base/workspace/js_practice/js_basic/main.js:2:18)
at Module._compile (node:internal/modules/cjs/loader:1097:14)
at Object.Module._extensions..js (node:internal/modules/cjs/loader:1151:10)
at Module.load (node:internal/modules/cjs/loader:975:32)
at Function.Module._load (node:internal/modules/cjs/loader:822:12)
at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:77:12)
at node:internal/main/run_main_module:17:47 {
errno: -2,
syscall: 'open',
code: 'ENOENT',
path: './input.txt'
}
만약 위와 비슷한 에러가 발생한다면 파일 경로를 다시 한 번 확인하세요!
readFileSync 의 파일 경로는 절대경로여야 합니다. (Mac OS, nodejs 기준)
참조 : nodejs에서 fs.readFileSync 사용시 발생하는 에러 확인
JavaScript 는 문법의 대부분을 C, C++, Java 로부터 차용하여 제작된 스크립트 기반의 언어입니다.
다수의 표현식(expression)으로 하나의 명령문(statement)이 만들어지며, 명령문으로 프로그램이 수행됩니다.
하나의 명령문 끝은 개행 문자(Enter
) 혹은 세미콜론(;
) 으로 표시해줍니다.
⭐️ 개발을 처음 접하시는 분들이 가장 많이 간과하는것이 세미콜론을 빼먹어서 나는 에러들입니다. 꼭 습관을 들이도록 합시다!
name = value
의 형태로써 왼쪽의 이름에 오른쪽의 값을 집어넣습니다.
JavaScript에서 문법을 만들 때 미리 정해진 용도로 동작하기 위해 정의해 놓은 단어입니다.
ex) let, class, extends, await, import, if, else, ...
일일이 외우지 않아도 실제 프로그래밍에는 아무런 지장이 없습니다.
우리에겐 Google신이 있으니까요! 그리고 VSCode의 자동추천 기능도 사용합시다.
스크립트에서 변수나 함수에 이름을 붙일 때 사용하는 단어입니다.
대소문자를 구별하며 유니코드 문자셋을 이용합니다.
자바스크립트 내 식별자 규칙
1) 키워드 사용이 불가능합니다.
2) 숫자로 시작할 수 없습니다.
3) 특수문자는 _
와 $
만 허용합니다.
4) 공백 문자를 포함할 수 없습니다.
프로그램 구현 시 개발자의 설명 및 이해를 쉽게 도와주는 문장으로, 실제 실행 코드에는 포함되지 않습니다.
주석의 종류는 단일 행 주석 //
과 다중 행 주석 /**/
이 존재합니다.
꼭! 단일 행 주석은 실행되어야 하는 코드의 뒤쪽에 작성합시다.
안녕, hi, HI 의 변수에는 각각 "하세요", "hello", "HELLO" 의 값이 배정됩니다.
다중 행 주석 내부에 있는 출력문은 실행되지 않는것을 확인할 수 있습니다.
let 안녕 = "하세요";
let hi = "hello";
let HI = "HELLO";
console.log(안녕);
console.log(hi);
console.log(HI);
// single-line comments
/*
multi-line comments
여러 문장들이
개행으로 이어져도
주석처리 된다.
console.log("hello, world!");
*/
console.log("hello, world!");
변경 가능한 값을 저장하기 위한 기억 공간(memory) 입니다.
사용하기 전 반드시 선언이 필요합니다.
중복 선언이 불가능합니다.
키워드는 let
을 사용합니다.
변수에 대한 접근으로 변수의 값을 수정할 수 있습니다.
1) 선언 : let A = 123;
--> 변수 A 의 값을 123 으로 초기화(선언)
2) 수정 : A = 456
--> 변수 A 의 값이 456 으로 변경
변수를 중복 선언하게 되면 아래와 같은 SyntaxError 오류를 뿜어냅니다.
SyntaxError: Identifier 'A' has already been declared
at Object.compileFunction (node:vm:352:18)
at wrapSafe (node:internal/modules/cjs/loader:1026:15)
at Module._compile (node:internal/modules/cjs/loader:1061:27)
...
변경 불가능한 값을 저장하기 위한 기억 공간입니다.
사용하기 전 반드시 선언이 필요합니다.
선언과 동시에 초기화가 필요합니다.
중복 선언이 불가능합니다.
키워드는 const
를 사용합니다.
❗️ 변수와는 달리 한번 선언되면 값을 변경할 수 없습니다. 잘 짚고 넘어갑시다!
// 선언 후 할당
let hi;
hi = "hello";
// 선언과 동시에 초기화
let halo = "hello!";
// 한 줄에 여러 변수 선언하고 초기화
let name = "john",
age = 13,
msg = "hello";
// 상수는 보통 대문자로 표기
const TESTCASE = 5;
const BIRTHDAY = "2020. 1. 1";
코드에 선언된 변수 및 함수를 유효한 범위의 코드 상단으로 끌어 올리는 작업입니다.
var의 변수/함수의 선언만 위로 올려지고, 할당은 올려지지 않습니다.
let/const 변수 선언과 함수 표현식에서는 호이스팅이 발생하지 않습니다.
// using var
console.log(name);
var name = "john";
console.log(name);
// hoisting
var name_2;
console.log(name_2);
name_2 = "john";
console.log(name_2);
위 두 형식의 코드는 같은 출력결과를 나타냅니다.
변수가 초기화되기 전에 출력문에 쓰였으므로 undefined
가 자동 할당됩니다.
목적에 따라 특별한 성질이나 정해진 범주를 갖고 있는 데이터의 종류입니다.
JavaScript에서는 6가지의 원시 타입 자료형과 1가지의 객체 타입 자료형으로 구성되어있습니다.
true
, false
typeof는 인수의 자료형을 반환하는 연산자입니다.
연산자인 typeof x와 함수인 typeof(x)로 문법을 지원합니다.
let str = "hello, world!";
console.log(typeof str);
console.log(typeof undefined);
console.log(typeof 123);
console.log(typeof 456n);
console.log(typeof 123.123);
console.log(true);
console.log(typeof "hello");
console.log(typeof Symbol("id"));
console.log(typeof Math);
console.log(typeof null);
console.log(typeof console.log);
위 예제문의 출력은 아래와 같습니다.
왜 아래처럼 출력되는지 자료형들을 통해 더 알아봅시다.
true
와 거짓인 false
, 두가지 값만 존재합니다.let name_check = true;
let age_check = false;
let value_check = 10 > 3;
console.log(value_check); // true 출력
null은 값이 비어있다는 의미로 표현되는 자료형입니다.
존재하지 않는(nothing), 비어 있는(empty), 알 수 없는(unknown) 값을 나타내는데 사용합니다.
console.log(typeof null); // object 출력
const null_check = null;
console.log(null_check === null); // true 출력
undefined는 값이 할당되어 있지 않은 상태를 나타낼 때 사용되는 자료형입니다.
변수 선언 후 초기화하지 않는다면, undefined가 자동으로 할당됩니다.
let name;
console.log(name); // undefined 출력
number(숫자형)은 정수, 부동소수점(floating point) 숫자를 표현하는 자료형입니다.
number와 관련된 연산은 사칙연산(+
,-
,*
,/
) 이 대표적입니다.
number에는 일반적인 숫자 외에 Infinity, -Infinity, NaN(Not a Number) 같은 특수 숫자 값이 포함됩니다.
number에서는 253-1 보다 큰 값을 사용할 수 없으며, 더 큰 정수를 다루고 싶다면 bigint
자료형을 사용해야 합니다.
let num_1 = 123.0;
let num_2 = 123.456;
let num_3 = 1 / 0;
console.log(num_1 - num_2); // -0.45600000000000307 출력
console.log((num_1 - num_2).toFixed(3)); // -0.456 출력
console.log(num_3); // Infinity 출력
console.log(num_1 / "hello"); // NaN 출력
string은 문자, 문자열을 표현하는 자료형입니다.
JavaScript에서 문자열은 3가지 종류의 따옴표로 표현 가능합니다.
--> 큰따옴표, 작은 따옴표, 백틱(역따옴표 : backtick)
let str_1 = "hello";
let str_2 = "hello";
let num = 3;
let str_3 = `hello_${num}`;
console.log(str_3); // hello_3 출력
object에 저장되는 개체들은 직접적으로 object 자료형에 저장되는 것이 아니고, 특정 메모리 공간을 할당받아 해당 장소에 저장됩니다.
object 자료형의 값은 이 메모리 주소를 참조(reference)하여 불러오게 됩니다.
object는 다수의 원시 자료형을 포함하거나 복잡한 개체(entity)를 표현할 수 있는 자료형입니다.
object는 Object() 혹은 중괄호({}
)를 통해 생성합니다.
object의 개체는 key: value
형태로 표현하며, 접근은 object.key
형태로 표현합니다.
let user = {
name: "john",
age: 27,
};
console.log(typeof user); // object 출력
console.log(typeof user.name); // string 출력
console.log(typeof user.age); // number 출력
console.log(user); // { name: 'john', age: 27 } 출력
console.log(user.name); // john 출력
console.log(user.age); // 27 출력
user.age = 30;
console.log(user.age); // 30 출력
user.weight = 72; // user object에 weight 필드 추가
console.log(user); // { name: 'john', age: 27, weight: 72 } 출력
위 예제에서 admin에 user object를 복사하면 따로따로 값이 적용될듯 하지만, 그렇지 않습니다.
아래 의도적으로 일으킨 문제를 보면 알 수 있습니다.
let admin = user; // 객체 복사
console.log(admin);
admin.name = "park";
console.log(admin.name); // park 출력
console.log(user.name); // john --> park 출력
user.age = 30;
console.log(user.age); // 30 출력
console.log(admin.age); // 27 --> 30 출력
object의 값을 복사할 때는 대상 전체가 아닌 object 내 주소 값만 복사되는 문제가 발생합니다.
가리키는 대상 전체를 복사하는 방법은 얕은 복사(Shllow Copy), 깊은 복사(Deep Copy)를 통해 가능합니다.
💡 참고 사이트 : Javascript의 인자전달 Call by value or reference
많이 쓰이는 얕은 복사 방법들을 알아봅시다.
아래와 같은 방법으로 얕은 복사를 실행하면 각각의 개별적인 주소를 가져 서로 영향을 주지 않습니다.
for (let key in user) { // for문 사용
admin[key] = user[key];
}
let admin_1 = Object.assign({}, user); // Object.assign 사용
let admin_2 = { ...user }; // ES6 부터 지원, 전개 연산자
객체 내 또 다른 객체가 있다면 복사되지 않습니다!
객체 내 객체를 얕은 복사
= 객체 내 객체의 주소를 복사
let user = {
name: "john",
age: 27,
sizes: {
height: 180,
weight: 72,
},
};
let admin = { ...user }; // 얕은 복사 문제 발생
admin.sizes.height += 1;
console.log(admin.sizes.height); // 181 출력
console.log(user.sizes.height); // 181 출력
// "객체를 문자열화 --> 다시 해당 문자열을 객체화" 할 때 기존 객체와의 연결이 끊김
let admin_1 = JSON.parse(JSON.stringify(user)); // 깊은 복사 진행
admin_1.sizes.height += 1;
console.log(admin_1.sizes.height); // 182 출력
console.log(user.sizes.height); // 181 출력
깊은 복사는 JSON 함수를 사용하면 한줄로 쉽게 실행시킬 수 있습니다.
위 예제와 같이 깊은 복사를 실행할 수 있으며, 객체의 보다 완벽한 복사를 위해 깊은 복사를 권장합니다.