즉시 실행 화살표 함수 - jeugsi silhaeng hwasalpyo hamsu

함수 선언 호이스팅(Function declaration hoisting)

: 함수는 호출 먼저 하고, 함수 정의는 나중에 정의하는..

즉시 실행 함수 (Immediately-invoked function expression)

즉시 실행 함수의 기본 형태는 아래와 같습니다.

(function () {
// statements
})()

함수 표현(Function expression)은 함수를 정의하고, 변수에 함수를 저장하고 실행하는 과정을 거칩니다. 하지만 즉시 실행 함수는 함수를 정의하고 바로 실행하여 이러한 과정을 거치지 않는 특징이 있습니다. 함수를 정의하자마자 바로 호출하는 것을 즉시 실행 함수라고 이해하면 편할 것 같습니다.

Immediately-invoked function expression 영어를 해석하면 즉시-호출 함수 표현 입니다. 즉시 실행 함수(IIFE)는 함수 표현(function expression)과 같이 익명 함수 표현, 기명 함수 표현으로 할 수 있습니다.

출처: https://beomy.tistory.com/9 [beomy]

변수에 즉시 실행 함수 저장

즉시 실행 함수도 함수이기 때문에, 변수에 즉시 실행 함수 저장이 가능합니다. 예를 들어 보겠습니다.

(mySquare = function (x) {
console.log(x*x);
})(2);
mySquare(3);

변수에 즉시 실행 함수 저장

함수를 mySquare에 저장하고 이 함수를 바로 실행하게 됩니다. mySquare는 즉시 실행 함수를 저장하고 있기 때문에 재호출이 가능하게 됩니다.

마찬가지로 즉시 실행 함수도 함수이기 때문에, 변수에 즉시 실행 함수의 리턴 값 저장도 가능합니다.

var mySquare = (function (x) {
return x*x;
})(2);
console.log(mySquare)

변수에 즉시실행함수 리턴값 저장

위의 두가지는 형태가 유사하지만 엄연히 다른 기능입니다. 괄호의 위치에 주의가 필요할 것 같습니다.

출처: https://beomy.tistory.com/9 [beomy]

2. 즉시 실행 함수를 사용하는 이유

초기화

즉시 실행 함수는 한 번의 실행만 필요로 하는 초기화 코드 부분에 많이 사용됩니다.

그렇다면 왜 초기화 코드 부분에 많이 사용 할까요? 변수를 전역(global scope)으로 선언하는 것을 피하기 위해서 입니다. 전역에 변수를 추가하지 않아도 되기 때문에 코드 충돌 없이 구현 할 수 있어, 플러그인이나 라이브러리 등을 만들 때 많이 사용됩니다.

예를 하나 들어보겠습니다.

var initText;(function (number) {
var textList = ["is Odd Text", "is Even Text"];
if (number % 2 == 0) {
initText = textList[1];
} else {
initText = textList[0];
}
})(5);
console.log(initText);
console.log(textList);

즉시실행함수 이용한 초기화

전역에 textList가 저장되지 않고, initText만 초기화 된 것을 확인 할 수 있습니다. 또한 textList는 지역 변수로, 전역 변수와 충돌없이 초기화 할 수 있게 됩니다.

출처: https://beomy.tistory.com/9 [beomy]

이 글을 작성하게 된 계기

습관적으로 사용하는 Arrow function은 과연 어떤 장점들을 가지고 있는지 한번 정리해 보고 싶었습니다.

기존 함수 선언을 화살표(=>)를 통해 선언해 줍니다.

(param1, param2, , paramN) => expression
                        //  => { return expression } 과 동일한 의미입니다.
(param1 = value1, param2, param3 = value2) => { statements }

// 즉시 실행 함수는 
(function(){
    //expression;
}());

(() => {
    //expression
})()

Arrow funciton의 장점은 무엇일까?

  1. 짧은 함수를 작성할 수 있게 됩니다. 밑 예제같은 콜백함수를 작성할 때 간결하겠네요.

