20. Additional features of ES6 function

ES6의 추가기능

Index

추가 기능의 필요성

ES6의 함수 구분

화살표 함수

매개변수 기본값



1. 추가 기능의 필요성

🧐 Q. ES6 이전에 객체에 바인딩된 함수가 construct(생성 가능한 함수)라는 것은 해당 함수가 prototype 프로퍼티를 가지며, 이로 인해 프로토타입 객체도 생성된다는 것을 의미한다. 이는 몇 가지 잠재적인 문제를 야기할 수 있지 않을까?

Answer)

1.1 모든 함수가 prototype을 가지므로 불필요한 리소스 낭비

function notAConstructor() {
  console.log("This function is not meant to be a constructor!");
}

console.log(notAConstructor.prototype); // { constructor: f }
  • notAConstructor 함수는 생성자로 사용되지 않지만, prototype 프로퍼티와 프로토타입 객체가 자동으로 생성됩니다.

  • 이 객체는 불필요한 리소스를 사용하며, 생성자의 의도가 없더라도 이를 무조건 포함하게 됩니다.



1.2 new와 일반 함수 호출 간의 혼동

function Person(name) {
  this.name = name;
}

const p1 = new Person("Lee"); // 생성자로 호출
console.log(p1.name); // Lee

const p2 = Person("Kim"); // 일반 함수로 호출
console.log(p2); // undefined (this는 전역 객체를 가리킴, strict mode에서는 에러)
  • new 없이 호출된 Personthis가 전역 객체를 가리키며, 이는 의도하지 않은 동작을 초래할 수 있습니다.

  • Strict mode에서는 thisundefined로 설정되기 때문에 에러가 발생할 가능성도 있습니다.



1.3 prototype 재정의의 비일관성

function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = function () {
  console.log(`Hi, ${this.name}`);
};

// 프로토타입 재정의
Person.prototype = {
  sayHi() {
    console.log("New prototype method!");
  },
};

const p1 = new Person("Lee");
console.log(p1.sayHi()); // TypeError: p1.sayHi is not a function
  • prototype을 재정의하면, 생성 가능한 함수로부터 생성된 새로운 인스턴스는 재정의된 프로토타입을 참조한다.
  • 하지만, 기존 인스턴스는 이미 생성 시점에 프로토타입 체인을 고정했기 때문에 재정의된 프로토타입과 연결되지 않는다.



1.4 객체 메서드와 생성 가능 함수 간의 혼동

const obj = {
  method: function () {
    console.log("This is a regular method.");
  },
};

console.log(obj.method.prototype); // { constructor: f }

const instance = new obj.method(); // 가능하지만 의도되지 않은 동작
  • method는 단순히 객체의 메서드로 사용하려는 의도였지만, new를 사용해 호출할 수도 있습니다.

  • 이는 함수가 생성 가능하다는 점에서 혼란을 초래할 수 있습니다.



2.ES6는 함수의 사용 목적에 따라 세 가지 종류로 명확히 구분

2.1 constructor

  • constructor생성 가능한 함수를 의미한다.
  • 생성 가능한 함수new 키워드로 호출할 수 있으며, 새로운 객체를 생성한다.

  • 일반 함수: constructor로 사용할 수 있다. (O)
  • 메서드: constructor로 사용할 수 없다. (X)
  • 화살표 함수: constructor로 사용할 수 없다. (X)
function Normal() {} // 일반 함수
const obj = {
  method() {}, // 메서드
  arrow: () => {}, // 화살표 함수
};

new Normal(); // 가능
// new obj.method(); // TypeError: obj.method is not a constructor
// new obj.arrow(); // TypeError: obj.arrow is not a constructor



2.2 prototype

  • 생성 가능한 함수는 기본적으로 prototype 프로퍼티를 가지고 있으며, 이를 통해 프로토타입 체인을 구성한다.

  • 일반 함수: prototype 프로퍼티를 가진다. (O)
  • 메서드: prototype 프로퍼티를 가지지 않는다. (X)
  • 화살표 함수: prototype 프로퍼티를 가지지 않는다. (X)
function Normal() {} // 일반 함수
const obj = {
  method() {}, // 메서드
  arrow: () => {}, // 화살표 함수
};

console.log(Normal.prototype); // {constructor: ƒ}
console.log(obj.method.prototype); // undefined
console.log(obj.arrow.prototype); // undefined



