22. 10. 13 자바스크립트) 자바스크립트 기본

divedeepp·2022년 10월 13일
0

JavaScript

목록 보기
2/11

스크립트를 작성하는 장소

내부 스크립트

<script> 태그를 이용하여 자바스크립트 코드를 HTML 문서에 삽입할 수 있다.

<!DOCTYPE HTML>
<html>

<body>

  <p>스크립트 전</p>

  <script>
    alert( 'Hello, world!' );
  </script>

  <p>스크립트 후</p>

</body>

</html>

외부 스크립트

<script>태그에 src속성을 사용하여 외부에서 작성한 자바스크립트 코드를 HTML에 삽입할 수 있다.

// 상대 경로 방식 예시
<script src="/path/to/script.js"></script>

// 절대 경로 방식 예시
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Strict mode

ES5 이후 기존 기능 중 일부가 변경되어, 하위 호환성에 문제가 생겼다.

기본 모드에선 변경사항의 대부분이 활성화되지 않지만, 특별 지시자를 사용해 strict mode를 활성화하면 변경사항을 활성화할 수 있다.

use strict 지시자

스크립트 최상단에 use strict 지시자가 오면, 스크립트 전체가 "모던"하게 동작한다.

"use strict";

...

함수 본문 맨앞에 use strict 지시자가 오면, 해당 함수만 strict mode로 실행된다.

function func() {
  "use strict";
  ...
}

참고로, 클래스와 모듈을 사용한 모던 자바스크립트는 use strict가 자동으로 적용되므로, 스크립트에 붙일 필요가 없다.


변수와 상수

변수(Variable)

값을 저장할 때 쓰이는, 쉽게 말해 이름이 붙은 저장소이다.
변수는 메모리 영역에 연결되고, 값이 해당 메모리 영역에 저장된다. 그 후 변수 이름을 통해 값에 접근할 수 있다.

변수 생성

let 키워드를 사용해 변수를 생성한다.

// 변수 선언(생성)
let message;

// 변수 안에 데이터 할당(저장)
message = "hello";

// 변수명을 이용해 저장된 데이터에 접근
alert(message);

// 변수 선언과 할당을 한 번에 하기
let message = "hello";

변수는 한 번만 선언해야 한다. 같은 이름의 변수를 여러 번 선언하면 에러가 발생한다.

참고로, var키워드는 let과 거의 동일하게 동작한다. 하지만 호이스팅 문제 때문에 모던 자바스크립트에는 쓰지 않는 것을 권장한다.

자바스크립트와 함수형 언어 내용 추가 예정

변수명을 짓는 규칙

변수명을 지을 때는 두 가지 제약 사항이 있다.

  1. 변수명에는 문자숫자, 기호 $_만 들어 갈 수 있다.
  2. 숫자는 변수명의 첫 글자에 올 수 없다.

그리고 제약 사항은 아니지만 개발자들 사이의 암묵적인 변수명 규칙들이 있다.

  1. 변수가 담고있는 것이 무엇인지 잘 설명해주는 이름이어야 한다.
    ex) userName
  2. 여러 단어를 조합한 변수명은 camelCase 혹은 snake_case 를 사용해 명명한다.
  3. let, class 등 예약어는 변수명으로 사용할 수 없다.

상수(Constant)

저장한 데이터를 변경하지 않는 변수를 선언할 때에는, const 키워드를 사용한다. 상수를 변경하려고 하면 에러가 발생한다.

const myBirthDay = "1996.06.26";

기억하기 힘든 값을 대문자 상수로 선언하는 것은 널리 사용되는 관습이다. 이런 상수는 대개 대문자와 밑줄로 명명한다.

const COLOR_RED = "#F00";

자료형

자바스크립트는 동적 타입 언어로, 변수에 저장되는 값의 타입은 언제든 바꿀 수 있다.

숫자형(number Type)

숫자형은 정수 및 부동소수점 숫자를 나타낸다.

let n = 123;

1, -1, 0.1 뿐만 아니라 Infinity, -Infinity, NaN 같은 특수 숫자 값도 포함된다.

