Afaik
책 읽기자바스크립트 딥다이브

자바스크립트 딥다이브 2

연산자

  • 증가/감소(++/--) 연산자는 피연산자의 값을 변경하는 부수 효과가 있다.
var x = 1;
 
// ++ 연산자는 피연산자의 값을 변경하는 암묵적 할당이 이뤄진다.
x++;
console.log(x); // 2
 
// -- 연산자는 피연산자의 값을 변경하는 암묵적 할당이 이뤄진다.
x--;
console.log(x); // 1

증가/감소 연산자

  • 피연산자 앞에 위치한 전위 증가/감소 연산자는 먼저 피연산자의 값을 증가/감소 시킨 후 다른 연산을 수행한다.
  • 피연산자 뒤에 위치한 후위 증가/감소 연산자는 먼저 다른 연산을 수행한 후 피연산자의 값을 증가/감소 시킨다.
var x = 5,
  result;
 
// 선할당 후증가(postfix increment operator)
result = x++;
console.log(result, x); // 5 6
 
// 선증가 후 할당 (prefix increment operator)
result = ++x;
console.log(result, x); // 7 7
 
// 선할당 후감소(postfix decrement operator)
result = x--;
console.log(result, x); // 7 6
 
// 선감소 후할당(prefix decrement operator)
result = --x;
console.log(result, x); // 5 5

문자열 연결 연산자

  • + 연산자는 피연산자 중 하나 이상이 문자열인 경우 문자열 연결 연산자로 동작한다.
    • 1 + true를 연산하면 자바스크립트 엔진은 암묵적으로 불리언 타입의 값인 true를 숫자 타입인 1로 타입을 강제로 변환한 후 연산을 수행한다.
    • 이를 암묵적 타입변환 또는 타입 강제변환 이라고 한다.

동등/일치 비교 연산자

  • 동등 비교 연산자(==)는 느슨한 비교를 하지만 일치 비교 연산자(===)는 엄격한 비교를 한다.
    • 동등 비교 연산자(==)는 좌항과 우항의 피연산자를 비교할 때 먼저 암묵적 타입 변환을 통해 타입을 일치시킨 후 같은 값인지 비교한다.
    • 일치 비교 연산자(===)는 좌항과 우항의 피연산자가 타입도 같고 값도 같은 경우에 한하여 true를 반환한다.

주의 사항

NaN
// NaN은 자신과 일치하지 않는 유일한 값이다.
NaN === NaN; // false
 
// 숫자가 NaN인지 조사하려면 빌트인 함수 Number.isNaN을 사용한다.
Number.isNaN(NaN); // true
Number.isNaN(10); // false
 
Number.isNaN(1 + undefined); // true
숫자 0
// 양의 0과 음의 0의 비교 (일치 비교/동등 비교 모두 true)
0 === -0; // true
0 == -0; // true

typeof 연산자

타입비고
typeof ''string
typeof 1number
typeof NaNnumbernumber 타입 주의
typeof trueboolean
typeof undefinedundefined
typeof nullobjectobject 타입 주의
typeof Symbol()symbol
typeof []object
typeof {}object
typeof new Date()object
typeof /abc/giobject
typeof function() {}function

typeof 연산자

  • typeof 연산자로 null 값을 연산해 보면 null이 아닌 object를 반환한다는 데 주의하자.
    • 이는 자바스크립트의 첫 버전의 버그이다.
    • 값이 null 타입인지 확인할 때는 일치 연산자 (===)를 사용하자.

제어문

블록문

  • 블록문(block statement/compound statement)은 0개 이상의 중괄호로 묶은 것으로, 코드 블록 또는 블록이라고 부르기도 한다.
블록문, 제어문, 함수 선언문
// 블록문
{
  var foo = 10;
}
 
// 제어문
var x = 1;
if (x < 10) {
  x++;
}
 
// 함수 선언문
function sum(a, b) {
  return a + b;
}

조건문

  • if 문의 조건식이 불리언 값이 아닌 값으로 평가되면 자바스크립트 엔진에 의해 암묵적으로 불리언 값으로 강제 변환되어 실행할 코드 블록을 결정한다.
if 문
var x = 2;
var result;
 
// 2 % 2는 0이므로 조건식은 false이다.
if (x % 2) {
  result = "홀수";
} else {
  result = "짝수";
}
 
console.log(result); // 짝수

타입 변환과 단축 평가

  • 개발자가 의도적으로 값의 타입을 변환하는 것을 명시적 타입 변환 또는 타입 캐스팅이라 한다.
  • 자바스크립트 엔진에 의해 표현식을 평가하는 도중 암묵적으로 타입이 자동으로 변환되기도 한다.
    • 이를 암묵적 타입 변환 또는 타입 강제 변환이라 한다.