2.3 super

  • super상위 클래스나 객체의 메서드를 호출하거나 접근할 때 사용한다.
  • 메서드 정의 문법에서는 super를 사용할 수 있지만, 일반 함수와 화살표 함수에서는 사용할 수 없다.
  • 일반 함수나 화살표 함수에서는 super를 사용하면 에러가 발생한다.

  • 일반 함수: super를 사용할 수 없다. (X)
  • 메서드: super를 사용할 수 있다. (O)
  • 화살표 함수: super를 사용할 수 없다. (X)
class Parent {
  greet() {
    console.log("Hello from Parent");
  }
}

class Child extends Parent {
  method() {
    super.greet(); // 가능
  }
}

const child = new Child();
child.method(); // Hello from Parent



2.4 arguments

  • arguments는 함수 호출 시 전달된 모든 인수 정보를 담고 있는 유사 배열 객체다.
  • ES6 이후의 화살표 함수에서는 arguments를 사용할 수 없으며, 대신 rest 파라미터를 사용해야 한다.

  • 일반 함수: arguments 객체를 사용할 수 있다. (O)
  • 메서드: arguments 객체를 사용할 수 있다. (O)
  • 화살표 함수: arguments 객체를 사용할 수 없다. (X)
function normalFunc() {
  console.log(arguments); // 유사 배열 객체
}

const obj = {
  method() {
    console.log(arguments); // 유사 배열 객체
  },
  arrow: () => {
    // console.log(arguments); // ReferenceError: arguments is not defined
  },
};

normalFunc(1, 2, 3); // [1, 2, 3]
obj.method(4, 5, 6); // [4, 5, 6]
// obj.arrow(7, 8, 9); // 에러 발생



3. 화살표 함수

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

this 바인딩은 함수의 호출방식, 즉 함수가 어떻게 호출되었는지에 따라 동적으로 결정된다. 다시 말해, 함수를 정의할 때 this에 바인딩할 객체가 정적으로 결정되는 것이 아니고, 함수를 호출할 때 🥸어떻게 호출되었는지에 따라 this에 바인딩할 객체가 동적으로 결정된다.

class Prefixer {
  constructor(prefix) {
    this.prefix = prefix;
  }
  add(arr) {
    return arr.map(function (item) {
      return this.prefix + item;
      // TypeError: Cannot read property 'prefix' of undefined
    });
  }
}

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

🧐 Q. 왜 이렇게 되는 걸까?

ⅰ. strict mode인 경우,

=> 엄격 모드(use strict)에서는 thisundefined로 설정됩니다.

ⅱ. strict mode가 아닌 경우

=> 일반 함수로 호출된 경우, 기본적으로 this전역 객체(window in 브라우저, global in Node.js)를 참조합니다.


🧐 Q. 그렇다면 항상 일반함수로서 호출되는 모든 함수내부의 this는 전역객체를 가리키나요?

ⅰ. 객체의 메서드로 호출하는 경우

const obj = {
  value: 42,
  method: function () {
    console.log(this.value);
  },
};

obj.method(); // 42 (this는 obj를 참조)

그러나 일반 함수로 호출되면 다시 전역 객체를 참조하거나 undefined가 됩니다.

const method = obj.method;
method(); // 브라우저: undefined (window.value), strict mode: undefined


ⅱ. 생성자 함수로 호출

일반 함수가 생성자 함수로 호출(new 사용)되면, this는 새로 생성된 객체를 참조합니다.

function Person(name) {
  this.name = name;
}

const person = new Person("Lee");
console.log(person.name); // Lee

이 경우, this는 생성된 person 객체를 가리킵니다.


ⅲ. call, apply, bind로 호출

일반 함수는 call, apply, bind를 사용하여 this를 명시적으로 설정할 수 있습니다.

function normalFunc() {
  console.log(this);
}

const obj = { value: 42 };

normalFunc.call(obj); // { value: 42 }
normalFunc.apply(obj); // { value: 42 }

const boundFunc = normalFunc.bind(obj);
boundFunc(); // { value: 42 }


ⅳ . 화살표 함수 내부에서 호출

화살표 함수 내부에서 일반 함수가 호출되면, 화살표 함수의 상위 스코프에서 this를 고정합니다.

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

