[Javascript] 일급 객체, ν•¨μˆ˜μ˜ ν”„λ‘œνΌν‹°

πŸ“¦μΌκΈ‰ κ°μ²΄λž€?

 

1. 무λͺ…μ˜ λ¦¬ν„°λŸ΄λ‘œ 생성할 수 μžˆλ‹€ = λŸ°νƒ€μž„μ— 생성이 κ°€λŠ₯ν•˜λ‹€.

2. λ³€μˆ˜λ‚˜ 자료ꡬ쑰(객체, λ°°μ—΄ λ“±)에 μ €μž₯ν•  수 μžˆλ‹€.

3. ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ— 전달할 수 μžˆλ‹€.

4. ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

 

μ—¬κΈ°μ„œ 1번 쑰건의 말이 μ–΄λ €μš΄λ° λŸ°νƒ€μž„μ— μƒμ„±λœλ‹€λŠ” 건

μ •μ μœΌλ‘œ μ½”λ“œμ— μž‘μ„±λœ ν•¨μˆ˜κ°€ μ•„λ‹ˆλΌ, ν”„λ‘œκ·Έλž¨μ΄ μ‹€ν–‰λ˜λŠ” λ™μ•ˆ ν•„μš”ν•  λ•Œ μƒˆλ‘œμš΄ ν•¨μˆ˜λ₯Ό λ§Œλ“€μ–΄ λ‚Ό 수 μžˆλ‹€λŠ” 것.

// μ‚¬μš©μž μž…λ ₯을 λ°›μ•„μ„œ 그에 λ§žλŠ” 인사 ν•¨μˆ˜λ₯Ό μƒμ„±ν•˜λŠ” 경우
function createGreeting(name) {
    // μ—¬κΈ° ν•¨μˆ˜κ°€ λŸ°νƒ€μž„μ— μƒμ„±λ˜λŠ” λΆ€λΆ„
    return function() {
        console.log(`μ•ˆλ…•ν•˜μ„Έμš”, ${name}λ‹˜!`);
    };
}

// ν”„λ‘œκ·Έλž¨ μ‹€ν–‰ 쀑에 μ‚¬μš©μž μž…λ ₯을 λ°›μ•˜λ‹€κ³  κ°€μ •ν–ˆμ„ λ•Œ
const userName = "좘배";  // μ‚¬μš©μž μž…λ ₯
const greeting = createGreeting(userName);  // μ—¬κΈ°μ„œ μƒˆλ‘œμš΄ ν•¨μˆ˜κ°€ 생성됨

greeting(); // "μ•ˆλ…•ν•˜μ„Έμš”, μΆ˜λ°°λ‹˜!" 좜λ ₯

 

 

Javascript의 ν•¨μˆ˜λŠ” μœ„μ˜ 4쑰건을 λͺ¨λ‘ λ§Œμ‘±ν•˜λ―€λ‘œ, 일급객체라고 ν•  수 μžˆλ‹€. 즉, 객체둜 μ‚¬μš©ν•  수 μžˆλ‹€.

 

ν•¨μˆ˜ = 일급 κ°μ²΄μ΄λ―€λ‘œ ν•  수 μžˆλŠ” 것

  • ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ° κ°€λŠ₯ (map, filter, reduceλ“±)
  • ν΄λ‘œμ € κ΅¬ν˜„ κΈ°λŠ₯(데이터 μΊ‘μŠν™”μ™€ 정보 은닉)
  • 콜백 νŒ¨ν„΄ κ΅¬ν˜• κ°€λŠ₯(비동기 처리, 이벀트 처리)
  • κ³ μ°¨ ν•¨μˆ˜ κ΅¬ν˜„ κ°€λŠ₯(ν•¨μˆ˜λ₯Ό 인자둜 λ°›κ±°λ‚˜ λ°˜ν™˜)

 

ν•˜μ§€λ§Œ, 차이점도 μ‘΄μž¬ν•œλ‹€.

  • 일반 객체: 호좜 λΆˆκ°€λŠ₯
  • ν•¨μˆ˜: 호좜 κ°€λŠ₯, ν•¨μˆ˜ 고유의 ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ ν•¨

