본문 바로가기
Frontend/JavaScript

[JavaScript] 함수와 일급 객체

by 모너아링 2022. 11. 8.

일급 객체

일급 객체의 조건

  1. 익명 리터럴을 런타임에 생성 가능
  2. 변수나 자료구조에 저장 가능
//변수
const foo = function() {
	console.log("foo");
}

const bar = function() {
	console.log("bar");
}

foo(); //foo
bar(); //bar

//객체
const obj = { foo, bar };

console.log(obj); //{ foo: [Function: foo], bar: [Function: bar] }

//배열
const arr = [foo, bar];
console.log(arr[0]); //[Function: foo]

3. 함수의 매개변수에 전달 가능

function sayHello() {
   return "Hello, ";
}
function greeting(helloMessage, name) {
  console.log(helloMessage() + name);
}
// sayHello를 greeting 함수에 인자로 전달
greeting(sayHello, "JavaScript!");

4. 함수의 반환 값으로 사용 가능

function sayHello() {
   return function() {
      console.log("Hello!");
   }
}

  • 익명 함수 호출
//반환된 함수 다른 변수에 저장
const sayHello = function() {
	return function() {
		console.log("Hello!");
	}
}
const myFunc = sayHello();
myFunc();
  • sayHello 를 직접 호출하면, 반환된 함수를 호출하지 않고 함수 자체를 반환
  • 따라서 다른 변수에 저장하여 사용
//이중 괄호 사용
function sayHello() {
	return function() {
		console.log("Hello!");
	}
}
sayHello()();

함수 객체의 프로퍼티

  • 일반 객체에 없는 함수 객체 고유의 프로퍼티
  • __proto__ 는 예외적으로 함수 객체 고유의 프로퍼티가 아니라 Object.prototype 객체의 프로퍼티를 상속받는다.
function square(number) { return number * number; }

//square 함수의 프로퍼티 어트리뷰트 확인
console.log(Object.getOwnPropertyDescriptors(square));
/*
{
	length: {value: 1, writable: false, enumerable: false, configurable: true},
	name: {value: "square", writable: false, enumerable: false, configurable: true},
	arguments: {value: null, writable: false, enumerable: false, configurable: false},
	caller: {value: null, writable: false, enumerable: false, configurable: false},
	prototype: {value: {...}, writable: true, enumerable: false, configurable: false}

}
*/

//__proto__는 함수의 프로퍼티가 아니라 Object.prototype 객체의 접근자 프로퍼티
console.log(Object.getOwnPropertyDescriptors(square, '__proto__')); // undefined

arguments 프로퍼티

function func1(a, b, c) {
    console.log(arguments[0]);
    console.log(arguments[1]);
    console.log(arguments[2]);
}
func1(1, 2, 3);
func1(1, 2);
func1(1, 2, 3, 4);
  • 함수 호출 시 전달된 인수들의 정보를 담고 있는 순회 가능한 유사 배열 객체
  • 함수 내부에서 지역 변수처럼 사용 가능
  • 매개변수 개수와 인수 개수가 달라도 에러가 발생하지 않는다.
    • 매개변수 개수 > 인수 개수: undefined 초기화
    • 매개변수 개수 < 인수 개수: 초과된 인수 무시
  • 유사 배열 객체이므로 for 문으로 순회 가능

구성

arguments.callee

  • 현재 실행 중인 함수
  • ES5 에서는 strict mode 에서의 사용을 금지

arguments.length

  • 함수에 전달된 인수의 수
  • 가변 인자 함수를 구현할 때 유용
//가변 인자 함수
function sum() {
	let res = 0;

	for(let i = 0; i < arguments.length; i++){
		res += arguments[i]
	}
	return res;
}
console.log(sum());
console.log(sum(1, 2));
console.log(sum(1, 2, 3));

arguments.Symbol

  • arguments 객체를 순회 가능한 자료구조인 이터러블로 만들기 위한 프로퍼티
function multiply(x, y) {
	const iterator = arguments[Symbol.iterator]();

	console.log(iterator.next()); // {value: 1, done: false}
	console.log(iterator.next()); // {value: 2, done: false}
	console.log(iterator.next()); // {value: 3, done: false}
	console.log(iterator.next()); // {value: undefined, done: true}
	
	return x * y;
}
console.log(multiply(1, 2, 3));

유사 배열 객체

  • 배열처럼 보이지만 key가 숫자이고, length 값을 가지고 있는 객체
  • 배열 메서드를 사용할 수 없다.
//배열
array = [1, 2, 3];
array.forEach(function (el) { console.log(el); }); // 1, 2, 3

//유사 배열 객체
notArray = { 
    0: 'Hi',
    1: 'My',
    2: 'name',
}

console.log(notArray[0]); //Hi
console.log(notArray[0].length); //2

console.log(notArray.length);
notArray.forEach(function (el) { console.log(el); }); // Error

배열로 만들려면?

  • Array.from()
    • 유사 배열 객체나 반복 가능 객체의 value를 얕은 복사해서 배열로 만드는 메서드
    console.log(Array.from('foo')); // Array ["f", "o", "o"]
    console.log(Array.from([1, 2, 3], x => x + x)); //Array [2, 4, 6]

 

배열 메서드를 사용하고 싶다면?

  • Function.prototype.apply
function.apply(thisArg, argsArray)
  • thisArg 를 this 객체에 바인딩하고 전달 받은 인자를 arguments 에 설정한 후 해당 함수 호출
  • arguments 를 배열로 전달
  • strict mode 가 아닌 경우 null 과 undefined 가 전역 객체로 대체