const obj = {
  value: 42,
  arrowFunc: () => {
    function normalFunc() {
      console.log(this);
    }
    normalFunc();
  },
};

obj.arrowFunc(); // 브라우저: window, strict mode: undefined


🧐 Q. 화살표 함수가 this 바인딩이 없다면 어떤 스코프를 참조할까?

Answer)

화살표 함수는 함수 자체의 this 바인딩을 갖지 않기 때문에, Function.prototype.call, apply, bind 메서드를 사용해도 화살표 함수 내부의 this를 교체할 수 없다. 화살표 함수는 함수 자체의 this 바인딩을 갖지 않기 때문에 this를 교체할 수 없고 언제나 상위 스코프의 this 바인딩을 참조한다. 그럼에도 Function.prototype.call, apply, bind 메서드를 호출할 수 있다.

const add = (a, b) => a + b;

console.log(add.call(null, 1, 2)); // 3
console.log(add.apply(null, [1, 2])); // 3
console.log(add.bind(null, 1, 2)()); // 3
// call, apply, bind 메서드에서는 첫 번째 인자로 this를 전달해야 하므로, 특별히 설정할 필요가 없는 경우 null이나 undefined를 관례적으로 전달합니다. 이 두 값은 다음과 같은 이유로 자주 사용된다.



3.2 화살표 함수 사용시 주의해야 할 사항!

ⅰ. 프로퍼티에 할당한 화살표 함수 내부의 this는 상위스코프인 전역의 this가 가리키는 전역객체를 가리킨다.

=> 메서드 축약 표현으로 메서드를 사용하자!

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

person.sayHi(); // Hi

화살표 함수의 this는 상위 스코프의 this를 고정합니다.

  • sayHiperson 객체 내부에 정의되었지만, 화살표 함수는 this를 자신의 상위 스코프에서 찾습니다.
  • 객체 리터럴의 상위 스코프는 전역 스코프이므로, this는 전역 객체를 참조합니다.

전역 객체의 name

  • 브라우저 환경에서 window.name의 기본값은 빈 문자열("")이고, Node.js 환경에서는 global.nameundefined입니다.
  • 따라서 this.nameundefined가 됩니다.
const person = {
  name: "Lee",
  sayHi() {
    const greet = () => console.log(`Hi ${this.name}`);
    greet(); // 화살표 함수 호출
  },
};

person.sayHi(); // Hi Lee

객체 리터럴 안에서 화살표 함수가 정의되었을 때, 화살표 함수의 상위 스코프는 전역 스코프로 간주됩니다. 객체 리터럴 자체는 단순히 값으로 평가될 뿐, 스코프를 생성하지 않기 때문입니다.

일반 메서드로 정의된 함수는 호출 시점에서 this가 결정되므로, person.sayHi()와 같은 방식으로 호출하면 this는 객체를 참조합니다.


ⅱ. 프로토타입 객체의 프로퍼티에 화살표 함수를 할당하는 경우도 동일한 문제가 발생한다

function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = () => console.log(`Hi ${this.name}`);

const person = new Person("Lee");
// 이 예제를 브라우저에서 실행하면 this.name은 빈 문자열을 갖는 window name과 같다.
person.sayHi(); // Hi

Person.prototype.sayHi가 화살표 함수로 정의

  • 화살표 함수는 자신의 this를 가지지 않으며, 상위 스코프의 this를 참조합니다.
  • 여기서 sayHiPerson.prototype에 추가된 메서드이지만, 화살표 함수의 상위 스코프는 전역 스코프입니다.

this는 전역 객체를 참조

  • 브라우저 환경에서 window 객체가 전역 객체로 작동합니다.
  • 브라우저의 window 객체에는 기본적으로 name 속성이 존재하며, 초기값은 빈 문자열("")입니다.
  • 따라서 this.namewindow.name과 같아지며, 결과적으로 빈 문자열이 출력됩니다.
function Person(name) {
  this.name = name;
}

Person.prototype.sayHi = function () {
  console.log(`Hi ${this.name}`);
};
// 프로토타입 메서드에서 화살표 함수를 사용하면, this가 인스턴스를 참조하지 않고, 상위 스코프(대부분 전역 객체)를 참조합니다. 화살표 함수는 상위 스코프의 this를 고정하기 때문에, 인스턴스를 참조하지 못합니다.
// 화살표 함수에서 일반 함수로 바꾼 이유는 프로토타입 메서드에서 this가 올바르게 인스턴스를 참조하도록 하기 위함입니다.
const person = new Person("Lee");
person.sayHi(); // Hi Lee

