[스터디] 함수와 일급 객체

김하은·2024년 2월 15일
0

스터디

목록 보기
4/23

일급 객체

  • 다음과 같은 조건을 만족하는 객체
    • 무명의 리터럴로 생성할 수 있음 / 즉, 런타임에 생성이 가능함
    • 변수나 자료구조(객체, 배열 등)에 저장할 수 있음
    • 함수의 매개변수에 전달할 수 있음
    • 함수의 반환값으로 사용할 수 있음
  • 자바스크립트의 함수는 위 조건을 모두 만족하므로 일급 객체임
  • 함수는객체이지만 일반 객체와는 차이가 있음
    • 일반 객체는 호출할 수 없지만 함수 객체는 호출할 수 있음
    • 함수 객체는 일반 객체에는 없는 함수 고유의 프로퍼티를 소유함
  • '일급' 이란 뜻은 일급 시민 처럼 무슨 혜택을 받는 다는 뜻이 아니라, 사용할 때 다른 요소들과 아무런 차별이 없다는 것을 뜻함

함수 객체의 프로퍼티

  • 함수 객체의 내부

  • arguments, caller, length, name, prototype 프로퍼티는 모두 함수 객체의 데이터 프로퍼티임
  • __proto__는 접근자 프로퍼티이며, 함수 객체 고유의 프로퍼티가 아니라 Object.prototype 객체의 프로퍼티를 상속받는 것임

arguments 프로퍼티

  • 함수 객체의 arguments 프로퍼티 값은 arguments 객체임
  • arguments 객체는 함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한(iterable) 유사 배열 객체이며 함수 내부에서 지역 변수처럼 사용됨
    즉, 함수 외부에서는 참조할 수 없음
  • 함수 객체의 arguments 프로퍼티는 현재 일부 브라우저에서 지원하고 있지만 ES3부터 표준에서 폐지됨
    • 따라서 Function.arguments와 같은 사용법은 권장되지 않음 함수 내부에서 지역 변수처럼 사용할 수 있는 arguments 객체를 참조하도록 함
  • 자바스크립트는 함수의 매개변수와 인수의 개수가 일치하는지 확인하지 않음
    • 따라서 함수 호출 시 매개 변수 개수만큼 인수를 전달하지 않아도 에러가 발생하지 않음
  • 함수를 정의할 때 선언한 매개변수는 함수 몸체 내부에서 변수와 동일하게 취급됨
    • 함수가 호출되면 함수 몸체 내에서 암묵적으로 매개변수가 선언되고 undefined로 초기화된 이후 인수가 할당 됨
    • 선언된 매개변수의 개수보다 인수를 적개 전달했을 경우 인수가 전달되지 않은 매개변수는 undefined로 초기화된 상태를 유지하며 초과된 인수는 무시됨
    • 그렇다고 초과된 인수가 그냥 버려지는 것은 아니고 모든 인수는 암묵적으로 arguments 객체의 프로퍼티로 보관됨
    • 따라서 arguments 객체는 매개변수 개수를 확정할 수 없는 가변 인자 함수를 구현할 때 유용함
function sum() {
  let res = 0;
  
  // arguments 객체는 length 프로퍼티가 있는 유사 배열 객체이므로 for 문으로 순회할 수 있음
  for (let i = 0; i < arguments.length; i++) {
    res += arguments[i];
  }
  return res;
}
console.log(sum()); // 0
console.log(sum(1,2)); // 3
console.log(sum(1, 2, 3)); // 6
  • 유사 배열 객체느 배열이 아니므로 배열 메서드를 사용할 경우 에러가 발생함
    • 배열 메서드를 사용하려면 Function.prototype.call, Function.prototype.apply를 사용해 간접호출해야 하는 번거로움이 있음
  • 이러한 번거로움을 해결하기 위해 ES6에서는 Rest 파라미터를 도입함
    • Rest 파라미터의 도입으로 모던 자바스크립트에서는 arguments 객체의 중요성이 이전 같지는 않지만 언제나 ES6만 사용하지는 않을 수 있기 때문에 알아둘 필요가 있음