반환 값

  • 지정된 this 값과 인수로 함수를 호출한 결과
Math.max(5, 6, 2, 3, 7);

var numbers = [5, 6, 2, 3, 7];
Math.max.apply(null, numbers); //7

 

  • Function.prototype.bind
function.bind(thisArg, arg1, arg2, ...)
  • 첫 번째 인자를 this 에 바인딩하고, 두 번째 인자부터 arguments 를 순서대로 전달
  • 전달된 arguments 를 미리 부분 적용한 함수를 리턴
  • Function.prototype.call
function.call(thisArg, arg1, arg2, ...)
  • thisArg 를 this 객체에 바인딩하고 전달 받은 인자를 arguments 에 설정한 후 해당 함수 호출
  • arguments 를 순서대로 전달

caller 프로퍼티

  • 지정된 함수를 호출한 함수를 반환
  • strict mode 에서는 오류 발생
  • 웹 표준에서 이미 제거된 프로퍼티. 사용 권장하지 않음
function foo(func) {
	return func();
}

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

console.log(foo(bar)); // caller: function foo(func) {...}
console.log(bar()); // caller: null
  • foo(bar) 에서 bar 함수를 호출한 함수는 foo 이므로 caller: foo
  • bar() 에서 bar 함수를 호출한 함수는 존재하지 않으므로 null

length 프로퍼티

  • 함수를 정의할 때 선언한 매개변수의 개수

arguments.length vs Function.length

  • arguments.length
//인자의 개수를 가리킴
function func1(a, b) {
	console.log(arguments.length); // 2
	return a * b;
}
  • Function.length
//매개 변수의 개수를 가리킴
function func1() {}
function func2(a) {}
function func3(a, b) {}

console.log(func1.length); // 0
console.log(func2.length); // 1
console.log(func3.length); // 2
  1. Writable(변경 가능): no
  2. Enumerable(열거 가능): no
  3. Configurable(재정의 가능): yes

name 프로퍼티

  • 함수 이름
  • 익명 함수의 경우 함수 객체를 가리키는 변수 이름을 값으로 가짐
//기명함수
var namedFunc = function foo() {};
console.log(namedFunc.name); // foo

//익명함수
var anonymousFunc = function() {};
console.log(anonymousFunc.name); // anonymousFunc

__proto__ 접근자 프로퍼티

  • 내부 슬롯이 가리키는 프로토타입([[Prototype]] 내부 슬록) 에 간접적으로 접근하기 위해 사용하는 접근자 프로퍼티
  • 사용 이유는 상호 참조에 의해 프로토타입 체인이 생성되는 것을 방지
  • 객체 리터럴 방식으로 생성한 객체는 프로토타입 객체인 Object.prototype 을 상속받는다.
  • hasOwnProperty 메서드는 Object.prototype의 메서드이다.
const obj = { a: 1 };

console.log(obj.__proto__ === Object.prototype);

//해당 인수가 객체 고유의 프로퍼티 키인 경우 true
//상속받은 프로토타입의 프로퍼티 키인 경우 false
console.log(obj.hasOwnProperty('a')); //true
console.log(obj.hasOwnProperty('__proto__')); //false

hasOwnProperty()

  • 객체가 특정 프로퍼티를 가지고 있는지 여부를 나타내는 메서드

__proto__ 대신 사용할 수 있는 메서드

1. Object.create(proto, [descriptors])

  • [[Prototype]] 이 proto 를 참조하는 빈 객체를 만든다.

2. getPrototypeOf(obj)

  • __proto__ 에서 대체된 메서드
  • 지정된 객체의 [[Prototype]]를 반환
  • 매개변수가 객체가 아닌 경우 에러가 발생

3. Object.setPrototypeOf(obj, proto)

  • 지정된 객체의 [[Prototype]] 이 proto 가 되도록 설정
let animal = {
	eats: true
};

// 프로토타입이 animal인 새로운 객체를 생성
let rabbit = Object.create(animal);

console.log(rabbit.eats); // true
console.log(Object.getPrototypeOf(rabbit) === animal); //true

Object.setPrototypeOf(rabbit, {}); // rabbit의 prototype을 {}로 바꾼다.

prototype 프로퍼티

  • 생성자 함수로 호출할 수 있는 함수 객체
  • constructor 만이 소유하는 프로퍼티
  • 함수 객체가 생성자로 사용될 때 이 함수를 통해 생성될 객체의 프로토타입 객체를 가리킨다.
  1. Writable(변경 가능): yes
  2. Enumerable(열거 가능): no
  3. Configurable(재정의 가능): no
//함수 객체(constructor)
(function () {}).hasOwnProperty('prototype'); // true

//일반 객체(non-constructor)
({}).hasOwnProperty('prototype'); //false
let animal = {
	eats: true
};

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

Rabbit.prototype = animal;

let rabbit = new Rabbit("White Rabbit");
// rabbit.__proto__ == animal

 

 

'Frontend > JavaScript' 카테고리의 다른 글

[JavaScript] 제너레이터와 async/await  (0) 2023.02.16
[JavaScript] DOM 이벤트  (0) 2023.02.16
[JavaScript] Set  (2) 2023.02.16
[JavaScript] 이터러블  (1) 2023.02.16
[JavaScript] 객체 리터럴  (1) 2022.11.08