// 일일이 프로토타입 메서드를 개별적으로 추가하기 보단 객체리터럴을 바인딩하고 프로토타입의 constructor 프로퍼티와 생성자 함수 간의 연결을 재설정한다.
function Person(name) {
  this.name = name;
}

Person.prototype = {
  constructor: Person, // `Person`으로 수정
  sayHi() {
    console.log(`Hi ${this.name}`);
  },
  sayBye() {
    console.log(`Bye ${this.name}`);
  },
};

const person = new Person("Lee");
person.sayHi(); // Hi Lee
person.sayBye(); // Bye Lee

프로토타입 메서드에서 화살표 함수를 사용하면, this가 인스턴스를 참조하지 않고, 상위 스코프(대부분 전역 객체)를 참조합니다.
화살표 함수상위 스코프의 this를 고정하기 때문에, 인스턴스를 참조하지 못합니다. 화살표 함수에서 일반 함수로 바꾼 이유는 프로토타입 메서드에서 this가 올바르게 인스턴스를 참조하도록 하기 위함입니다.


ⅲ. 클래스 필드에서 화살표 함수를 사용하면 메서드가 인스턴스 메서드로 정의되고, ES6 메서드 축약 표현을 사용하면 메서드가 프로토타입 메서드로 정의된다

class Person {
  constructor() {
    this.name = "Lee";
    this.sayHi = () => console.log(`Hi ${this.name}`);
  }
}

const person = new Person();
person.sayHi(); // Hi Lee

this.sayHi = () => {...}로 화살표 함수를 클래스 필드에 정의하면, 이 함수는 인스턴스에 직접 할당됩니다.

여기서 상위 스코프는 constructor 함수이므로, this는 생성된 인스턴스를 참조합니다.

즉, 각 인스턴스가 자신의 sayHi 함수를 가지게 됩니다.

class Person {
  name = "Lee";

  sayHi() {
    console.log(`Hi ${this.name}`);
  }
}

const person = new Person();
person.sayHi(); // Hi Lee

sayHi()로 정의한 메서드는 프로토타입 메서드로 등록됩니다.

모든 인스턴스가 Person.prototype에 정의된 동일한 sayHi 메서드를 공유하기 때문입니다.


핵심 차이 정리: 인스턴스 메서드 vs 프로토타입 메서드
Photo of Using an arrow function in a class field defines an instance method, while using the ES6 method shorthand defines a prototype method.

Using an arrow function in a class field defines an instance method, while using the ES6 method shorthand defines a prototype method.

Jay Tak


🤓 this는 어떻게 결정되는가?

일반 함수의 경우:

  • this호출 시점에 결정됩니다.
  • 함수가 실행될 때 어떤 객체를 통해 호출되었는지에 따라 this가 바뀝니다.

화살표 함수의 경우:

  • this정의 시점상위 스코프의 this로 고정됩니다.
  • 호출 방식과 관계없이 this렉시컬(Lexical)로 결정됩니다.



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

화살표 함수에서 super를 “바인딩하지 않는다”는 것은 화살표 함수가 자체적으로 super를 설정하지 않고, 작성된 위치의 상위 스코프의 super를 그대로 참조한다는 뜻입니다.

3.3.1 일반 메서드에서 super의 동적 동작

class GrandBase {
  sayHi() {
    return "Hi from GrandBase";
  }
}

class Base extends GrandBase {
  sayHi() {
    return `${super.sayHi()} -> Hi from Base`;
  }
}

class Derived extends Base {
  sayHi() {
    return `${super.sayHi()} -> Hi from Derived`;
  }
}

// Base 클래스의 sayHi를 호출하는 다른 객체 생성
const baseInstance = {
  sayHi: Base.prototype.sayHi,
  __proto__: GrandBase.prototype, // Base의 프로토타입 체인 강제 설정
};

const derived = new Derived();