BigInt형(bigInt Type)

높은 정밀도로 작업을 해야 할 때 다루는 숫자형과 비슷한 타입이다.

정수 리터럴 끝에 n을 붙여서 만들 수 있다.

const bigInt = 1234567890123456789012345678901234567890n;

문자형(string Type)

"", '', `` 세 가지 따옴표로 문자열을 만들 수 있다.

백틱으로 감싼 문자열안에는 ${} 안에 변수나 표현식을 넣을 수 있다.

let str = "hello";
let str2 = 'Single quotes are ok too';
let phrase = `can embed another ${str}`;

불리언형(boolean Type)

truefalse 값을 나타내는 자료형이다.

let isGreater = 4 > 1;

alert( isGreater ); // true

null형(null Type)

null 값만을 가지는 자료형이다.

존재하지 않는 값, 비어 있는 값, 알 수 없는 값 등을 나타내는 데 사용한다.

let age = null;

undefined형(undefined Type)

undefined 값만을 가지는 자료형이다.

값이 할당되지 않은 상태를 나타낸다. 변수는 선언했지만 값을 할당하지 않았을 때, 해당 변수에 undefined가 자동으로 할당된다.

let age;

alert(age); // undefined

객체형(object Type)

문자열이나 숫자, null 등 한 가지만 표현할 수 있는 원시(primitive) 자료형과 달리, 데이터 컬렉션이나 복잡한 개체를 표현할 수 있는 자료형이다.

심볼형(Symbol Type)

객체의 고유한 식별자(unique identifier)를 만들 때 사용된다.

typeof 연산자

해당 변수의 자료형을 알고 싶을 때 사용하는 연산자이다.

typeof ... 혹은 typeof(...) 두 가지 방식으로 사용할 수 있다.

typeof undefined // undefined
typeof 0 // number
typeof("foo") // string
typeof null // object  => null 타입은 객체형과 별도의 자료형이지만 하위 호환성을 위해 object 타입을 나타낸다.
typeof alert // function => 함수형으로 표현되지만 함수형은 따로 없고, 함수는 객체형에 속한다. 이 또한 하위 호환성 유지를 위해 남겨진 표현이다.

형 변환(Type Conversion)

함수와 연산자에 전달되는 값이 적절한 자료형으로 자동 변환되는 일이나, 전달받은 값을 의도적으로 원하는 타입으로 변환해 주는 경우를 말한다.

// 문자형으로 변환
let value = true; // true
value = String(value) // "true"

// 숫자형으로 변환
let num = "123"; // "123"
num = Number(num) // 123

// 불린형으로 변환
// 0, 빈 문자열, null, undefined, NaN은 false.
// 그 외의 값은 true로 변환된다.
Boolea(1) // true
Boolean(0) // false
Boolean("hi") // true
Boolean("") // false

연산자

피연산자의 갯수에 따른 연산자 분류

단항 연산자(unary operator) : 피연산자를 하나만 받는 연산자

// 단항 연산자(unary operator)
let x = 1;
x = -x; // -1

// 단항 연산자 +는 피연산자가 숫자형이 아닌 경우 숫자형으로 변환한다.
+true // 1
+"" // 0

이항 연산자(binary operator) : 두 개의 피연산자를 받는 연산자

// 숫자 덧셈
let x = 1, y = 3;
y - x // 2

// 문자열 붙이기
let s = "my" + "string"; // "mystring"

// 피연산자가 하나라도 문자열이면 결과는 문자열을 반환
2 + "1" // "21"

연산자 우선순위(Precedence)

하나의 표현식에 둘 이상의 연산자가 있는 경우, 실행 순서는 연산자의 우선순위에 의해 결정된다.

우선순위가 같으면 왼쪽에서 오른쪽으로 연산이 수행된다.

괄호안의 연산은 모든 우선순위를 무시하고 가장 먼저 수행된다.

수학 연산자

  • 덧셈 연산자 +
  • 뺄셈 연산자 -
  • 곱셈 연산자 *
  • 나눗셈 연산자 /
  • 나머지 연산자 %
  • 거듭제곱 연산자 **