문자열 타입으로 변환

  • 문자열 연결 연산자 표현식을 평가하기 위해 문자열 연결 연산자의 피연산자 중에서 문자열 타입이 아닌 피연산자를 문자열 타입으로 암묵적 타입 변환한다.
문자열 연결 연산자
1 + "2"; // "12"

숫자 타입으로 변환

  • 산술 연산자 표현식을 평가하기 위해 산술 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환한다.
    • 이때 피연산자를 숫자 타입으로 변환할 수 없는 경우는 평가 결과가 NaN이다.
산술 연산자
10 - "2"; // 8
10 * "2"; // 20
10 / "one"; // NaN
  • 비교 연산자는 피연산자의 크기를 비교하므로 모든 피연산자는 코드의 문맥상 모두 숫자 타입이어야 한다.
    • 자바스크립트 엔진은 비교 연산자 표현식을 평가하기 위해 비교 연산자의 피연산자 중에서 숫자 타입이 아닌 피연산자를 숫자 타입으로 암묵적 타입 변환한다.
비교 연산자
"10" > 2; // true

+ 단항 연산자

  • + 단항 연산자는 피연산자가 숫자 타입의 값이 아니면 숫자 타입의 값으로 암묵적 타입 변환을 수행한다.
+ 단항 연산자
// 문자열 타입
 
+""; // 0
+"10"; // 10
+"one"; // NaN
 
// 불리언 타입
+true; // 1
+false; // 0
 
// null 타입
+null; // 0
 
// undefined 타입
+undefined; // NaN
 
// 심벌 타입
+Symbol(); // TypeError: Cannot convert a Symbol value to a number
 
// 객체 타입
+{}; // NaN
+[]; // 0
+[10, 20]; // NaN
+function () {}; // NaN

주의 사항

  • 빈 문자열, 빈 배열, null, false는 0으로, true는 1로 변환된다.
  • 객체와 빈 배열이 아닌 배열, undefined는 변환이 되지 않아 NaN이 된다는 것에 주의해야한다.

객체란?

  • 자바스크립트는 객체 기반의 프로그래밍 언어이며, 자바스크립트를 구성하는 거의 "모든 것"이 객체다.
    • 원시 값을 제외한 나머지 값(함수, 배열 정규 표현식 등)은 모두 객체다.
  • 원시 타입의 값은 변경 불가능한 값이지만 객체 타입의 값은 변경 가능한 값이다.
  • 객체에 존재하지 않는 프로퍼티에 접근하면 undefined를 반환한다.
    • ReferenceError가 발생하지 않는데 주의하자.
  • delete 연산자는 객체의 프로퍼티를 삭제한다.
    • 프로퍼티 삭제 후 객체에 삭제한 프로퍼티가 존재하지 않는다면 프로퍼티 값은 undefined가 된다.
    • 존재하지 않는 프로퍼티를 삭제하려고 하면 에러가 발생하지 않는다는 것에 주의하자.

원시 값과 객체의 비교

  • 원시 값은 변경 불가능한 값이며 객체는 변경 가능한 값이다.
    • 원시 값은 읽기 전용 값으로서 변경할 수 없다.
    • 새로운 원시 값을 재할당하면 메모리 공산에 저장되어 있는 값을 변경하는 것이 아니라 새로운 메모리 공간을 확보하고 재할당한 원시 값을 저장한 후 이 공간을 가리킨다. (변수가 참조하던 메모리 공간의 주소가 바뀐다.)
      • 값의 이러한 특성을 불변성이라 한다.
  • 변수에 원시 값을 갖는 변수를 할당하면 원시 값이 복사되어 전달된다.
    • 이를 값에 의한 전달이라 한다.
    • 각 변수의 값은 같지만 다른 메모리 공간에 저장된 별개의 값이 된다.
      • A 변수의 값을 B에게 할당하고 B의 값을 바꾸더라도 A의 값은 변경되지 않는다.
      • 파이썬의 경우 두 변수가 같은 원시값을 참조하다가 어느 한쪽의 값이 바뀌면 새로운 메모리 공간에 재할당된 값을 저장하도록 동작할 수도 있다.
    • 식별자는 값이 아니라 메모리 주소를 기억하고 있다. (메모리 주소를 통해 메모리 공간에 접근하면 값을 참조할 수 있다.)
  • 객체를 변수에 할당하면 변수에는 참조 값이 저장된다.
    • 이를 참조에 의한 전달이라 한다.
    • 객체를 할당한 변수는 재할당 없이 객체를 직접 변경할 수 있다.
      • 메모리를 효율적으로 사용하고 객체를 복사해 생성하는 비용을 절약해 성능을 향상시키기 위해 변경이 가능한 값으로 설계되어 있다.
      • 단점으로 여러개의 식별자가 하나의 객체를 공유할 수 있다.
    • 식별자에 할당된 객체를 다른 변수에 복사(할당)하면 메모리 주소는 다르지만 동일한 참조 값을 갖는다.
      • 원본 또는 사본 중 어느 한쪽에서 객체를 변경하면 서로 영향을 주고 받는다.