μ—¬κΈ°μ„œ ν•¨μˆ˜μ˜ ν”„λ‘œνΌν‹°λž€?

 

πŸ”Žν•¨μˆ˜μ˜ ν”„λ‘œνΌν‹°

ν•¨μˆ˜μ˜ ν”„λ‘œνΌν‹°κ°€ 뭔지 μ•Œμ•„λ³΄κΈ° μ „,

객체의 λͺ¨λ“  속성을 λ³΄μ—¬μ£ΌλŠ” ν•¨μˆ˜μΈ console.dirν•¨μˆ˜λ₯Ό μ΄μš©ν•΄μ„œ ν•¨μˆ˜ ν•˜λ‚˜λ₯Ό λœ―μ–΄λ³΄μž

κ°„λ‹¨ν•œ ν•¨μˆ˜λ₯Ό ν•˜λ‚˜ λ§Œλ“€κ³ , console.dir둜 λœ―μ–΄λ³΄μž
κ²°κ³Ό 값이 μ΄λ ‡κ²Œ λ‚˜μ˜΄
쑰금 더 μžμ„Ένžˆ 보기 μœ„ν•΄ Object.getOwnPropertyDescriptors λ©”μ„œλ“œ μ‚¬μš©

 

μœ„μ˜ 두 κ²°κ³Ό κ°’μ—μ„œ 확인할 수 μžˆλŠ” arguments, caller, length, name, prototype은 ν•¨μˆ˜ 객체의 데이터 ν”„λ‘œνΌν‹°μ΄λ‹€.

이 ν”„λ‘œνΌν‹°λ“€μ€ 일반 κ°μ²΄μ—μ„œλŠ” μ—†λŠ” ν•¨μˆ˜ 객체 고유의 ν”„λ‘œνΌν‹°μ΄λ‹€.

각각의 ν”„λ‘œνΌν‹°κ°€ 무엇을 μ˜λ―Έν•˜λŠ”μ§€ ν•˜λ‚˜ν•˜λ‚˜ λœ―μ–΄λ³΄μž

 

arguments ν”„λ‘œνΌν‹°

ν•¨μˆ˜ 호좜 μ‹œ μ „λ‹¬λœ μΈμˆ˜λ“€μ˜ 정보λ₯Ό λ‹΄κ³  μžˆλŠ” iterableν•œ μœ μ‚¬ λ°°μ—΄ 객체이닀.

그리고, ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ μ‚¬μš©λ˜λ―€λ‘œ μ™ΈλΆ€μ—μ„œλŠ” μ°Έμ‘°ν•  수 μ—†λ‹€.

ν™•μΈν•΄λ³΄μž

 

직접 argumentsλ₯Ό 찍어보면 μ „λ‹¬λœ 인수λ₯Ό 확인할 수 μžˆλ‹€.

λ§Œμ•½ μΈμˆ˜κ°€ μ—¬λŸ¬κ°œμΈλ°, 정해진 μΈμˆ˜λ³΄λ‹€ 적게 μ „λ‹¬λ˜λ©΄ undefined둜 μœ μ§€ν•˜κ³ ,

더 λ§Žλ‹€λ©΄ 초과된 것은 κ²°κ³Όμ—μ„œλŠ” λ¬΄μ‹œν•˜μ§€λ§Œ arguments의 ν”„λ‘œνΌν‹°λ‘œ λ³΄κ΄€λ˜κΈ΄ ν•œλ‹€.

λΆ€μ‘±ν•˜κ²Œ μ „λ‹¬λ˜λ©΄ ν•œκ°œλ§Œ μ €μž₯됨
μ΄ˆκ³Όν•˜λ©΄ argumentsμ—λŠ” λ“€μ–΄κ°€μ§€λ§Œ, 결과값에선 λ¬΄μ‹œ

 

argumentsλŠ” iterableν•œ μœ μ‚¬ λ°°μ—΄ κ°μ²΄μ΄λ―€λ‘œ, 이λ₯Ό μ΄μš©ν•΄ κ°€λ³€ 인자 ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•˜λ‹€.

