자바스크립트는 웹 사이트에서 대화형 및 동적 요소를 만드는 데 주로 사용되는 프로그래밍 언어이다. 원래는 웹 브라우저에서 실행되도록 설계된 자바스크립트는 서버 언어(Node.js)로 발전하여, 현재는 프론트앤드와 백앤드 환경에서도 사용될 수 있다. 인터프리터(interpreter) 프로그래밍 언어이며, 일급 함수를 지원한다.
인터프리터 언어란?
컴파일 언어(C, C++, Java)는 정적 타입을 지원하고 애플리케이션이 실행하기 전에 빌드 과정을 거친다. 즉, 빌드된 것을 바탕으로 애플리케이션이 실행된다. 반면, 인터프리터 언어는 런타임시에 동적으로 타입을 결정하면서 코드를 한줄씩 해석하여 실행한다. 컴파일 언어는 안정성이 높지만 실행하기까지 빌드 과정을 거쳐야 하는 반면, 인터프리터 언어는 런타임시에 코드를 해석하고 실행하기 때문에 개발속도가 빠르다.
일급 함수, 일급 객체, 고차 함수
일급 함수
함수를 변수처럼 할당하고 처리할 수 있다.
함수를 배열과 같은 객체와 같은 데이터에 저장할 수 있다.
다른 함수에 인자로 전달될 수 있다.
다른 함수의 반환 값이 될 수 있다.
// Function assigned to a variable
const greet = function (name) {
return `Hello, ${name}!`;
};
// Function passed as an argument
function executeFunction(func, value) {
return func(value);
}
console.log(executeFunction(greet, 'John')); // Output: Hello, John!
일급 개체
다른 함수의 인수로 전달할 수 있다.
다른 함수의 반환값이 될 수 있다.
함수를 배열과 같은 객체와 같은 데이터에 저장할 수 있다.
고차 함수
하나 이상의 함수를 인수로 사용하거나 결과로 함수를 반환하는 함수
// Higher-order function that takes another function as an argument
function multiplier(factor) {
return function (x) {
return x * factor;
};
}
const double = multiplier(2);
console.log(double(5)); // Output: 10
function addAndMultipler(multi, a, b) {
return multi(a + b);
}
const double2 = addAndMultipler(multiplier, 1, 2);
console.log(double2(2)); // Output: 6
콜백함수
이미 만들어 놓은 함수를 다른 함수의 인자로 전달했을 때, 전달된 함수는 콜백함수
전달될 당시에 함수를 바로 호출해서 반환된 값을 전달하는 것이 아니라, 함수를 가리키고 있는 참조값, 이 전달된다. 따라서, 해당 함수는 고차 함수 안에서 필요한 순간에 호출된다.
불편성
함수내부에서 외부로부터 주어진 인자의 값을 변경하는 것으 좋지 않다. 변경이 필요한 경우에는 새로운 상태(오브젝트 또는 값)를 만들어서 반환하는 것이 좋다. 이것을 인지하기 위해서는 원시 타입의 값과 과 참조 타입의 값에 대한 이해가 필요하다.
원시 타입
number
string
boolean
undefined
null
Symbol (ES6+, 고유 식별자를 나타냄)
Bigint (ES2020, 기본 타입으로 간주되지는 않는다)
Object
자바스크립트에서 가장 일반적인 객체 유형이다. 자바스크립트 객체는 키-값 쌍의 모음이며 다양한 엔티티를 나타낸다.
let person = { name: 'John', age: 30 };
let car = { make: 'Toyota', model: 'Camry' };
Array
순서가 지정된 값 목록을 저장하고 조작하는 데 사용되는 객체이다. 0부터 시작하는 정수로 인덱스됩니다.
let numbers = [1, 2, 3, 4, 5];
let fruits = ['apple', 'orange', 'banana'];
Function
자바스크립트에서 함수는 일급 객체이다. 즉, 함수는 변수에 할당되고, 인수로 전달되고, 다른 함수에서 반환될 수 있다. 자바스크립트에서 함수를 정의하는 여러가지 방식이 있다.
// 함수 선언
function name() {}
// 함수 표현
const name = function () {};
// 화살표 함수
const func () => {}
// 생성자 함수
const funcName = new Function()
// IIFE (Immediatley-Invoked Function Expression)
// 이렇게 하면 바로 실행된다. 즉, 호출할 필요가 없다.
(function run() { console.log('test');})();
Date
날짜와 시간을 나타낸다.
let currentDate = new Date();
RegExp(정규식)
문자열 일치에 대한 패턴을 나타낸다.
let regex = /pattern/;
Map
키가 모든 데이터 유형일 수 있는 키-값 쌍의 모음이다. 효율적인 데이터 검색이 가능하다.
let myMap = new Map();
myMap.set('name', 'John');
Object 와의 차이점
객체에서 키는 항상 문자열 또는 기호이다. 숫자와 같은 문자열이 아닌 키는 자동으로 문자열이 된다. 맵에서 키는 객체, 숫자, 문자열 등 모든 데이터 유형이 될 수 있다.
맵의 키 순서는 추가된 순서가 보장되지만, 객체는 그렇지 않다. 보통 객체도 키가 추가된 순서가 유지 되지만, 이것은 표준화된 동작은 아니다.
맵은 Prototype 에 있는 다양한 메서드 등을 지원히잠, 오브젝트는 그렇지 않다.
Set
고유한 값의 모음이다.
let mySet = new Set([1, 2, 3, 4, 5]);
Promise
비동기 작업을 처리하는 데 사용된다.
let myPromise = new Promise((resolve, reject) => {
// asynchronous operation
});
Symbol(추후 더 자세히 정리)
고유하고 변경할 수 없는 식별자를 나타낸다. 객체에 고유한 속성 키를 생성하는 데 사용된다.
let mySymbol = Symbol('description');
Call By Value, Call by Reference
원시 값은 stack 이라는 공간에 값 자체를 보관한다.
객체는 heap 이라는 공간에 저장된다. 이 객체의 변수명은 heap 메모리 주소를 가지고 있다. 즉, heap 메모리에 저장되어있는 주소 값을 stack 에 저장하는 것이며, 해당 변수는 stack 에 저장된다.
const a = 1;
const b = 1;
// 값 자체를 비교한다.
console.log(a === b); // true
const c = { a: 1, b: 1 };
const d = { a: 1, b: 1 };
// heap 이라는 메모리 주소를 비교하기 때문에 내용이 같더라도 false 가 출력된다.
console.log(a === b); // false
변수(var, let, const)
변수는 이름이 주어진 기억장소를 뜻한다. 따라서 변수의 이름은 구체적이고 명확하고 의미를 나타낼수록 좋다. 앞에서 설명한 것과 같이 변수에는 원시 값과 객체 둘 다 할당할 수 있다.
var
변수에 var 를 선언하지 않아도 var 가 기본적으로 선언된다. 즉, 변수를 선언하는 키워드 없이 선언하고 할당이 가능한데, 이 특징으로 인하여 할당/재할당 구분이 어렵다.
변수명 중복 선언이 가능하다.
블록 레벨 스코프가 적용되지 않는다.
함수 스코프이기 때문에 호이스팅 될 때 초기화도 된다.
// var a 라는 변수가 호이스팅 되고 초기화가 되어, console.log(a) 에 값이 출력된다.
console.log(a); // a
var a = 0;
let
let 으로 선언된 변수는 블록 범위이다. 즉, 정의된 블록({}) 내에서만 접근할 수 있다.
호이스팅 될 때, 초기화가 되지 않는다. 따라서, 선언전에 접근하면 에러가 발생한다.
재할당 가능하다.
const
let 과 마찬가지로 블록 범위에서 접근 가능하다.
이 역시 호이스팅 될 때, 초기화가 되지 않는다. 따라서, 선언전에 접근하면 에러가 발생한다.
재할당이 불가능하다. const 라는 이름에서 알 수 있듯이 상수를 정의할 때 사용한다.
Wrapper 클래스
래퍼 객체라고 읽을 수 있다. 필요에 따라서 원시 값을 관련된 객체로 변환한다. 래퍼 객체를 사용하여 만들거나 혹은 변환한 변수에서 . 을 하는 순간 변수는 래퍼 겍체로 변환된다. 래퍼 객체 안에는 많은 기능들이 정의되어있는데(클래스 변수, 각종 메서드 등..), 이 기능을 사용할 수 있다. 간단하게 이해하자면 어떤 클래스를 상속받은 하위 클래스의 인스턴스에서 부모 클래스에 정의된 변수나 메서드를 사용할 수 있는 것과 같다.
한가지 주의해야 할 점은 래퍼 객체를 사용하여 변수를 만들면 메모리를 더 잡아먹는다는 것이다.
const flag1 = true;
const flag2 = new Boolean(true);
글로벌 객체
// this 는 전역객체를 가리키고, node 에서는 현재 module 가 전역객체이다.
// 브라우저에서는 Window 를 가리킨다.
console.log(globalThis);
// 그 외 글로벌 객체
// this, Infinity, NaN, undefined
Truthy, Falthy, Nullish 에 대하여
Truthy 의 경우
// 1
// -1
// '0'
// 'false'
// [] (Python 에서는 False 로 판단한다.)
// {} (Python 에서는 False 로 판단한다.)
Falthy 의 경우
// 0
// -0
// null
// NaN
// undefined
// ''
논리 연산자 && 와 ||, ??
'단락 평가' 또는 '단축 평가'(short-circuit)를 수행하기 위해서 사용되는 연산자이다. if 문 안에서의 쓰임새와는 다르다.
&&
첫 번째 피연산자가 참인 경우 두 번째 피연산자의 값을 반환한다.
첫 번째 피연산자가 거짓인 경우, 첫 번째 피연산자의 값을 반환한다.
즉, 첫 번째 피연산자가 거짓인 경우, 두 번째 피연산자는 평가하지 않는다.
let result1 = true && 'Hello';
console.log(result1); // Output: 'Hello'
let result2 = false && 'Hello';
console.log(result2); // Output: 'Hello'
||
첫 번째 피연산자가 참인 경우 첫 번째 피연산자의 값을 반환한다.
첫 번째 피연산자가 거짓이면 두 번째 피연산자의 값을 반환한다.
'&&'와 마찬가지로, 첫 번째 피연산자가 참이면 두 번째 피연산자는 평가되지 않는다.
let result1 = true || 'Hello';
console.log(result1); // Output: 'true'
let result2 = false || 'Hello';
console.log(result2); // Output: 'Hello'
??
nullish 병합 연산자이다.
왼쪽 피연산자가 null 또는 undefined 인 경우, 오른쪽 피연산자를 반환한다. || 연산자와는 달리, 0 이나 false 또는 빈문자열에 대해서는 연산을 수행하지 않는다.
const someValue = '';
let result = someValue ?? defaultValue;
console.log(result); // 연산되지 않음, 따라서 undefined 도 출력되지 않음
const someValue2 = 'aaa';
let result2 = someValue2 ?? defaultValue;
console.log(result2); // 'aaa'
const someValue3 = null;
const defaultValue = 'default';
let result3 = someValue3 ?? defaultValue;
console.log(result3); // 'default'
someValue가 null 또는 undefine이 아닌 경우 someValue 값이 할당된다.
someValue가 null 또는 undefine인 경우 defaultValue 값이 할당된다.
// 1.7976931348623157e+308
// e+308 = 10의 308승
// 즉 1.7976931348623157 308승
// 5e-324
// 즉, 5의 -324승
// 0과 1사이에서 나타낼 수 있는 가장 작은 숫자 EPSILON
// console.log(Number.EPSILON);