let a = ["a","b","c","d"];
let b = a.map(function(s){return s.length});
let c = a.map((s)=>s.length());
let d = a.filter((item, index) => index % 2);

  1. 기존 자바스크립트에서 this는 dynamic scoping 이 되었는데 이 경우 lexical scoping을 사용하게 된다. 고로 따로 binding을 사용하지 않아도 된다. 정리하면 자신만의 this를 생성하지 않고 자신을 포함하고 있는 context의 this를 이어 받습니다.
    • ES5 의 bind 예를 살펴 보면

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  return arr.map(function (x) {
    return this.prefix + ' ' + x;;
  }.bind(this)); // this: Prefixer 생성자 함수의 인스턴스
};

var pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

  • 위 코드를 ES6의 Arrow function을 사용하면

function Prefixer(prefix) {
  this.prefix = prefix;
}

Prefixer.prototype.prefixArray = function (arr) {
  return arr.map(x => `${this.prefix}  ${x}`);
};

const pre = new Prefixer('Hi');
console.log(pre.prefixArray(['Lee', 'Kim']));

훨씬 직관적이고 간결하게 쓸 수 있다.

lexical scope란?

렉시컬 스코프란 소스코드가 작성된 그 문맥에 결정된다고 합니다. 현대 프로그래밍 대부분 언어는 렉시컬 스코프 규칙을 따르고 있다고 합니다. 가장 많이 언급되는 예제라고 하는데

var x = 'global';
function foo(){
    var x = 'local';
    bar();
}
function bar(){
    console.log(x);
}
foo(); // global
bar(); // global

렉시컬 환경의 대응표(환경 레코드)에서 변수를 찾아보고, 없다면 바깥 렉시컬 환경을 참조하여 찾아보는 식으로 중첩 스코프가 가능해진다고 합니다.

Arrow function은 어느곳에 사용하면 안될까?

  1. 번외이지만.. 가장 먼저 IE환경에서 아직 제공하지 않습니다. 쓰려면 babel과!
  2. 메소드

const obj = {
    name: "han",
    hi: () => console.log(`Hi ${this.name}`)
};
obj.hi(); // Hi undefined

위 bind의 설명했을 때와 같이 이 경우 호출한 객체에 바인딩되는 것이 아닌 전역객체에 바인딩 된다. 이때는 이렇게 축약표현을 작성하는 것이 좋다고 합니다.

const obj = {
    name: "han",
    hi(){ 
        console.log(`Hi ${this.name}`);
    }
};
obj.hi(); // Hi undefined

  1. prototype 이 때는 메소드가 아닌 일반 함수가 할당 된다. 고로 기존처럼 작성해야 한다.

const obj = {
  name: 'Lee',
};
Object.prototype.hi = () => console.log(`Hi ${this.name}`);
obj.hi(); // Hi undefined

// 이게 옳은 표현이라고 한다.
Object.prototype.sayHi = function() {
  console.log(`Hi ${this.name}`);
};

  1. 생성자 생성자 함수는 prototype 프로퍼티를 갖지만 arrow function은 prototype 프로퍼티를 갖지 않는다고 합니다. 고로 사용할 수 없다!

  2. addEventListener 이 경우 this가 상위 컨택스트를 가리 킨다고 합니다. 고로 이전처럼 function(){}으로 사용하는 것이 옳은 표현입니다.

button.addEventListener('click', () => {
  console.log(this === window); // => true
  console.log(this === button); // => false
});

button.addEventListener('click', function() {
  console.log(this === window); // => false
  console.log(this === button); // => true
});

결론은?

편리하지만 용도에 맞춰서 작성하는 것이 좋을 것 같다. 그리고 빠르게 변화하는 사항이니 이후에 어떻게 변화되는지 계속되서 주목할 필요가 있는 것 같습니다.

참조

  • 링크, MDN.화살표 함수란?
  • 링크, 언제 화살표 함수를 사용하면 안될까?
  • 링크, 자바스크립트의 스코프와 클로저
  • 링크, arrow function