할당 연산자

무언가를 할당할 때 쓰이는 연산자이다.

// 값 할당
let x = 2 * 2 + 1; // 5

// 값을 반환
let a = 1;
let b = 2;

let c = 3 - (a = b + 1);

a // 3
c // 0

// 체이닝 => 할당 연산자는 우측부터 평가가 진행된다.
let a, b, c;

a = b = c = 2 + 2;

a // 4
b // 4
c // 4

복합 할당 연산자

변수에 연산자를 적용하고, 그 결과를 같은 변수에 저장할 때 쓰이는 연산자이다.

let n = 2;
n += 5; // 7
n *= 2; // 14
n -= 8; // 6
n /= 3; // 2

증가 / 감소 연산자

let counter = 2;

// 증가 연산자 : 변수를 1 증가시킨다.
counter++; // 3

// 감소 연산자 : 변수를 1 감소시킨다.
counter--; // 2

증감 연산자는 피연산자의 뒤에 올 때를 후위형(postfix), 피연산자 앞에 올 때는 전위형(prefix)이라 부른다.

전위형은 증감 후의 새로운 값을 반환한다.
후위형은 증감 전의 기존 값을 반환하고, 증감한다.

비트 연산자

피연산자를 32비트 정수로 변환하여 이진 연산을 수행한다.

  • AND &
  • OR |
  • XOR ^
  • NOT ~
  • 왼쪽 시프트 <<
  • 오른쪽 시프트 >>
  • 부호 없는 오른쪽 시프트 >>>

쉼표 연산자

여러 표현식을 코드 한 줄에서 평가할 수 있게 한다.

표현식 각각이 모두 평가되지만, 마지막 표현식의 평가 결과만 반환된다.

let a = (1 + 2, 3 + 4);

a; // 7 (3 + 4의 결과만 할당됨)

// 한 줄에서 세 개의 연산이 수행됨
for (a = 1, b = 3, c = a * b; a < 10; a++) {
 ...
}

비교 연산자

  • 부등호 연산자 >, <, >=, <=
  • 동등 연산자 ==
  • 부등 연산자 !=
  • 일치 연산자 ===
  • 불일치 연산자 !==

비교 연산자는 기본적으로 불린형을 반환한다.

2 > 1 // true
2 == 1 // false
2 != 1 // true

비교 연산자를 사용하여 유니코드순으로 문자열을 비교할 수 있다.

  • 유니코드 뒤쪽의 문자열은 유니코드 앞쪽의 문자열보다 크다.
  • 문자열의 첫 글자부터 차례대로 비교한다.
  • 비교가 종료되었을 때, 문자열이 긴 쪽이 더 크다고 결론내린다.
"Z" > "A" // true
"A" > "a" // false
"Bee" < "Be" // false

일치와 불일치 연산자는 형 변환 없이 피연산자의 자료형까지 비교하여 검사하기 때문에 더 엄격하다.

0 == false // true
0 === false // false

논리 연산자

  • OR ||
  • AND &&
  • NOT !

OR 연산자는 피연산자가 모두 false인 경우를 제외하고 연산 결과는 항상 true이다.

true || true;   // true
false || true;  // true
true || false;  // true
false || false; // false

또, 첫 번째 truthy를 찾는데에도 쓰인다.

result = value1 || value2 || value3;
  1. 왼쪽 피연산자부터 시작해 평가한다.
  2. 각 피연산자를 불린형으로 변환하고, 변환값이 true이면 연산을 멈추고 해당 피연산자의 변환 전 원래 값을 반환한다.
  3. 피연산자를 모두 평가해도 false인 경우 가장 마지막 피연산자를 반환한다.

이러한 기능은 다양한 용도로 활용할 수 있다.

  1. 변수 또는 표현식들에서 첫 번째 truthy 값 얻기
let firstName = "";
let lastName = "";
let nickName = "바이올렛";

