[JavaScript] 자바스크립트 함수 작성 방법

 

자바스크립트는 ECMA Script(ES)를 기반으로 표준화되었으며, 시간이 흐르면서 프로그래밍 패러다임의 변화에 맞춰 발전해왔다.

ES6이전에는 함수를 선언문과 표현식으로 정의할 수 있었으나, ES6부터는 함수형 프로그래밍 패러다임을 반영해 화살표 함수라는 새로운 방식의 함수 선언이 도입되었다. 이번 포스팅에서는 자바스크립트에서 함수를 작성하는 방법과 이들의 차이점을 알아보고자 한다.

 
 

01. 함수 선언문

function func_name(){
	...
}

function func_name( ) { } 처럼 함수를 선언하고 함수 이름을 호출하는 방법이다.

함수 선언문은 호이스팅이 발생한다.

 

함수 호이스팅, 변수 호이스팅 등 호이스팅과 관련된 내용은 아래 포스팅 링크를 참고하면 된다.

https://itguswjd.tistory.com/206

 

[JavaScript] 호이스팅과 var/let/const 차이

01. JS 변수 선언 방법 : var / let / const자바스크립트에서 사용되는 변수 선언 방식에는 var, let, const 3가지가 있다.var는 ES6이전인 비교적 오래전부터 사용되었지만, ES6 등장 이후 현재는 잘 사용되지

itguswjd.tistory.com

 

 

 

 

02. 함수 표현식

hoisting() // ReferenceError: Cannot access 'hoisting' before initialization

let hoisting = function () {
	console.log('variable is hoisted')
}

함수 표현식은 let 변수명 = function() { }처럼 함수를 변수에 저장하고 변수를 통해 함수를 사용하는 방법이다.

함수 표현식은 변수를 사용하기 전까지 변수에 함수가 할당되지 않으므로, 호이스팅이 발생하지 않는다.

 

💡 익명 함수와 기명 함수

let unnamed = function() {
  console.log('익명 함수');
};

let named = function name() {
  console.log('기명 함수');
};
  • 익명 함수 : 이름이 없는 함수. 일반적으로 함수 표현식에서 사용
  • 기명 함수 : 이름이 있는 함수. 함수 디버깅이나 재귀 호출에 유리

 

함수와 메서드 차이
- 함수 : 독자적으로 존재(클래스, 객체 없이)
- 메서드 : 클래스, 객체 안에서 존재

 

 

 

 

03. 화살표 함수

let arrowFunc = () => {
  console.log('arrow function');
};

화살표 함수는 ES6에서 도입한 함수 정의 방식으로, ( ) => { } 문법을 사용하여 정의한다.

기존 함수 표현식과 비교하여 더 간단한 문법을 제공하며, this, arguments, super, new.target 등의 바인딩을 갖지 않는다.

 

 

#1. 일반 함수 표현식과 화살표 함수 표현식의 this 바인딩 차이

◼︎ 일반 함수 표현식

일반 함수 표현식에서는 동적 바인딩이 발생한다.

동적 바인딩은 함수가 호출될 때 this가 할당되어, 호출된 객체에 따라 this가 가리키는 대상이 결정되는 것을 말한다.

따라서 일반 함수 표현식은 함수가 어디서 호출되었느냐에 따라 this가 참조하는 객체가 달라진다.

var param = 'global param';

let printParam = function() {
  console.log(this.param);  // 호출한 객체의 this를 참조
};

let object = {
  param: 'object param',
  func: printParam
};

object.func();  // "object param" 출력

 

위 코드는 일반 함수 표현식의 동적 바인딩의 예시를 잘 나타내며 다음과 같이 동작한다.

 

  1. 먼저, param 변수가 전역 스코프에 선언되었다. 일반적으로 브라우저 환경에서는 전역 스코프의 변수가 window 객체의 프로퍼티로 등록되며 window.param이 'global param'을 가리킨다.
  2. 다음으로 printParam이 일반 함수 표현식으로 작성되었다. 일반 함수에서 this는 호출한 객체에 바인딩되므로, 이 함수가 호출되는 객체에 따라 this가 가리키는 객체가 달라진다. console.log(this.param)는 함수가 호출될 때 this가 무엇인지에 따라 다른 값을 출력할 것이다.
  3. object 객체는 param속성과 func라는 메서드를 가지고 있다. func는 printParam 함수를 참조하므로, object.func()를 호출하면 printParam이 실행된다. 이때 printParam이 호출될 때 this가 object 객체로 바인딩된다. object.func()를 호출하면, printParam 함수가 실행되고, 이때 this는 object 객체로 바인딩되므로, this.param은 object.param인 'object param'을 참조하는 것이다.
  4. 결과적으로, console.log(this.param)은 'object param'을 출력한다.

 

