본문 바로가기

JavaScript

[Deep dive] 26장 ES6 함수의 추가 기능

26.1 함수의 구분

 

- ES6 이전의 모든 함수는 일반 함수로서 호출할 수 있는 것은 물론 생성자 함수로서 호출할 수 있음

- ES6 이전의 모든 함수는 callable 이면서 constructor다

- ES6 이전에 일반적으로 메서드라고 부르던 객체에 바인딩된 함수도 callable이면서 constructor

 

- ES6에서는 함수를 사용 목적에 따라 세 가지 종류로 명확히 구분

ES6함수의 구분 constructor prototype super arguments
일반 함수  o o o
메서드  x x o x
화살표 함수  x x x x

 

 

26.2 메서드 

 

- ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미 

- ES6 사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 non - constructor

- ES6 메서드는 인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고 프로토타입도 생성하지 않음

- ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 가짐 

 => super 키워드 사용 가능

 

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

const derived ={
  __proto__ : base,
  //sayHi는 ES6메서드.ES6 메서드는 [[HomemObject]]를 가짐 
  //sayHi의 [[HomeObject]]는 sayHi가 바인딩된 객체인 derived를 가리킴
  //super는 sayHi의 [[HomeObject]]의 프로토타입인 base를 가리킴
  sayHi() {
    return `${super.sayHi()}.how are you doing?`;
  }
};

console.log(derived.sayHi()); //Hi! Lee.how are you doing?

 

26.3 화살표 함수 

 

- 화살표 함수(arrow function)은 function 키워드 대신 화살표(=>)를 사용하여 기존의 함수 정의 방식보다 더 간략하게 함수 정의 가능

 

26.3.1 화살표 함수 정의 

 

- 화살표 함수는 함수 표현식으로 정의해야함 

const multiply = (x,y) => x*y;
multiply(2,3); //6

- 매개변수가 여러 개인 경우 소괄호 ()안에 매개변수 선언 

- 매개변수가 한 개인 경우 소괄호 () 생략 가능

- 매개변수가 없는 경우 소괄호 () 생략 불가 

 

- 함수 몸체가 하나의 문으로 구성된다면 함수 몸체를 감싸는 중괄호 {} 생략 가능

//concise body
const power1 = x => x ** 2;
power(2); //4

//block body
const power2 = x => {return x **2;};

- 함수 몸체가 하나의 문으로 구성된다 해도 함수 몸체의 문이 표현식이 아닌 문이라면 중괄호 생략 불가 

const arrow = () => {const x = 1;};

- 객체 리터럴을 반환하는 경우 객체 리터럴을 소괄호 ()로 감싸 주어야 함

const create = (id,content) => ({id,content});
create(1,'JavaScript'); // {id:1, content:"JavaScript"}

- 화살표 함수도 즉시 실행 함수로 사용 할 수 있음

const person = (name => ({ 
  sayHi() {return `Hi? My name is ${name}.`;}
}))('Lee');

console.log(person.sayHi()); //Hi? My name is Lee.

- 화살표 함수도 일급 객체이므로 Array.prototype.map, Array.prototype.filter, Array.prototype.reduce 같은 고차 함수에 인수로 전달 가능

- 화살표 함수는 콜백 함수로서 정의할 때 유리 

//ES5
[1,2,3].map(function(v) {
	return v * 2;
});

//ES6
[1,2,3].map(v => v*2); //[2,4,6]

 

26.3.2 화살표 함수와 일반 함수의 차이

 

1) 화살표 함수는 인스턴스를 생성할 수 없는 non_constructor이다

 - 화살표 함수는 생성자 함수로서 호출 불가 

 

2) 중복된 매개변수 이름을 선언할 수 없다 

- 화살표 함수에서 중복된 매개변수 이름을 선언하면 에러 발생

 

3) 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다

 - 화살표 함수 내부에서 this, arguments, super, new.target을 참조하면 스코프 체인을 통해 상위 스코프의 this, arguments, super, new.target을 참조 

 

 

26.3.3 this

- 화살표 함수는 다른 함수의 인수로 전달되어 콜백 함수로 사용되는 경우가 많음

- "콜백 함수 내부의 this 문제"를 해결 

 

콜백 함수 내부의 this 문제 

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }

  add(arr) {
    //add 메서드는 인수로 전달된 배열 arr을 순회하며 배열의 모든 요소에 prefix를 추가 
    return arr.map(function(item) {
      return this.prefix + item;
      //undefined
    });
  }
}

const prefixer = new Prefixer('-webkit-');
console.log(prefixer.add['transition','user-select']);

- Array.prototype.map 메서드가 콜백 함수를 일반 함수로서 호출

 -> 일반 함수로서 호출된 모든 함수 내부의 this에는 undefined가 바인딩 

 

- 콜백 함수의 this(undefined)와 외부 함수의 thi(prefixer 객체)가 서로 다른 값을 가리키고 있기 떄문에 TypeError 발생 

 