alert( firstName || lastName || nickName || "익명"); // 바이올렛
  1. 단락 평가(short circuit evaluation)
    논리 연산자 (&& , ||) 를 사용하여 연산을 진행 할 때 좌측 식의 값에 따라 우측 식의 실행 여부를 판단하는 동작. || 단락 평가는 연산자 왼쪽 조건이 falsy일 때만 명령어를 실행하고자 할 때 자주 쓰인다.
true || alert("not printed");
false || alert("printed");

AND 연산자는 두 피연산자가 모두 참일 때만 true를 반환한다. 또, 첫 번째 falsy를 찾는데에도 쓰인다.

result = value1 && value2 && value3;
  1. 왼쪽부터 피연산자를 평가한다.
  2. 각 피연산자는 불린형으로 변환되고, 변환후 값이 false이면 평가를 멈추고 해당 피연산자의 원래 값을 반환한다.
  3. 피연산자 모두가 true로 평가되는 경우 마지막 피연산자를 반환한다.
1 && 0; // 0
1 && 5; // 5
null && 5; // null
0 && "아무거나 와도 상관없습니다."; // 0

NOT 연산자는 피연산자를 불린형으로 변환하고, 변환된 불린값의 역을 반환한다.

result = !value;

!true; // false
!0; // true

NOT연산자가 피연산자를 불린형으로 변환하고 평가하는 특징을 활용해 , 두 개 연달아 사용하면 역의 역연산을 수행하므로 피연산자를 불린형으로 변환할 수 있다.

!!"non-empty string"; // true
!!null; // false

nullish 병합 연산자

여러 피연산자 중 값이 확정되어있는 변수를 찾을 수 있다.

a ?? b // a가 null 혹은 undefined이면 b, 아니면 a 이다.

조건문

if문

괄호 안에 들어가는 조건을 평가하고, 그 결과를 불린값으로 변환하여 true이면 코드 블록이 실행된다.

let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year == 2015) {
  alert( '정답입니다!' )
};
  • 0, "", null, undefined, NaN은 불린형으로 변환 시 모두 false가 된다. 이 들을 falsy 값이라 부른다.
  • 이 외의 값을 불린형으로 변환 시 true가 되므로, truthy 값이라 부른다.

else문

if문else문을 불일 수 있다.

else 뒤에 이어지는 코드 블록은 조건이 거짓일 때 실행된다.

let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year == 2015) {
  alert( '정답입니다!' );
} else {
  alert( '오답입니다!' ); // 2015 이외의 값을 입력한 경우
}

else문은 필수가 아닌 선택 사항이다.

else if문

여러 개의 조건을 처리할 때 쓰이는 구문이다.

let year = prompt('ECMAScript-2015 명세는 몇 년도에 출판되었을까요?', '');

if (year < 2015) {
  alert( '숫자를 좀 더 올려보세요.' );
} else if (year > 2015) {
  alert( '숫자를 좀 더 내려보세요.' );
} else {
  alert( '정답입니다!' );
}

조건부 연산자

물음표 연산자 또는 삼항 연산자라고도 불리며, 조건문을 좀 더 간결하게 변형할 수 있다.

연산자 앞의 조건이 truthy이면 value1이, falsy라면 value2 가 반환된다.

let result = condition ? value1 : value2;

추가적으로 물음표 연산자는 조건에 따라 반환 값을 달리하려는 목적으로 만들어졌다. 조건을 여러 분기로 만들어 처리할 때는 if를 사용하는 것이 좋다.

switch문

복수의 if 조건문을 switch 조건문으로 바꿀 수 있다.

switch(x) {
  case 'value1':  // if (x === 'value1')
    ...
    [break]

  case 'value2':
    ...
    [break]

  default:	// 옵션임
    ...
    [break]
}
  1. 변수 x의 값과 첫 번째 case문의 값부터 차례대로 비교한다.
  2. 값이 일치하는 case문의 body를 실행한다. 일치하는 case가 없으면 default 문이 존재할 시, default 문의 코드를 실행한다.
  3. body가 실행되고 break문을 만나거나 switch문이 끝나면 코드의 실행이 멈춘다.
  4. 참고로 case안에 break가 없으면 조건과 일치하지 않아도 하위의 case문들을 모두 실행한다. 따라서, break 문은 꼭 쓰는 것이 좋다.

