JavaScript - 함수의 정의 방식이 4가지나 있다고?!

김민재·2021년 7월 30일
1

TIL, Deep Javascript

목록 보기
9/22
post-thumbnail

*🔐Study Keyword :

함수를 정의하는 4가지 방식 중 🔑함수선언문과 🔑함수 🔑생성자 함수 🔑화살표 함수에 대해서

함수 정의

  • WHAT IS❓ 함수 정의함수를 호출하기 이전에 인수를 전달받을 매개변수와 실행 문들 그리고 반환값을 지정하는 것을 말한다.
  • 정의된 함수는 자바스크립트 엔진에 의해 평가되어
    함수 객체가 된다.

함수를 정의하는 4가지 방식

  • 모두 함수를 정의하는 면에서 동일하지만 미묘하지만 중요한 차이가 있으니 그 차이에 대해서 잘 알아야한다...!

1. 함수 선언문

<script>
function add(x,y){
  return x+y;
}
</script>

2. 함수 표현식

<script>
const add = function(){
  return x+y;
}
</script>

3. Function 생성자 함수

<script>
const add = new Function('x', 'y', 'return x+y');
</script>

4. 화살표 함수

<script>
const add = (x, y) => x+y;
</script>

- 1. 함수 선언문

  • 함수 선언문은 함수 리터럴과 형태가 동일하지만
    함수 선언문은 함수 이름을 생략할 수 없다.
  • 함수 선언문은 표현식이 아닌 문이다.
<script>
//함수 선언문, 함수명 생략할 수 없다는 것에 주의!
function add(x,y){
  return x+y;
}
//함수 참조
console.dir(add)// f add(x, y) , dir은 함수의 객체의 프로퍼티까지 출력해주는 명령어
//함수 호출
console.log(add(2, 5))// 7
</script>

-함수 선언문의 <예시1>

Q. 함수 선언문은 표현식이 아닌 문인데 변수에 할당이 되는 것처럼 동작한다?

<script>
//함수 선언문, 변수에 할당하는 것처럼 보인다?!
cosnt add = function add(x,y){
  return x+y;
}
//함수 호출
console.log(add(2, 5))// 7
</script>

A. 이유는 자바스크립트 엔진이 코드의 문맥에 따라 기명 함수 리터럴을 두 가지의 경우로 나눠서 해석한다.
1. 표현식이 아닌 문인 함수 선언문으로 해석하는 경우
2. 표현식인 문인 함수 리터럴 표현식으로 해석하는 경우

<script>
//함수 이름이 있는 기명 함수 리터럴은 해석될 가능성이 2가지
// 1. 함수 리터럴을 단독으로 사용 => 함수 선언문으로 해석
function funcDeclare(){
  console.log('나는 함수 선언문으로 해석'); 	
}
funcDeclare();
//2. 함수 리터럴 값을 평가되는 문맥(변수 할당) => 함수 리터럴 표현식으로 해석
// 함수 리터럴에선 함수 이름 생략 가능
(function fucLiteral() { console.log('나는 함수 리터럴 표현식으로 해석')}; );
</script>
  1. 기명 함수함수 리터럴을 단독으로 사용하면 함수 선언문으로 해석하고,
  2. 함수 리털럴이 값으로 평가되어야 하는 문맥(함수 리터럴을 변수에 할당하거나 피연산자로 사용)에선함수 리터럴 표현식으로 해석한다.

함수 선언문의 <예시2>

Q. 함수 선언문과 함수 리터럴 표현식에는 어떤 차이가 존재하할까?

<script>
//1. 기명함수로 리터럴을 단독으로 사용 => 함수 선언문
function foo(){console.log('foo')};
foo(); // foo
//2. 함수 리터럴 값을 평가되는 문맥(피연산자로 사용) => 함수 리터럴 표현식으로 해석
(function bar(){console.log('bar')};);
bar(); // 참조 오류발생 
</script>