// 일반 메서드 호출
console.log(derived.sayHi()); // Hi from GrandBase -> Hi from Base -> Hi from Derived
console.log(baseInstance.sayHi()); // Hi from GrandBase -> Hi from Base
3.3.1.1 Derived 클래스의 sayHi 호출
  • derived.sayHi()에서 super.sayHi()Base 클래스의 sayHi 메서드를 참조합니다.

  • Base 클래스의 sayHi 메서드는 다시 super.sayHi()를 호출하며, 이는 GrandBase 클래스의 sayHi 메서드를 참조합니다.

  • 이처럼 호출 시점에서 상속 계층에 따라 super가 동적으로 참조됩니다.

    Hi from GrandBase -> Hi from Base -> Hi from Derived
    
3.3.1.2 baseInstance.sayHi 호출
  • baseInstanceBase.prototype.sayHi를 직접 참조하지만, 프로토타입 체인을 GrandBase로 강제 설정했습니다.

  • super.sayHi()GrandBasesayHi 메서드를 호출하며, 그 결과는 다음과 같습니다:

    Hi from GrandBase -> Hi from Base
    


3.3.2 화살표 함수로 동일한 동작을 구현한 경우

class Derived extends Base {
  sayHiArrow = () => `${super.sayHi()} -> Hi from Derived (Arrow)`;
}

const derived = new Derived();
const baseInstanceArrow = {
  sayHiArrow: Base.prototype.sayHi,
  __proto__: GrandBase.prototype, // Base의 프로토타입 체인 강제 설정
};

console.log(derived.sayHiArrow()); // Hi from GrandBase -> Hi from Base -> Hi from Derived (Arrow)
console.log(baseInstanceArrow.sayHiArrow()); // TypeError: super is not valid
  • 화살표 함수는 작성된 위치에서 super가 고정되기 때문에, 프로토타입 체인을 강제로 변경해도 동적으로 동작하지 않습니다.
  • baseInstanceArrow.sayHiArrow()는 작동하지 않으며, super를 호출할 수 없다는 에러가 발생합니다.

결론

  1. 일반 메서드에서 super의 동적 동작:
    • 호출된 객체의 프로토타입 체인에 따라 바로 위 상위 클래스의 메서드를 참조합니다.
    • 상속 계층이 달라지거나 프로토타입 체인이 강제 변경되면, 참조되는 메서드도 달라질 수 있습니다.
  2. 화살표 함수에서 super:
    • 작성된 위치에서 super가 고정되므로, 호출된 객체의 프로토타입 체인과 상관없이 항상 고정된 상위 클래스를 참조합니다.



3.4 화살표 함수에서는 argument 객체를 사용할 수 없다.

3.4.1 즉시실행 함수의 arguments

(function () {
  const foo = () => console.log(arguments); // 상위 스코프의 arguments를 참조
  foo(3, 4); // arguments는 즉시 실행 함수의 arguments
})(1, 2);

[Arguments] { '0': 1, '1': 2 }

즉시 실행 함수 (function() { ... })(1, 2)는 일반 함수이므로, 자체적으로 arguments 객체를 생성합니다.
즉시실행 함수는 상위 스코프(즉시 실행 함수)의 arguments 객체를 참조합니다.
화살표 함수는 즉시 실행 함수의 arguments를 출력합니다.


3.4.2 전역스코프에서 화살표 함수의 arguments

const foo = () => console.log(arguments);
foo(1, 2);

ReferenceError: arguments is not defined

전역 스코프에서는 arguments 객체가 존재하지 않습니다.
화살표 함수는 자체 arguments 객체를 생성하지 않으므로, 상위 스코프의 arguments를 찾으려고 시도합니다.


3.4.3 화살표 함수에서 arguments 대신 Rest 파라미터 사용

const foo = (...args) => console.log(args);
foo(1, 2, 3);

[1, 2, 3];

Rest 파라미터(...args)는 함수에 전달된 인수를 배열 형태로 캡처합니다.
arguments 객체와 달리, Rest 파라미터는 배열이므로 배열 메서드를 사용할 수 있습니다.


요약

  • 화살표 함수는 자체 arguments 객체를 가지지 않으며, 상위 스코프의 arguments를 참조합니다.
  • 상위 스코프에 arguments가 없으면 ReferenceError가 발생합니다.
  • arguments 대신 Rest 파라미터(...args)를 사용하는 것이 권장됩니다. 😊



4. 매개변수 기본값

4.1 ES6 이전 방어코드

function sum(x, y) {
  // 인수가 전달되지 않거나 undefined인 경우 기본값을 할당
  x = x || 0;
  y = y || 0;

  return x + y;
}