함수란?

  • 함수는 일련의 과정을 문으로 구현하고 코드 블록으로 감싸서 하나의 실행 단위로 정의한 것이다.
  • 함수 내부로 입력을 전달받는 변수를 매개변수(parameter), 입력을 인수(argument), 출력을 반환값(return value)이라 한다.

함수의 정의 방식

함수 선언문
function add(x, y) {
  return x + y;
}
  • 함수 선언문은 함수 이름을 생략할 수 없다.
  • 함수 선언문 이전에 호출할 수 있다.
함수 표현식
const add = function (x, y) {
  return x + y;
};
  • 함수 표현식은 함수 이름을 생략할 수 있다. (이를 익명 함수라 한다.)
  • 함수 표현식 이전에 호출할 수 없다.
Function 생성자 함수
const add = new Function("x", "y", "return x + y");
  • Function 생성자 함수는 함수 선언문이나 함수 표현식으로 정의한 함수와 다르게 동작한다.
    • 클로저를 생성하지 않는 등의 차이가 있다.
화살표 함수
const add = (x, y) => x + y;
  • 기존 함수와 this 바인딩 방식이 다르며 prototype 프로퍼티가 없으며 arguments 객체를 생성하지 않는다.

함수 호출

매개변수와 인수

function add(x, y) {
  return x + y;
}
 
// 함수 호출
// 인수 1과 2가 매개변수 x와 y에 순서대로 할당되고 함수 몸체의 문들이 실행된다.
const result = add(1, 2);
  • 함수 호출 시 매개변수가 생성되어 undefined로 초기화된 후, 인수가 할당된다.
  • 함수를 호출할 때 매개변수의 개수만큼 인수를 전달하는 것이 일반적이지만 그렇지 않은 경우에도 에러가 발생하지는 않는다.
    • 인수가 부족할 경우 매개변수에는 undefined가 할당된다.
  • 함수의 매개변수는 코드를 이해하는 데 방해되는 요소이므로 이상적인 매개변수 개수는 0개이다.
    • 매개변수가 많다는 것은 함수가 여러가지 일을 한다는 증거이므로 바람직하지 않다.
    • 이상적인 함수는 한 가지 일만 해야하며 가급적 작게 만들어야 한다.
    • 매개변수가 3개 이상을 넘어가게 되면 객체 형태로 인수를 전달하는 것이 좋다.

반환문

반환문 이후의 문은 실행되지 않는다.
function multiply(x, y) {
  return x * y;
  console.log("실행되지 않는다."); 
}
 
multiply(3, 5); // 15
  • 반환문은 함수의 실행을 중단하고 함수 몸체를 빠져나간다. 따라서 반환문 이후에 다른 문이 존재하면 그 문은 실행되지 않고 무시된다.
  • return 키워드 뒤에 반환값으로 사용할 표현식을 명시적으로 지정하지 않으면 undefined가 반환된다.

다양한 함수의 형태

즉시 실행 함수

함수 선언문이나 함수 표현식으로 정의되지 않은 이름 없는 함수를 즉시 실행할 수 있다.

(function () {
  var a = 3;
  var b = 5;
  return a * b;
})();
  • 즉시 실행 함수는 함수 이름이 없는 익명 함수를 사용하는 것이 일반적이다.
  • 그룹 연산자 (...) 내의 기명 함수는 함수 선언문이 아니라 함수 리터럴로 평가되며 함수 이름은 함수 몸체에서만 참조할 수 있는 식별자 이므로 즉시 실행 함수를 다시 호출할 수 없다.

재귀 함수

함수가 자기 자신을 호출하는 것을 재귀 호출이라 한다. 재귀 함수는 자기 자신을 호출하는 행위, 즉 재귀 호출을 수행하는 함수를 말한다.

  • 재귀 함수 내에는 재귀 호출을 멈출 수 있는 탈출 조건을 반드시 만들어야 한다.
    • 탈출 조건을 만들지 않으면 함수가 무한히 재귀 호출을 반복하여 스택 오버플로우를 발생시키고 프로그램이 종료된다.
function factorial(n) {
  if (n <= 1) return 1;
}

중첩 함수

함수 내부에 정의된 함수를 중첩 함수(nested function)라 한다.

  • 함수 내부에 정의된 함수를 중첩 함수 또는 내부 함수라 한다.
  • 중첩 함수는 외부 함수 내부에서만 호출할 수 있고 일반적으로 외부 함수를 돕는 헬퍼 함수 역할을 한다.
Edit on GitHub

Last updated on