- 화살표 함수를 사용하여 "콜백 함수 내부의 this 문제" 해결

class Prefiexer {
  constructor(prefix) {
    this.prefix = prefix;
  }

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

const prefixer = new Prefiexer('-webkit-');
console.log(prefixer.add(['transition', 'user-select']));
//[ '-webkit-transition', '-webkit-user-select' ]

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

 

- 화살표 함수를 Function.prototype.bind를 사용하여 표현

//화살표 함수는 상위 스코프의 this를 가리킴
() => this.x;

//익명 함수에 상위 스코프의 this를 주입. 위 화살표 함수와 동일하게 작동
(function () {return this.x;}).bind(this);

- 메서드를 화살표 함수로 정의하는 것은 피해야 함

- 메서드를 정의할 때는 ES6 메서드를 사용 

const person = {
  name : 'Lee',
  sayHi: () => console.log(`Hi ${this.name}`)
};

//sayHi 프로퍼티에 할당된 화살표 함수 내부의 this는 상위 스코프인 전역의 this가 가리키는 
//전역 객체를 가리키므로 this.name은 빈 문자열을 갖는 window.name과 같음
//전역 객체 window에는 빌트인 프로퍼티 name이 존재 
person.sayHi(); //Hi undefined

 

26.3.4 super

- 화살표 함수는 함수 자체의 super 바인딩을 갖지 않음. 화살표 함수 내부에서 super를 참조하면 상위 스코프의 super을 참조 

 

- super는 내부 슬롯 [[HomeObject]]를 갖는 ES6 메서드 내에서만 사용할 수 있는 키워드

- 화살표 함수는 ES6 메서드는 아니지만 함수 자체의 super 바인딩을 갖지 않으므로 super을 참조해도 에러가 발생하지 않고 constructor의 super 바인딩을 참조 

class Base {
  constructor(name) {
    this.name = name;
  }

  sayHi() {
    return `Hi! ${this.name}`;
  }
}

class Derived extends Base {
  //화살표 함수의 super는 상위 스코프인 constructor의 super을 가리킴
  sayHi = () => `${super.sayHi()} how are you doing?`;
}

const derived = new Derived('Lee');
console.log(derived.sayHi()); //Hi! Lee how are you doing?

 

26.3.5 arguments

 

- 화살표 함수는 함수 자체의  arguments 바인딩을 갖지 않음. 화살표 함수 내부에서 arguments를 참조하면 상위 스코프의 arguments를 참조 

 

 -arguments 객체는 함수를 정의할 때 매개변수의 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용 

 

- 화살표 함수로 가변 인자 함수를 구현해야 할 때는 Rest 파라미터 사용 

 

 

26.4 Rest 파라미터 

26.4.1 기본 문법

 

- 매개변수 이름 앞에 세개의 점(...)을 붙여서 정의한 매개변수

- Rest 파라미터는 함수에 전달된 인수들의 목록을 배열로 전달받음

function foo(...rest) {
  //매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터 
  console.log(rest); //[ 1, 2, 3, 4, 5 ]
}

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

- 먼저 선언된 매개변수에 할당된 인수를 제외한 나머지 인수들로 구성된 배열이 할당 

- Rest 파라미터는 반드시 마지막 파라미터이어야 함

- Rest 파라미터는 단 하나만 선언 가능 

- Rest 파라미터는 함수 객체의 length 프로퍼티에 영향을 주지 않음

 

26.4.2 Rest 파라미터와 arguments 객체 

 

- arguments 객체는 함수 호출시 전달된 인수(argument)들의 정보를 담고 있는 순회 가능한 유사 배열 객체이며 함수 내부에서 지역 변수처럼 사용가능

- arguments 객체는 배열 메서드를 사용하려면 arguments 객체를 배열로 변환해야 하는 번거로움 존재 

 

- Rest 파라미터를 사용하면 가변 인자 함수의 인수 목록을 배열로 직접 전달 받을 수 있음 

function sum(...args) {
  //Rest 파라미터 args에는 배열 [ 1, 2, 3, 4, 5 ]가 할당됨
  return args.reduce((pre,cur) => pre+cur,0);
}
console.log(sum(1,2,3,4,5)); //15

 

26.5 매개변수 기본값

 

- ES6에서 도입된 매개변수 기본값을 사용하면 함수 내에서 수행하던 인수 체크 및 초기화 간소화 가능

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

console.log(sum(1,2)); //3
console.log(sum(1)); //1

- Rest 파라미터에는 기본값 지정 불가 

- 매개변수 기본값은 함수 객체의 length 프로퍼티와 arguments 객체에 아무런 영향도 주지 않음

'JavaScript' 카테고리의 다른 글

[Deep dive] 27장 배열(2)  (0) 2023.08.16
[Deep dive] 27장 배열(1)  (0) 2023.08.16
[Deep dive] 25장 클래스 (2)  (0) 2023.08.16
[Deep dive] 25장 클래스 (1)  (0) 2023.08.15
[Deep dive] 24장 클로저  (0) 2023.08.14