function sum() {
	let res = 0
    
    // iterableν•˜λ―€λ‘œ 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

 

ν•˜μ§€λ§Œ μœ μ‚¬ λ°°μ—΄ 객체일 뿐, μ§„μ§œ 배열은 μ•„λ‹ˆλ―€λ‘œ λ°°μ—΄ λ©”μ„œλ“œλŠ” μ‚¬μš©ν•  수 μžˆλ‹€.

κ·Έλž˜μ„œ ꡳ이 λ°°μ—΄λ‘œ λ°”κΏ”μ„œ μ‚¬μš©ν•˜λ €λ©΄

(1) 객체λ₯Ό λ°°μ—΄λ‘œ λ³€ν™˜ν•˜λŠ” 방법

(2) ES6에 λ„μž…λœ Rest νŒŒλΌλ―Έν„° μ‚¬μš©(26μž₯μ—μ„œ 배울 μ˜ˆμ •μ΄λž˜μš”)

// 1번 방법
const arr = Array.prototype.slice.call(arguments)

// 2번 방법
function sum(...arg) {
	return arg.reduce((pre, cur) => pre + cur, 0)
}

 

caller ν”„λ‘œνΌν‹°

= ν•¨μˆ˜ μžμ‹ μ„ ν˜ΈμΆœν•œ ν•¨μˆ˜

ECMAScript 사양에 ν¬ν•¨λ˜μ§€ μ•Šμ€ λΉ„ν‘œμ€€ ν”„λ‘œνΌν‹°μ΄λ―€λ‘œ 참고둜만 μ•Œμ•„λ‘μž

downμ—μ„œ callerλ₯Ό 찍으면 μžμ‹ μ„ ν˜ΈμΆœν•œ up이 λ‚˜μ˜΄μ„ 확인 κ°€λŠ₯

 

length ν”„λ‘œνΌν‹°

= ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μ„ μ–Έν•œ λ§€κ°œλ³€μˆ˜μ˜ 개수

function temp1() {
	return temp1.length
}
console.log(temp1())    // 0

function temp2(arg1, arg2, arg3) {
	return temp2.length
}
console.log(temp2())    // 3

 

이 λ•Œ, arguments의 length ν”„λ‘œνΌν‹°μ™€λŠ” λ‹€λ₯΄λ‹€.

function temp(arg) {
  // temp.lengthλŠ” arg의 갯수 = 1
  console.log(temp.length)         // 1
    
    // arguments.lengthλŠ” λ“€μ–΄μ˜¨ 인수의 개수 = 4
    console.log(arguments.length)  // 4
}

temp(1, 2, 3, 4)

 

 

name ν”„λ‘œνΌν‹°

= ν•¨μˆ˜ 이름

ES6 μ΄μ „μ—λŠ” λΉ„ν‘œμ€€μ΄μ—ˆμ§€λ§Œ, ES6μ—μ„œ 정식 ν‘œμ€€μ΄ λ˜μ—ˆμŒ

κ·Έλž˜μ„œ ES5 μ΄μ „μ—μ„œλŠ” 읡λͺ… ν•¨μˆ˜μ—μ„œλŠ” 빈 λ¬Έμžμ—΄μ„ 가짐 / ES6λŠ” ν•¨μˆ˜ 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μžλ₯Ό κ°’μœΌλ‘œ 가짐

// 이름이 μžˆλŠ” ν•¨μˆ˜μ—μ„œλŠ” 이름이 κ·ΈλŒ€λ‘œ 좜λ ₯
let κΈ°λͺ…ν•¨μˆ˜ = function temp() {}
console.log(κΈ°λͺ…ν•¨μˆ˜.name)    // temp

// 읡λͺ…ν•¨μˆ˜μ—μ„œλŠ” ν•΄λ‹Ή ν•¨μˆ˜λ₯Ό κ°€λ₯΄ν‚€λŠ” λ³€μˆ˜μ΄λ¦„μ„ 좜λ ₯(ES6)
let 읡λͺ…ν•¨μˆ˜ = function() {}
console.log(읡λͺ…ν•¨μˆ˜.name)    // 읡λͺ…ν•¨μˆ˜

// ν•¨μˆ˜ μ„ μ–Έλ¬Έ
function μ„ μ–Έλœν•¨μˆ˜() {}
console.log(μ„ μ–Έλœν•¨μˆ˜.name)   // μ„ μ–Έλœν•¨μˆ˜

 

 

__proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°

λͺ¨λ“  κ°μ²΄λŠ” [[Prototype]]μ΄λΌλŠ” λ‚΄λΆ€ μŠ¬λ‘―μ„ 가짐

( = 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ 상속을 κ΅¬ν˜„ν•˜λŠ” ν”„λ‘œν† νƒ€μž… 객체, 19μž₯μ—μ„œ μ•Œμ•„λ³΄μž)

__proto__λŠ” [[Prototype]] λ‚΄λΆ€ 슬둯이 κ°€λ¦¬ν‚€λŠ” ν”„λ‘œν† νƒ€μž… 객체에 μ ‘κ·Όν•˜κΈ° μœ„ν•΄ μ‚¬μš©λ˜λŠ” μ ‘κ·Όμž ν”„λ‘œνΌν‹°μž„

 

prototype ν”„λ‘œνΌν‹°

μƒμ„±μž ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•  수 μžˆλŠ” ν•¨μˆ˜ 객체(= constructor)만이 μ†Œμœ ν•˜λŠ” ν”„λ‘œνΌν‹°

일반 객체와 μƒμ„±μž ν•¨μˆ˜λ‘œ ν˜ΈμΆœν•  수 μ—†λŠ” non-constructorμ—λŠ” prototype ν”„λ‘œνΌν‹°κ°€ μ—†μŒ

// ν•¨μˆ˜ κ°μ²΄λŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ 
(function () {}).hasOwnProperty('prototype')   // true

// 일반 κ°μ²΄λŠ” μ—†μŒ
({}).hasOwnProperty('prototype')     // false

 

 

더보기

__proto__와 prototype이 이해가 μ•ˆλ˜μ„œ ν΄λ‘œλ“œκ°€ μ•Œλ €μ€€ μ˜ˆμ‹œ..(참고용)

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

// 1. prototype ν”„λ‘œνΌν‹° μ‚¬μš©
Dog.prototype.bark = function() {
    console.log('멍멍!');
};

const dog1 = new Dog('뽀삐');
const dog2 = new Dog('μ½”μ½”');

// 2. __proto__λ₯Ό ν†΅ν•œ λ©”μ„œλ“œ μ ‘κ·Ό
dog1.bark();  // "멍멍!" 좜λ ₯
dog2.bark();  // "멍멍!" 좜λ ₯

// 3. ν”„λ‘œν† νƒ€μž… 체인 확인
console.log(dog1.__proto__ === Dog.prototype);         // true
console.log(dog1.__proto__.__proto__ === Object.prototype);  // true
console.log(dog1.__proto__.__proto__.__proto__);      // null

// 4. ν•¨μˆ˜μ˜ ν”„λ‘œν† νƒ€μž… 체인
console.log(Dog.__proto__ === Function.prototype);     // true
console.log(Dog.__proto__.__proto__ === Object.prototype);   // true

 

μ‹œκ°μ μœΌλ‘œ 보면

// 객체와 ν”„λ‘œν† νƒ€μž…μ˜ 관계
Dog (μƒμ„±μž ν•¨μˆ˜)
β”œβ”€β”€ prototype: Dog.prototype
β”‚   β”œβ”€β”€ constructor: Dog
β”‚   β”œβ”€β”€ bark: function
β”‚   └── __proto__: Object.prototype
└── __proto__: Function.prototype

dog1 (μΈμŠ€ν„΄μŠ€)
β”œβ”€β”€ name: "뽀삐"
└── __proto__: Dog.prototype

 

μ—¬κΈ°μ„œ prototype은 ν•¨μˆ˜λ§Œ 가지고 있음