A. 모두 함수가 생성되는 건 동일하지만 바로 호출의 차이가 발생한다. 위코드를 가지고 설명하겠다.
함수 선언문으로 생성된 함수 foo()는 호출할 수 있으나
함수 리터럴 표현식으로 생성된 함수 bar()는 호출 할 수 없다.
-함수 리터럴의 함수의 이름은 오직 함수 몸체 내에서만 참조할 수 있는 식별자이다.
-> 이는 현재 함수 bar를 가리키는 식별자가 없는 상태이기에 bar 함수를 호출 할 수 없다.

  • Q. 🙋‍♂️ : 함수 리터럴의 함수 이름이 오직 함수 몸체 내에서만 참조한고오...?
    🤷‍♂️ : 그럼 함수 선언문으로 정의된 함수 foo는 어떻게 이름으로 호출 한거영..❓❓❓❓
  • A. 🙆‍♂️ : 여기에 호출한 함수 foo는 자바스크립트에 엔진이 암묵적으로 생성한 식별자이기 때문에 가능다구...❕❕❕❕
  • 자바스크립트 엔진은 함수 선언문을 해석해 함수 객체를 생성하고 함수 이름과 동일한 이름의 식별자를 만든다.
  • 이때 함수 이름은 함수 몸체 내부에서만 유효한 식별자이므로 함수 객체를 참조하기 위해서는 함수 객체를 가리키는 식별자가 필요하다.
  • 따라서 자바스크립트 엔진은 생성된 함수를 호출하기 위해 함수 이름과 동일한 이름의 식별자를 '암묵적으로 생성하고 거기에 '함수 객체를 할당'한다.
  • 따라서 함수 선언문의 의사코드는 다음과 같아진다.
<script>
//함수 선언문 
cosnt add = function add(x,y){//함수 객체를 참조하기 위해 함수이름과 같은 식별자 생성 후 함수 객체를 할당
  return x+y;
}
//함수 호출은 함수 이름이 아닌 함수 객체를 가리키는 식별자자라는 것의 주의!!
console.log(add(2, 5))// 7
</script>

-함수는 함수 이름으로 호출하는 것이 아니라
함수 객체를 가리키는 식별자로 호출한다.
->자바스크립트 엔진은 함수 선언문함수 표현식으로 변환해 함수 객체를 생성한다고 생각할 수 있다.
하지만 선언문과 표현식이 정확히 동일하게 동작하지는 않는다.


- 2. 함수 표현식

  • 자바스크립트의 함수는 값처럼 변수에 할당할 수도 있고 프로퍼티 값이 될 수도 있으며 배열의 요소가 될 수 있다.
  • 이처럼 값의 성질을 갖는 객체를 '일급객체'라하는데 자바스크립트의 함수가 바로 '일급 객체'이다.
  • 값처럼 자유롭게 사용할 수 있는 일급객체인 함수는 함수 리터럴로 생성한 함수 객체를 변수에 할당할 수 있는데 이러한 함수 정의 방식을 함수 표현식이라 부른다.
<script>
//함수 선언문
function add(x,y){
  return x+y;
}
console.log(add(2, 5))// 7
//함수 선언문으로 정의한 add함수를 함수 표현식으로 바꾸어 정의
const add = function (x, y){
  return x+y;
}
//함수 호출
console.log(add(2, 5))// 7
</script>

-함수 표현식 <예시>

Q. 함수 표현식의 함수 리터럴에 함수 이름을 붙일 수도 생략할 수 있다고?

<script>
//함수 이름이 있는 기명 함수 표현식
const add = function foo(x,y){
  return x+y;
}
// 함수 객체를 가리키는 식별자로 호출해야한다.
console.log(add(2, 5))// 7
//함수 이름이 없는 익명 함수 표현식
const add = function (x, y){
  return x+y;
}
//함수 호출
console.log(add(2, 5))// 7
</script>

A. 함수 표현식은 익명 함수 표현식기명함수 표현식으로 나뉜다.

  • 함수 표현식의 함수 리터럴의 함수 이름을 생략한 익명 함수 표현식사용하는 것이 일반적이다.
  • 익명 함수 표현식은 함수에 식별자가 주어지지 않고 기명함수 표현식은 함수의 식별자가 존재한다.

+) 함수 선언문 VS 함수 표현식 미묘한 차이

  • 함수 생성 시점과 호이스팅에서 미묘한 차이가 있음을 인지!
  • 함수 선언문으로 정의한 함수와 함수 표현식으로 정의한 함수의 생성시점이 다르다.
  • 함수 선언문 - 표현식이 아닌 문으로 호이스팅의 영향을 받아 어디서든 호출이된다.
  • 함수 표현식 - 표현식인 문으로 호이스팅에 영향을 받지 않아 함수 코드에 도달해야 생성되고 호출이 된다.