console.log(sum(1, 2)); // 3
console.log(sum(1)); // 1 (y가 undefined이므로 0이 기본값으로 설정됨)

동작 원리:

  1. OR 연산자(||)를 사용:
    • x = x || 0xundefined, null, false, 0 등 falsy 값인 경우 기본값 0을 할당합니다.
    • 마찬가지로, y = y || 0y가 falsy 값인 경우 기본값을 할당합니다.
  2. 문제점:
    • x 또는 y가 의도적으로 0인 경우에도 기본값으로 덮어씌워질 수 있습니다.
    • 예: sum(0, 1)0을 기본값으로 간주하여 결과가 의도와 다를 수 있음.



4.2 ES6 이후: 매개 변수 기본값 문법 도입

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

console.log(sum(1, 2)); // 3
console.log(sum(1)); // 1 (y가 기본값 0을 가짐)
console.log(sum()); // 0 (x와 y 모두 기본값 0을 가짐)

동작 원리:

  1. 매개변수 기본값 지정:
    • x = 0은 매개변수 x인수가 전달되지 않거나 undefined인 경우 기본값 0을 할당합니다.
    • y = 0도 동일하게 동작합니다.
  2. null 처리:
    • null은 기본값으로 덮어쓰지 않습니다. 따라서 sum(null, 1)null + 1 = 1로 처리됩니다.



4.3 매개변수 기본값의 동작

function logName(name = "Lee") {
  console.log(name);
}

logName(); // Lee (기본값이 사용됨)
logName(undefined); // Lee (undefined일 때만 기본값이 적용됨)
logName(null); // null (기본값이 적용되지 않음)

동작 원리:

  1. 기본값 적용 조건:
    • 매개변수에 전달된 값이 undefined일 경우에만 기본값이 적용됩니다.
    • null은 기본값으로 간주되지 않으므로 전달된 그대로 null이 사용됩니다.
  2. 출력 결과:
    • logName()undefined로 간주되어 기본값 'Lee'가 출력됩니다.
    • logName(undefined) → 기본값 'Lee'가 출력됩니다.
    • logName(null) → 기본값이 적용되지 않고, 전달된 값 null이 그대로 출력됩니다.



4.4 Rest 파라미터의 기본값 불가능

function foo(...rest = []) {
  console.log(rest);
}
// SyntaxError: Rest parameter may not have a default initializer

  1. 제약 사항:
    • Rest 파라미터는 기본적으로 전달된 모든 인수의 배열을 캡처합니다.
    • 자바스크립트의 문법 제약상, Rest 파라미터에 기본값을 지정할 수 없습니다.
      • 예: ...rest = []문법 오류 발생
  2. 왜 기본값을 지정할 수 없는가?
    • Rest 파라미터는 함수 호출 시 전달된 인수의 전체 목록을 배열로 제공하기 때문에, 기본값을 지정할 필요가 없습니다.
    • 만약 인수가 전달되지 않았다면, Rest 파라미터는 빈 배열([])로 자동 초기화됩니다.



4.5 매개변수 기본값과 함수 lengtharguments

function sum(x, y = 0) {
  console.log(arguments); // 함수에 전달된 실제 인수 목록
}

console.log(sum.length); // 1 (기본값을 가지지 않는 매개변수만 계산)
sum(1); // Arguments { '0': 1 }
sum(1, 2); // Arguments { '0': 1, '1': 2 }

동작 원리:

4.5.1 함수 length 프로퍼티:

  • 함수의 length기본값이 없는 매개변수의 개수를 나타냅니다.
  • function sum(x, y = 0)에서 기본값이 없는 매개변수는 x 하나뿐이므로, sum.length1입니다.

    4.5.2 arguments 객체:

  • arguments는 함수 호출 시 전달된 실제 인수 목록을 나타냅니다.
  • 기본값으로 초기화된 매개변수는 arguments 객체에 포함되지 않습니다.
  • 예:
    • sum(1) 호출 시, arguments{ '0': 1 }로 표시됩니다. y는 기본값(0)이지만, arguments에 포함되지 않습니다.
    • sum(1, 2) 호출 시, arguments{ '0': 1, '1': 2 }로 표시됩니다.




reference: 모던자바스크립트 Deep Dive 26장. ES6 함수의 추가 기능