switch와 case 문의 조건에는 변수 뿐만아니라 어떤 표현식이든 올 수 있다.


반복문(Loop)

while 반복문

condition이 truthy이면 body가 실행된다.

while (condition) {
  // ...
}

do while 반복문

본문이 먼저 한 번 실행되고, 조건이 truthy이면 본문이 계속 실행된다.

do {
  // body
} while (condition);

for 반복문

  1. 가장 먼저 begin이 실행된다.
  2. condition이 truthy이면 body가 실행된다.
  3. 그 후 step을 실행한다.
  4. 2~3을 반복한다.
for (begin; condition; step) {
  // body
}

begin과 condition, step은 생략될 수 있다.

let i = 0; // i를 선언하고 값도 할당하였습니다.

// begin 생략
for (; i < 3; i++) { // 'begin'이 필요하지 않기 때문에 생략하였습니다.
  alert( i ); // 0, 1, 2
}

// begin과 step 생략
let i = 0;

for (; i < 3;) {
  alert( i++ );
}


// 모두 생략 => 무한 반복문
for (;;) {
  // 끊임 없이 본문이 실행됩니다.
}

반복문 빠져나오기

대개는 반복문의 조건이 falsy가 되면 반복문이 종료된다.

이외에도 break 지시자를 사용해 원하는 때에 반복문을 빠져나올 수 있다.

let sum = 0;

while (true) {

  let value = +prompt("숫자를 입력하세요.", '');

  if (!value) break; // (*)

  sum += value;

}
alert( '합계: ' + sum );

다음 반복으로 넘어가기

continue 지시자를 사용해 현재 실행 중인 반복을 멈추고, 조건이 truthy일 때 다음 반복을 강제로 실행시킬 수 있다.

for (let i = 0; i < 10; i++) {

  // 조건이 참이라면 남아있는 본문은 실행되지 않습니다.
  if (i % 2 == 0) continue;

  alert(i); // 1, 3, 5, 7, 9가 차례대로 출력됨
}

break / continue 지시자와 라벨을 사용해서 반복문을 빠져 나오거나 넘어가기

중첩된 반복문에서 한 번에 빠져나오고 싶을 때가 있다.

이때는 반복문 앞에 라벨을 사용한다.

labelName: for (...) {
  ...
}
  
// 예시
outer: for (let i = 0; i < 3; i++) {

  for (let j = 0; j < 3; j++) {

    let input = prompt(`(${i},${j})의 값`, '');

    // 사용자가 아무것도 입력하지 않거나 Cancel 버튼을 누르면 두 반복문 모두를 빠져나옵니다.
    if (!input) break outer; // (*)

    // 입력받은 값을 가지고 무언가를 함
  }
}
alert('완료!');

마찬가지로 continue 지시자에 사용하면 해당 레이블이 지정된 반복문의 다음 반복을 실행한다.


함수(function)

함수를 이용해 중복 작성 없이 유사한 동작을 하는 코드를 여러 번 호출할 수 있다.

함수 선언(함수 선언문)과 호출

함수는 function 키워드, 함수 이름, 매개변수들(생략가능), 함수 본문으로 구성된다.

정의된 함수 이름 옆에 괄호를 붙여 호출한다.

//함수 선언
function funcName(param1, param2, ... paramN) {
  // body ...
}

// 함수 호출
funcName(); 

지역 변수(local variable) or 내부 변수(inner variable)

함수 내에서 선언한 변수로, 함수 안에서만 접근할 수 있다.

function showMessage() {
  let message = "안녕하세요!"; // 지역 변수

  alert( message );
}

showMessage(); // 안녕하세요!

alert( message ); // ReferenceError: message is not defined (message는 함수 내 지역 변수이기 때문에 에러가 발생합니다.)

전역 변수(global variable) or 외부 변수(outer variable)