<script>
console.dir(sayHi);//참조 가능
console.dir(sayHello);//참조 불가능
sayHi()//호출 가능
sayHello()//호출 불가능
//함수 선언문으로 만든 함수
sayHi() // 호이스팅 -> 호출 가능
function sayHi(){
	console.log('hi');
}
//함수 표현식으로 만든 함수
const sayHello() = function sayHi(){ // 해당 코드에 도달해야 생성되고 
 	console.log('hi');// 코드 도달 후 사용할 수 있다.
}
// 여기선 호출과 참조가 가능하다
</script>

-함수 선언문

  • 모든 선언문이 그렇듯 함수 선언문 역시 1>런타임 이전에 먼저 실행되어 함수 객체를 생성하고 함수 이름과 동일한 식별자에 할당까지 완료된 상태이다.
  • 따라서 함수 선언문으로 정의한 함수는 선언문 이전에도
    2>함수 호이스팅
    에 의해 호출과 참조가 가능하다.
  • 이렇게 함수 선언문코드의 선두로 끌어 올려진 것처럼 동작하는 것, '함수 호이스팅'이라고 한다.

-함수 표현식

  • 함수 표현식은 변수 선언문과 변수 할당문을 한 번에 기술한 축약 표현과 동일하게 동작한다.
  • 변수 할당문의 값은 할당문이 실행되는 시점인 런타임에 평가되듯이 함수 표현식의 함수리터럴도 1>할당문이 시행되는 시점에 평가되어 함수 객체가 된다.
  • 따라서 함수 표현식으로 함수를 정의하면 함수 호이스팅이 발생하는 것이 아니라 2>변수 호이스팅 발생한다

- 3. 생성자 함수

  • WHAT IS❓ 생성자 함수객체를 생성하는 함수를 말한다.
    객체를 생성하는 방식에 객체 리터럴 방식 이외에 다양한 방법이 있다.

HOW TO USE❕❓ - 자바스크립트가 기본 제공하는 빌트인 함수인 Function 생성자 함수에 매개변수 목록과 함수 몸체를 문자열로 전달하면서 new연산자(없어도 가능)와 함께 호출하면 함수객체를 생성해서 반환한다.

<script>
//생성자 함수
const add = new Function('x', 'y', 'return x + y');
//함수 호출
console.log(add(2, 5))// 7
</script>

-생성자 함수의 <예시>

  • Function 생성자 함수로 생성하는 함수클로저를 생성하지 않는 등 함수 선언문이나 표현식으로 생성한 함수와 다르게 동작한다.
<script>
//함수 선언문 시 클로저
const add1 =(function (){
  const a = 10;
  return function (x, y){
    return x + y;
  };
}());
console.log(add1(1,3)) // 13
//생성자 함수시 클로저
const add2 =(function (){
  const a = 10;
  return new Function('x', 'y', 'return x+y');
}());
console.log(add2(1,3)) // 변수 a참조 오류?
</script>

- 4. 화살표 함수

  • WHAT IS❓ 화살표 함수함수 선언시 함수 표현과 내부 동작을 간략화 한 것이다.
  • HOW TO USE❕❓ 화살표 함수는 함상 익명함수로 정의한다.
  • 화살표 함수function 키워드 대신 화살표를 사용해 더 간략한 방법으로 함수를 선언한다.
<script>
//화살펴ㅛ 함수
const add = (x, y) => x + y;
//함수 호출
console.log(add(2, 5))// 7
</script>
  • 생성자함수로는 화살표함수를 사용할 수 없고
    기존의 함수와 this 바인딩 방식이 다르고 prototype 프로퍼티가 없으며 arguments 객체를 생성하지 않는다.

*💡conclusion

  • 함수 선언문함수 표현식의 미묘한 차이, 실행시점과 호이스팅에 대해서 잘 알아두잡!
  • 함수 호이스팅은 함수를 호출하기 전에 반드시 함수를 선언하는 규칙을 무시하므로 함수 선언문 대신 함수 표현식을 주로 이용하도록하장!

#📑Study Source

  1. 책 - 딥다이브 자바스크립트
profile
자기 신뢰의 힘을 믿고 실천하는 개발자가 되고자합니다.

0개의 댓글