javaScript/jsDeepDive

함수 리터럴에 대해서

부엉이사장 2023. 5. 16. 22:10

# 먼저 리터럴에 대해서 다시 살펴보자.
https://jacobowl.tistory.com/137

값(value), 리터럴(literal), 표현식(expression), 문(statement)

# 리터럴(literal) 리터럴은 사람이 알아보는 기호로 적은 표기법을 말한다. 이전 '메모리에 저장되는 기본구조' 포스팅에서 컴퓨터는 데이터를 2진법으로 저장한다고 했었다. 메모리에 저장되는

jacobowl.tistory.com

 
위 포스팅에서 리터럴에 대해서 설명을 했었다.
리터럴이란 우리가 직접 vs코드에 치는 사람이 알아볼수 있는 코드이고, 
이 리터럴이 자바스크립트엔진에의해 평가되어 메모리에 값으로 저장된다.
리터럴은 표현식에 포함된다.
 
 
 
# 함수는 객체다
https://jacobowl.tistory.com/170

primitive타입, object타입 mutable(변경가능함)

원시타입은 흔히 우리가 변수에 할당하는 스트링 넘버 등이 있고, 객체타입은 말그대로 객체타입이다. 어레이, 객체, 함수등이 있다. 원시타입과 객체타입은 근본적으로 메모리접근,참조방법에

jacobowl.tistory.com

위 포스팅 제일 아래 번외편에서 함수는 객체라는걸 간단히 실험해보았다.

const obj = { dog1: "muzzi" };
const fuc = function () {};

console.dir(obj);
console.dir(fuc);

위 코드에서는 브라우저 환경에서 console.dir을 쳐서 일반 객체리터럴로 생성한 객체와
함수리터럴로 생성한 함수객체의 프로퍼티를 각각 확인할 수 있다.
 

위와같이 일반리터럴로 생성한 객체와 함수리터럴로 생성된 함수객체는 서로 프로퍼티가 다르다.
이번 포스팅에선 함수는 이렇게 프로퍼티를 갖는 객체라는점이 중요하다.
위에 함수와 일반객체가 갖는 프로퍼티 프로토타입등이 다른점은 프로퍼티에 관한 포스팅으로 소개할예정이다.
 
참고로 원시값을 console.dir로 쳐보면 그냥 원시값이 나온다

console.dir("hello"); // hello 출력
console.dir(1); // 1출력

 
 
 
# 함수리터럴

function fuc() {
  return "뿩!";
}

 
위 함수리터럴은 자바스크립트 엔진에 의해 해석되어 함수객체가된다.
따라서 함수리터럴은 표현식인 문이고 자바스크립트엔진에 의해 해석되어 이 함수객체가 메모리가 값으로써 저장된다.
함수객체는

이런 프로퍼티, 프로토타입을 가진 객체이다.
 
 
 
 
# 함수 리터럴은 함수선언문이랑 똑같이 생겼네?
그렇다면 의문이 생길것이다. 위에 함수리터럴은 함수선언문인데요?
이 말은 반은 맞고 반은 틀리다.
 
브라우저 개발자도구 콘솔에서 함수리터럴을 쳐보았다.

이럴수가? 분명 함수리터럴은 표현식이라고 했잖아? 왜 개발자도구에서 undefined가 뜨는거야?
개발자도구에서 적은 코드가 표현식이 아니면 undefined가 뜬다면서?
 
그렇다 저 함수 리터럴은 표현식이 아닌 문이다. (응? 당황..)
 
 
 
 
# 콘솔로 함수리터럴(함수선언문)을 쳐보자.
먼저 아래 코드를 보자

console.log(let value =123;)

표현식이 아닌 문인 변수선언문을 콘솔로치면 이렇게 되는데 이는 syntax에러를 발생시킨다.
콘솔로그로 참조할수있는건 메모리에 '값'으로 저장된 '표현식'이어야 한다.
리터럴자체가 표현식이기때문에 리터럴을 콘솔로 참조해보면 에러가 안뜨지만,
위에 변수선언문처럼 표현식이 아닌 문을 콘솔로치면 에러가 뜨게된다.
 
그래서 함수리터럴을 콘솔로 쳐보았다.

console.log(function fuc() {
  return "뿩!";
});

결과는?

nodejs환경에서
브라우저 환경에서

결과는 위 사진과 같이 뜬다. 둘다 함수라는결과를 배출한다. 
즉 저 함수리터럴(표현식이 아닌 문인 함수선언문과 똑같이생겼지만..)은 표현식이다.
 
 
 
# 그래서 말하자고 하는게 뭔데? 

function fuc() {
  return "뿩!";
}

결론부터 말하면, 자바스크립트 엔진이 위 코드를 '함수선언문'으로 평가하는 경우가 있고, '리터럴 표현식'으로 평가하는 경우로 나뉘어진다는 것이다.
 
- 함수 선언문으로 평가되는경우
표현식이나 표현식이아닌문이 둘다 위치할 수 있는곳에서는 함수리터럴이 존재하면 함수 선언문으로 동작한다.

function fuc() {
  return "뿩!";
}

{
  function fuc() {
    return "뿩!";
  }
}

if (true) {
  function fuc() {
    return "뿩!";
  }
}

for (let i = 0; i < 1; i++) {
  function fuc() {
    return "뿩!";
  }
}

위에 코드처럼 전체 코드나 코드블럭에서 함수리터럴이 존재하면 이는 함수 선언문으로 해석한다.
 
- 함수리터럴로 평가하는 경우
'표현식이 있어야만 하는곳'에서는 함수리터럴로 평가된다.

const fuc = function fuc() {
  return "뿩!";
};

console.log(
  function fuc() {
    return "뿩!";
  } + 1
);

(function fuc() {
  return "뿩!";
});

 
'표현식이 있어야만 하는곳'이라는건 즉 '참조할수있는 값'이어야 하는 곳이다. 함수선언문은 함수리터럴이 아니다라는걸 조심하고 혼동하지말자. 리터럴은 표현식이기 때문에 함수리터럴은 참조시 함수객체로 평가된다.
 
 
# 쉽게생각해서
함수객체를 참조하는 표현식에다가 소괄호 '(parameter)' 을 붙이면 함수가 호출invoke, call이 된다고 생각하면 된다.
이를 알면 즉시실행함수, 콜백함수등이 어떻게 작동되는지 보이게된다.
 
- 함수표현식

위 코드에서 fuc이라는 변수(식별자)에 함수리터럴을 할당한거다.이 함수리터럴은 함수객체를 값으로 참조한다.
그래서 fuc()으로 함수를 호출할수 있는거야~
 
- 즉시실행함수

위 코드에선 그룹연산자 ( ) 소괄호에 함수리터럴을 넣으면 그자체가 함수객체를 참조하게되고
거기에 ()을 붙여서 함수를 호출하는거다.
더해서 연산자 우선순위가 그룹연산자가 제일 높기때문에 코드에서 저 함수가 가장 먼저 실행되서
즉시실행함수가 되는것이다 ㅎㅎ
 
 
- 콜백함수

고차함수인 fucc에 콜백으로써 함수리터럴을 넣어주는건 그냥 함수객체 참조하는 함수리터럴을 argument(인수)로 넣어주고 고차함수내에서 함수를 호출하는거다.
ㅇㅋ?
 
 
 
 
# 최종적으로
함수리터럴이 코드상에 있을때 이것이 함수선언문으로 작동하는지, 함수객체자체를 참조하는것인지 정확히 구분을 할 줄 알아야한다~