ES6 함수의 추가 기능

솜사탕·2023년 5월 28일
0

JavaScript

목록 보기
22/23

함수의 구분

ES6 이전까지 자바스크립트의 함수는 별다른 구분 없이 다양한 목적으로 사용 되었다.

  • 일반 함수로서 호출
  • new 연산자와 함께 호출하여 인스턴스를 생성
  • 객체에 바인딩되어 메서드로 호출

어떻게보면 편리한 것 같지만 실수를 유발 시키고, 성능 면에서도 손해다.

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

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

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

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

// 프로퍼티에 함수 바인딩 이 함수는 callable이며 constructor다.
var xObj = {
  x: 10,
  f: functino() {return this.x;}
};

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

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

객체에 바인딩된 함수를 생성자 함수로 호출하는 경우는 흔치하지 않지만,
문법상 가능한 것은 문제가 있으며 성능적인 부분도 문제가 있는데

함수가 constructor라는 것은 객체에 바인딩된 함수가 prototype 프로퍼티를 가지며 프로토타입 객체도 생성한다는 것을 의미한다.

그래서 이러한 부분은 혼란스러우며 실수 유발 및 성능면에는 단점이라고 볼수 있다.

ES6에서는 사용 목적에 따라 세 가지 종류로 명확히 구분 했다.

ES6 함수의 구분constructorprototypesuperarguments
일반함수OOXO
메서드XXOO
화살표 함수XXXX

메서드

ES6 사양에서 메서드는 메서드 축약 표현으로 정의된 함수만을 의미한다.
또한, ES6 사양에서 정의한 메서드는 인스턴스를 생성할 수 없는 non-constructor다.

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 {}

또한 ES6 메서드는 자신을 바인딩한 객체를 가리키는 내부 슬롯 [[HomeObject]]를 갖는다.
super 참조는 내부 슬롯 [[HomeObject]]를 사용하여 수퍼클래스의 메서드를 참조한다.

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

const derived = {
  __proto__: base,
  // sayHi는 ES6메서드다 이므로 [[HomeObject]]를 갖는다.
  // sayHi의 [[HomeObject]]는 sayHi가 바인딩된 객체인 derived를 가리키고
  // super는 sayHi의 [[HomeObject]]의 프로토타입인 base를 가리킨다.
  sayHi() {
    return `${super.sayHi()} do it ?`;
  }
};

console.log(derived.sayHi()); // hi lee do it ?

화살표 함수

화살표 함수는 function 키워드 대신 화살표를 사용하여 기존의 함수 정의 방식보다 좀더 간략하게 함수를 정의할 수 있으며
내부 동작도 기존의 함수보다 간략하다.

// 함수 정의
const test = (a, b) => a + b;
const test = (a, b) => { return a + b }


//매개변수 선언
const test = (a, b) => {...}

// 매개변수 없을 시
const test = () => {...}

// 함수 호출
test(1,5);

화살표, 일반함수 차이 ?

  • 화살표 함수는 프로토타입 프로퍼티가 없으므로 생성자 함수로서 호출이 불가능 하다.
  • 화살표 함수는 중복된 매개변수 이름을 선언할 수 없다.(일반 함수는 가능)
  • 화살표 함수는 함수 자체의 this, arguemnts, super, new.target 바인딩을 갖지 않는다.

화살표 함수 this

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

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

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

해당 코드의 기대 결과는 ['-webkit-transition', '-webkit-user-select'] 이지만
typeError가 발생한다.

  • arr.map 메서드가 콜백 함수를 일반 함수로 호출함.
  • 클래스 내부의 모든 코드에는 엄격 모드가 암묵적으로 적용된다.
  • map 메서드의 콜백 함수에도 엄격 모드가 적용
    이로 인해 this는 전역 객체가 아닌 undeifned가 바인딩 된다.

이러한 문제가 바로 콜백 함수 내부의 this 문제다.

아래는 화살표 함수를 사용하여 콜백 함수 내부의 this문제를 해결할 수 있다.

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

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

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

화살표 함수는 함수 자체의 this 바인딩을 갖지 않으며
화살표 함수 내부에서 this를 참조하면 사우이 스코프의 this를 그대로 참조한다
이를 lexical this(렉시컬 디스)라 한다.

arguments

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

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

// 화살표 함수 foo의 arguments는 상위 스코프인 전역의 arguments를 가리킨다.
// 하지만 전역에는 arguments 객체가 존재하지 않으므로 arguments 객체는 함수 내부에서만 유효하다.

const foo = () => console.log(arguments);
foo(1, 2); // ReferenceError: arguments is not defined

Rest 파라미터

Rest 파라미터는 매개변수 이름 앞에 세개의 점을 붙여서 정의한 것을 말한다.
즉 전달받은 데이터를 객체나 배열에 채워넣는 역할이라고 볼수 있다.

function foo(...rest) {
  // 2.함수 호출시 전달받은 데이터를 배열에 채워 넣음
  console.log(rest); // [1,2,3,4,5]
}

foo(1, 2, 3, 4, 5) // 1.데이터 전달

매개변수 기본 값

자바스크립트는 함수를 정의할때, 매개변수 개수와 인수의 개수를 체크하지 않는다.
즉 매개변수가 2개로 지정이 되어있어도 인수는 0 개 또는 1개만 전달하여도 에러가 발생하지 않는다.

function sum(x, y) {
  return x + y;
}
console.log(sum(1)); // NaN

ES6에서는 매개변수 기본값을 사용하면 함수 내에서 수행하던 인수 체크 및 초기화를 간소화 할 수 있다.

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

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

0개의 댓글