일반 함수 표현식에서는 this가 함수 호출 시점에 동적으로 바인딩된다. 위 예시에서 printParam 함수는 object.func()로 호출되었기 때문에 this는 object 객체를 가리키며, object.param의 값인 'object param'이 출력되는 것이다. 

 

 

 

 

 

◼︎ 화살표 함수 표현식

화살표 함수 표현식에서는 정적 바인딩이 발생한다.

정적 바인딩은 자신이 정의된 환경에서의 this를 기억하는 것으로, 함수가 정의된 위치에 따라 this가 결정된다.

var param = 'global param';

let printParam = () => {
  console.log(this.param);  // 상위 스코프의 this를 참조 (여기선 window 객체)
};

let object = {
  param: 'object param',
  func: printParam
};

object.func();  // "global param" 출력

 

위 코드는 화살표 함수 표현식의 정적 바인딩의 예시를 잘 나타내며 다음과 같이 동작한다.

 

  1. 먼저, param 변수가 전역 스코프에 선언되었다. 일반적으로 브라우저 환경에서는 전역 스코프의 변수가 window 객체의 프로퍼티로 등록되며 window.param이 'global param'을 가리킨다.
  2. printParam은 화살표 함수로 선언되었다. 화살표 함수는 this가 상위 스코프의 this를 그대로 상속받는다. 위 코드에서 화살표 함수가 선언된 위치의 상위 스코프는 전역 스코프이므로, this는 전역 객체를 가리킨다. 따라서 this.param은 window.param을 참조하게 된다.
  3. object 객체는 param 속성과 func라는 메서드를 가진다. 이때 func는 화살표 함수인 printParam을 참조한다.
  4. 그러나, 화살표 함수는 객체에 상관없이 this를 바인딩하지 않으므로 func()가 호출되어도 this는 object 객체를 가리키지 않는다. 따라서 object.func()가 실행되면 this.param은 전역 스코프의 param으로 해석하기 때문에 'global param'이 출력된다.

 

 

#2. 화살표 함수에서 var / let 차이

화살표 함수에서 전역 변수를 선언할 때, var와 let의 동작이 다르다.

 

◼︎ var

var param = 'global param';

let printParam = () => {
  console.log(this.param);  // "global param" 출력
};

var로 선언된 변수는 전역 객체 속성으로 추가된다.

따라서 this가 전역 객체를 참조할 때 그 값을 사용 가능하다.

 

 

◼︎ let

let param = 'global param';

let printParam = () => {
  console.log(this.param);  // undefined 출력
};

 

let으로 선언된 변수는 전역 객체의 속성이 아니므로 this.param으로 접근할 수 없다.

따라서 위 예시처럼 함수 내에서 this로 let으로 선언된 변수를 접근하려한다면 undefined가 출력되는 결과가 나올 것이다.

 

 

 

 

#3. 일반 함수 표현식과 화살표 함수 표현식의 재선언 가능 여부

◼︎ 일반 함수 표현식

: 재선언 가능

function helloWorld() {
  console.log('h');
}

function helloWorld() {
  console.log('w');
}

helloWorld();  // "w" 출력

 

 

◼︎ 화살표 함수 표현식

  • var로 선언된 화살표 함수 : 재선언 가능
  • let, const로 선언된 화살표 함수 : 재선언 불가
var helloWorld = () => {
  console.log('h');
};

var helloWorld = () => {
  console.log('w');
};

helloWorld();  // "w" 출력

let helloWorld2 = () => {
  console.log('h');
};

let helloWorld2 = () => {
  console.log('w');
};

// SyntaxError: Identifier 'helloWorld2' has already been declared.

 

 

 

 

 

반응형