모던 자바스크립트 Deep Dive 26장 정리 - ES6 함수의 추가 기능

Hyodduru ·2022년 8월 10일
0
post-thumbnail

26.1 함수의 구분

✔️ ES6 이전의 모든 함수는 일반 함수로도 호출할 수도 있고, 생성자 함수로서 호출할 수 있다. (callable & constructor)

var foo = function(){
  return 1;
};

//일반적인 함수로서 호출 
foo(); // 1 

//생성자 함수로서 호출 
new foo(); // foo{}

//메서드로서 호출 
var obj = {foo :foo};
obj.foo(); //1 

🔖 참고)

  • callable : 호출할 수 있는 함수 객체
  • constructor : 인스턴스를 생성할 수 있는 함수 객체
  • non-constructor : 인스턴스를 생성할 수 없는 함수 객체

여기서 발생하는 문제 👉
객체에 바인딩된 함수도 일반 함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수도 있음, 콜백함수도 constructor이기 때문에 불필요한 프로토타입 객체를 생성하는 문제 등

이를 해결하고자 ES6에서는, 함수를 세가지 종류로 구분한다.

  • 일반함수 : constructor, prototype, arguments
  • 메서드 (Method) : super, arguments
  • 화살표 함수(Arrow)

26.2 메서드

ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미한다.
✔️ ES6사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor 이다.
✔️ ES6 메서드는 prototype 프로퍼티가 없고 프로토타입도 생성하지 않음
✔️ ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 갖는다. (super 키워드 사용 가능)

const obj = {
	x : 1,
    // foo는 메서드다.
    foo() { return this.x; }.
    // bar에 바인딩 된 함수는 메서드가 아닌 일반 함수다. 
  	bar : function(){ return this.x; } 
};

console.log(obj.foo()); //1 
console.log(obj.bar()); //1 


new obj.foo(); // TypeError : obj.foo is not a constructor 
new obj.bar(); // bar {} 

obj.foo.hasOwnProperty('prototype'); // false 

✔️ 참고로 표준 빌드인 객체가 제공하는 프로토타입 메서드와 정적 메서드는 모두 non-constructor 이다.

String.prototype.toUppercase.prototype; // undefined 

✔️ ES6 메소드의 super 키워드 예시

const base = {
  name : 'Lee',
  sayHi() {
    return `Hi ${this.name}`;
  }
}

const derived = {
  __proto__ : base,
  sayHi(){
    return `${super.sayHi()}` 
  }
};

console.log(derived.sayHi());// Hi Lee 

26.3 화살표 함수

// 함수 정의 
const multiply = (x, y) => x * y;

// 매개변수 선언 - 소괄호 생략 가능(매개변수가 한개인 경우) 
const arrow = x => {...};
                    
// 매가변수 없는 경우 소괄호 생략 불가능 
const arrow = () => {...};
                     
// 함수 몸체 정의 - 중괄호 생략 가능 
const power = x => x * 2;

//객체 리터럴을 반환하는 경우 객체리터럴을 소괄호로 감싸주어야 한다.
cosnt create = (id, create) => ({id, create}); 
                     
// 함수 몸체가 여러개의 문으로 구성되어있는 경우 중괄호 생략 불가능
const sum = (a,b) => {
  const result = a+b;
  return result; 
} 

// 화살표 함수도 즉시 실행 함수로 사용 가능
const person = (name => ({
  sayHi(){return `Hi? My name is ${name}.`;}
}))('Lee');
                     
console.log(person.sayHi());// Hi? My name is Lee.

🧐 화살표함수와 일반함수의 차이?

✔️ 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor다.
✔️ 중복된 매개변수 이름을 선언할 수 없다. const arrow =(a,a) => a + a // SyntaxError
✔️ 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.

🧐 화살표 함수에서의 this

✔️ ES6에서는 화살표 함수를 사용하여 "콜백 함수 내부의 this 문제를 해결할 수 있다.
👉 map 을 통해 일반함수를 return할 때 this는 global 객체를 가리키게 되고 class 내부에서는 코드가 암묵적으로 'strict mode'로 동작하기 때문에 'undefined'를 반환한다는 문제를 갖고 있었음.

class Prefixer {
  constructor(prefix){
    this.prefix = prefix;
  }
  
  add(arr){
    return arr.map(item => this.prefix + item);
  }
}

화살표 함수는 함수 자체의 this 바인딩을 갖지 않는다. 따라서 화살표 함수 내부에서 this를 참조하면 상위 스코프의 this를 그대로 참조한다. 이를 lexical this라고 함.

ex)

const foo = () => console.log(this);
foo(); // window
const counter = {
  num : 1, 
  increase : () => ++this.num
};

console.log(counter.increase());// NaN 

✔️ 화살표함수는 함수자체의 this바인딩을 갖지 않기 때문에 call, apply, bind 메서드를 사용해도 화살표 내부의 this를 교체할 수 없음!

window.x = 1;  

const arrow = () => this.x;

console.log(arrow.call({x : 10})); // 1

✔️ 메서드를 화살표 함수로 정의하는 것은 피해야함! (메서드 : ES6 메서드가 아닌 일반적인 의미의 메서드) 👉 this를 참조하지 못하므로

🧐 화살표함수에서의 super

✔️ 화살표 함수는 함수 자체의 super 바인딩을 갖지 않음. 따라서 화살표 함수 내부에서 super를 참조하면 this와 마찬가지로 상위 스코프의 super를 참조한다.

ex)

class Base {
  constructor(name){
    this.name = name; 
  }
  
  sayHi(){
    return `Hi! ${this.name}`;
  }
}

class Derived extends Base {
  sayHi = () => `${super.sayHi()} Hi!`;
}

const derived = new Derived('Lee'); 
console.log(derived.sayHi()); // Lee Hi! 

🧐 화살표 함수 내에서의 arguments

✔️ 화살표 함수는 함수 자체의 arguments 바인딩을 갖지 않음. this와 마찬가지로 상위 스코프의 arguments를 참조.

ex)

(funtion(){
 // 화살표 함수 foo의 arguments는 상위 스코프인 즉시 실행 함수의 arguments를 가리킨다.  
 const foo = () => console.log(arguments); // [Arguments]{ '0' : 1, '1' : 2 }
foo(3,4);
}(1,2)); 


const foo = (1,2) => console.log(arguments);
foo(1,2); // Reference Error 전역에서는 arguments 객체가 존재하지 않으므로! 함수내부에서만 유효함! 

26.4 Rest 파라미터

Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달받는다.
✔️ 먼저 선언된 매개변수에 할당된 인수를 제외한 나머지 인수들로 구서된 배열에 할당된다. 따라서 Rest 파라미터는 반드시 마지막 파라미터이어야함.

function foo(param, ...rest){
  console.log(param); // 1 
  console.log(rest); // [2,3,4,5]
}

foo(1,2,3,4,5);

✔️ rest 파라미터를 활용함으로써 유사 배열 객체인 arguments 객체를 배열로 변환하는 번거로움을 피할 수 있음.

26.5 매개변수 기본값

ES6에서 도입된 매개변수 기본값

function sum(x=0,y=0){
  return x + y;
}

console.log((sum(1)); // 1 

참고로, Rest 파라미터에는 기본값 지정할 수 없음!
또한 매개변수 기본값은 함수 정의 시 선언한 매개변수 개수를 나타내는 함수 객체의 length 프로퍼티와 arguments 객체에 아무런 영향 주지 않음!

profile
꾸준히 성장하기🦋 https://hyodduru.tistory.com/ 로 블로그 옮겼습니다

0개의 댓글