함수 외부에서 선언된 변수로, 함수 내부에서 외부 변수에 접근하거나 수정할 수 있다.

let userName = 'John';

function showMessage() {
  userName = "Bob"; // (1) 외부 변수를 수정함

  let message = 'Hello, ' + userName;
  alert(message);
}

alert( userName ); // 함수 호출 전이므로 John 이 출력됨

showMessage();

alert( userName ); // 함수에 의해 Bob 으로 값이 바뀜

다만 함수 내부에 외부 변수와 동일한 이름을 가진 지역변수가 선언되었다면, 해당 지역변수는 외부 변수를 가린다.

let userName = 'John';

function showMessage() {
  let userName = "Bob"; // 같은 이름을 가진 지역 변수를 선언합니다.

  let message = 'Hello, ' + userName; // Bob
  alert(message);
}

// 함수는 내부 변수인 userName만 사용합니다,
showMessage();

alert( userName ); // 함수는 외부 변수에 접근하지 않습니다. 따라서 값이 변경되지 않고, John이 출력됩니다.

매개변수(parameter, 인자)

매개변수를 이용해 임의의 데이터를 함수 안에 전달할 수 있다.

function showMessage(from, text) { // 인자: from, text
  alert(from + ': ' + text);
}

showMessage('Ann', 'Hello!'); // Ann: Hello! (*)
showMessage('Ann', "What's up?"); // Ann: What's up? (**)

함수 호출 시에 각각의 매개변수 위치에 맞춰 인수(argument)를 전달하면 된다.

전달된 값은 매개변수에 복사되고, 매개변수는 지역변수처럼 사용된다.

매개변수가 있는 함수 호출시에 인수를 전달하지 않으면, 해당 매개변수는 undefined가 된다.

이 때, 매개변수에는 default 값을 설정해줄 수 있다.

function showMessage(from, text = "no text given") {
  alert( from + ": " + text );
}

showMessage("Ann"); // Ann: no text given

반환값(return value)

함수 선언시에 return 지시자를 사용해 함수를 호출했을 때, 호출한 곳에 특정 값을 반환하게 할 수 있다.

function sum(a, b) {
  return a + b;
}

let result = sum(1, 2);
alert( result ); // 3

return문은 함수 내 어디서든 사용할 수 있다.

return을 만나게 되면 함수 실행은 즉시 중단되고, 함수를 호출한 곳에 값을 반환한다.

return 문이 없거나 return만 있는 함수는 undefined를 반환한다.

함수 선언시 암묵적인 규칙

  1. 함수는 동작 하나만 담당해야 한다.
  2. 이름만 보고도 어떤 동작을 하는지 알 수 있는 코드를 자기 설명적(self-describing) 코드라하고, 함수는 자기 설명적 코드여야한다. 즉, 함수 이름은 함수가 어떤 동작을 하는지 표현해야한다.

함수를 선언하는 또 다른 방법 : 함수 표현식(function expression)

자바스크립트는 함수를 특별한 종류의 값으로 취급한다.

이러한 특성에 의해, 함수 선언문 이외에도 함수 표현식을 사용해 함수를 만들 수 있다.

변수를 선언하고 할당하는 것처럼, 함수를 생성하고 변수에 할당할 수 있다.

// 함수 선언문
function sayHi() {
  alert( "Hello" );
}

// 함수 표현식
let sayHi = function() {
  alert( "Hello" );
};

위의 어떤 방식으로 함수를 생성했든, 함수는 값으로 취급되고 변수에 할당할 수 있다. 따라서, 변수를 다른 변수에 할당하는 것처럼 함수도 다른 변수에 할당할 수 있다.

function sayHi() {   // (1) 함수 생성
  alert( "Hello" );
}

let func = sayHi;    // (2) 함수 복사

func(); // Hello     // (3) 복사한 함수를 실행(정상적으로 실행됩니다)!
sayHi(); // Hello    //     본래 함수도 정상적으로 실행됩니다.

콜백함수(callback function)

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

function showOk() {
  alert( "동의하셨습니다." );
}

