26장. ES6 함수의 추가 기능

나주엽·2024년 6월 27일
0
post-thumbnail

함수의 구분

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

즉, ES6 이전의 모든 함수는 일반 함수로서 호출할 수 있으면서, 생성자 함수로서 호출할 수 있다.

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

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

메서드

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

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

이러한 메서드는 인스턴스를 생성할 수 없는 non-constructor 이다.

인스턴스를 생성할 수 없으므로 prototype 프로퍼티가 없고, 프토토타입도 생성하지 않는다.

new obj.foo(); // -> TypeError: obj.foo is not a constructor
new obj.bar(); // -> bar {}
// obj.foo는 constructor가 아닌 ES6 메서드이므로 prototype 프로퍼티가 없다.
obj.foo.hasOwnProperty('prototype'); // -> false

// obj.bar는 constructor인 일반 함수이므로 prototype 프로퍼티가 있다.
obj.bar.hasOwnProperty('prototype'); // -> true

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

super 참조는 내부 슬롯 [[HomeObject]] 를 사용하여 수퍼클래스의 메서드를 참조하므로 ES6 메서드는 super 키워드를 사용할 수 있다.

화살표 함수

화살표 함수는 function 키워드 대신 화살표를 사용하여 함수를 정의할 수 있다.

몇 가지 주의할 점이 있다.

  • 화살표 함수는 함수 표현식으로 정의해야 한다.
  • 매개변수가 여러 개인 경우 소괄호 () 안에 매개변수를 선언한다.
  • 매개변수가 한 개인 경우 소괄호는 생략 가능하다.
  • 함수 몸체 내부의 문이 값으로 평가될 수 있는 표현식인 문이라면 생략 가능하다.
  • 객체를 반환하기 위해서는 소괄호 () 로 감싸야 한다.
  • 즉시 실행 함수로 사용할 수 있다.

화살표 함수의 특징은 다음과 같다.

  • 화살표 함수는 인스턴스를 생성할 수 없는 non-constructor 다.
  • 중복된 매개변수 이름을 선언할 수 없다.
  • 화살표 함수는 함수 자체의 this, arguments, super, new.target 바인딩을 갖지 않는다.

this

화살표 함수가 일반 함수와 구별되는 가장 큰 특징은 바로 this 다.

화살표 함수는 함수 자체의 this 바인딩이 없고, 상위 스코프의 this 를 그대로 참조한다.

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

콜백 함수 내부의 this 가 외부 함수의 this 와 다르기 때문에 발생하는 문제, 즉 “콜백 함수 내부의 this 문제” 를 해결하기 위해 의도적으로 설계된 것이다.

class Prefixer {
	constructor(prefix) {
		this.prefix = prefix;
	}
	
	add(arr) {
		// add 메서드는 배열 arr 을 순회하며 모든 요소에 prefix를 추가한다.
		// 1
		return arr.map(function (item) {
			return this.prefix + item; // 2
			// TypeError 발생
		}
	}
}

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

위 예제를 실행할 때 기대하는 결과는 앞에 -webkit- 이 추가된 배열일 것이다.

하지만 TypeError 가 발생한다.

프로토타입 메서드 내부인 1 번 위치에서의 this 는 메서드를 호출한 객체, 즉 prefixer 객체를 가리킨다. 하지만, map() 메서드의 인수로 전달한 콜백 함수의 내부인 2 번 위치에서의 thisundefined 를 가리키게 된다.

22장에서, 일반 함수로서 호출되는 모든 함수 내부의 this 는 전역 객체를 가리킨다고 설명했다.
그런데 클래스 내부의 모든 코드에는 암묵적으로 strict mode 가 적용되어 있다.
따라서, 위의 map() 메서드의 콜백 함수에도 strict mode 가 적용된다.
strict mode 에서 일반 함수로 호출되는 모든 내부 함수의 thisundefined 가 바인딩 된다.
→ 그 결과로, 2 번 위치에서의 thisundefined 를 가리키게 된다.
이 문제가 바로 “콜백 함수 내부에서의 this 문제” 이다.

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

→ 이를 lexical this 라 한다. 이는 렉시컬 스코프와 같이 화살표 함수의 this 가 함수가 정의된 위치에 의해 결정된다는 것을 의미한다.

super

화살표 함수는 함수 자체의 super 바인딩을 갖지 않는다.

->this 와 마찬가지로 화살표 함수 내에서 super 를 참조하면 상위 스코프의 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('Son');
console.log(derived.sayHi());
//Hi! Son. how are you doing?

arguments

화살표 함수는 함수 자체의 arguments 바인딩을 갖지 않는다.

→ 화살표 함수 내부에서 arguments 를 참조하면 this 와 마찬가지로 상위 스코프의 arguments 를 참조한다.

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

// 전역에는 arguments 객체가 존재하지 않는다.
const foo = () => console.log(arguments);
foo(1, 2); // ReferenceError

Rest 파라미터

매개변수의 이름 앞에 ... 을 붙여 정의한 매겨변수이다.

Rest 파라미터를 통해 전달된 인수들의 목록을 배열로 전달 받을 수 있다.

function foo(...rest) {
  // 매개변수 rest는 인수들의 목록을 배열로 전달받는 Rest 파라미터다.
  console.log(rest);
}

foo(1, 2, 3, 4, 5);
// [ 1, 2, 3, 4, 5 ]

주의사항

  • 반드시 마지막 파라미터여야 한다.
  • 단 하나만 선언할 수 있다.
  • Rest 파라미터는 함수 정의 시 선언한 매개변수 개수를 나타내는 함수 객체의 length 프로퍼티에 영향을 주지 않는다.
  • 화살표 함수는 arguments 객체를 갖지 않는다. 반드시 Rest 파라미터를 사용해야 한다.

매개변수 기본값

인수가 전달되지 않은 매개변수의 값은 undefined 이다.

ES6 에서 도입된 매개변수 기본값을 사용하면 이를 방지할 수 있다.

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

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

매개변수 기본값은 매개변수에 인수를 전달하지 않은 경우와, undefined 가 전달된 경우에만 유효하다.

function logName(name = 'Son') {
  console.log(name);
}

logName(); // Son
logName(undefined); // Son
logName(null); // null

Rest 파라미터에는 기본값을 지정할 수 없다.

function foo(...rest = []) {
	console.log(rest);
}
// SyntaxError

0개의 댓글