caller 프로퍼티

  • caller 프로 퍼티는 ECMAScript 사양에 포함되지 않는 비표준 프로퍼티이며 이후 표준화될 예정도 없으므로 사용하지 말고 참고로만 알아둘 것
  • 함수 객체의 caller 프로퍼티는 함수 자신을 호출한 함수를 가리킴
function foo(func) {
  return func();
}

function bar() {
  return 'caller': ' + bar.caller;
}

// 브라우저에서의 실행 결과
console.log(foo(bar)); // caller: function foo(func) {...}
console.log(bar()); // caller: null

length 프로퍼티

  • 함수 객체의 length 프로퍼티는 함수를 정의할 때 선언한 매개변수의 개수를 가리킴
  • arguments 객체의 length 프로퍼티와 함수 객체의 length 프로퍼티 값은 다를 수 있으므로 주의해야 함
  • arguments 객체의 length 프로퍼티는 인자(argument)의 객수를 가리키고, 함수 객체의 length 프로퍼티는 매개 변수(parameter)의 개수를 가리킴

name 프로퍼티

  • 함수 객체의 name 프로퍼티는 함수 이름을 나타냄
  • ES5와 ES6에서 동작을 달리하므로 주의가 필요함
    • 익명 함수 표현식의 경우 ES5에서 name 프로퍼티는 빈 문자열을 값으로 갖지만 ES6에서는 함수 객체를 가리키는 식별자를 값으로 가짐

__proto__ 접근자 프로퍼티

  • 모든 객체는 [[Prototype]]이라는 내부 슬롯을 가짐
  • [[Prototype]] 내부 슬롯은 객체지향 프로그래밍의 상속을 구현하는 프로토타입 객체를 가리킴
  • 내부 슬롯에는 직접 접근할 수 없고 간접적인 접근 방법을 제공하는 경우에 한하여 접근할 수 있음
  • [[Prototype]] 내부 슬롯에도 직접 접근할 수 없으며 __proto__ 접근자 프로퍼티를 통해 간접적으로 프로토타입 객체에 접근할 수 있음
const obj = { a: 1 };

// 객체 리터럴 방식으로 생성한 객체의 프로토타입 객체는 Object.prototype이다.
console.log(obj.__proto__ === Object.prototype); // true

//객체 리터럴 방식으로 생성한 객체는 프로토타입 객체인 Object.prototype의 프로퍼티를 상속받는다.
// hasOwnProperty 메서드는 Object.prototype의 메서드다.
console.log(obj.hasOwnProperty('a')); // true
console.log(obj.hasOwnProperty('__proto__') // false
  • hasOwnProperty 메서드는 이름에서 알 수 있듯이 인수로 전달받은 프로퍼티 키가 객체 고유의 프로퍼티 키인 경우에만 true를 반환하고 상속받은 프로토타입의 프로퍼티 키인 경우 false를 반환함

prototype 프로퍼티

  • prototype 프로퍼티는 생성자 함수로 호출할 수 있는 함수 객체, 즉 constructor만이 소유하는 프로퍼티임
  • 일반 객체와 생성자 함수로 호출할 수 없는 non-constructor에는 prototype 프로퍼티가 없음
 // 함수 객체는 prototype 프로퍼티를 소유한다.
(function () {}).hasOwnProperty('prototype'); // -> true

// 일반 객체는 prototype 프로퍼티를 소유하지 않는다.
({}).hasOwnProperty('prototype'); // -> false
  • prototype 프로퍼티는 함수가 객체를 생성하는 생성자 함수로 호출될 때 생성자 함수가 생성할 인스턴스의 프로토타입 객체를 가리킴

참고 자료

profile
아이디어와 구현을 좋아합니다!

0개의 댓글