function showCancel() {
  alert( "취소 버튼을 누르셨습니다." );
}

// 사용법: 함수 showOk와 showCancel가 ask 함수의 인수로 전달됨
ask("동의하십니까?", showOk, showCancel);

위 예시에서 함수 ask의 인수, showOk와 showCacncel을 콜백함수 또는 콜백이라 한다.

쉽게 말해 어떤 함수를 함수의 인수로 전달하고, 인수로 전달한 그 함수를 나중에 호출(called back)하는 것이 콜백 함수의 개념이다.

익명함수(anonymous function)

function ask(question, yes, no) {
  if (confirm(question)) yes()
  else no();
}

ask(
  "동의하십니까?",
  function() { alert("동의하셨습니다."); },
  function() { alert("취소 버튼을 누르셨습니다."); }
);

위의 예시에서 함수 ask의 인수에 이름이 없이 선언된 함수를 익명함수라 한다.

익명 함수는 변수에 할당된 것이 아니므로, 함수 ask 내부에서만 접근할 수 있다.

함수 표현식과 함수 선언문 차이

  1. 문법적 차이

  2. 자바스크립트 엔진이 언제 함수를 생성하는지 차이

  • 함수 표현식은 실제 실행 흐름이 해당 함수에 도달했을 때 함수를 생성한다. 따라서, 실행 흐름이 함수에 도달했을 때부터 해당 함수를 사용할 수 있다.
  • 함수 선언문은 함수 선언문이 정의되기 전에도 호출할 수 있다. 쉽게 말해 함수 호출이 함수 선언보다 앞서도 함수를 사용할 수 있다. 이게 가능한 이유는 자바스크립트의 내부 알고리즘 때문이다. 자바스크립트는 스크립트를 실행하기 전 준비단계에서 전역에 선언된 함수 선언문을 찾고, 해당 함수를 생성한다. 스크립트는 함수 선언문이 모두 처리된 이후에서야 실행된다. 따라서 스크립트 어디서든 함수 선언문으로 선언한 함수에 접근할 수 있다.
//  함수 표현식
sayHi("John"); // error!

let sayHi = function(name) {  // (*) 마술은 일어나지 않습니다.
  alert( `Hello, ${name}` );
};

// 함수 선언문
sayHi("John"); // Hello, John

function sayHi(name) {
  alert( `Hello, ${name}` );
}
  1. 스코프(scope)
    strict mode에서 함수 선언문이 어떤 코드 블록 내에 위치하면, 선언된 함수는 해당 코드 블록 내에서만 접근할 수 있다.
let age = prompt("나이를 알려주세요.", 18);

// 조건에 따라 함수를 선언함
if (age < 18) {

  function welcome() {
    alert("안녕!");
  }

} else {

  function welcome() {
    alert("안녕하세요!");
  }

}

// 함수를 나중에 호출합니다.
welcome(); // Error: welcome is not defined

이를 해결하기 위해서는 함수 표현식을 쓰면 된다.

let age = prompt("나이를 알려주세요.", 18);

let welcome;

if (age < 18) {

  welcome = function() {
    alert("안녕!");
  };

} else {

  welcome = function() {
    alert("안녕하세요!");
  };

}

welcome(); // 제대로 동작합니다.

화살표 함수(arrow function)

함수 표현식보다 단순하고 간결한 문법으로 함수를 만들 수 있는 방법이다.

let func = (arg1, arg2, ...argN) => expression

인수가 없다면 괄호를 비워 놓으면 된다.

let func = () => expression

함수 본문이 여러 줄이라면 중괄호 안에 함수 본문을 넣고, return 지시자를 사용해 명시적으로 결과값을 반환해주어야 한다.

let sum = (a, b) => {  // 중괄호는 본문 여러 줄로 구성되어 있음을 알려줍니다.
  let result = a + b;
  return result; // 중괄호를 사용했다면, return 지시자로 결괏값을 반환해주어야 합니다.
};

alert( sum(1, 2) ); // 3

참고 문헌

https://ko.javascript.info/first-steps

profile
더깊이

0개의 댓글