[πŸ“– λͺ¨λ˜ μžλ°”μŠ€ν¬λ¦½νŠΈ λ”₯λ‹€μ΄λΈŒ] 18μž₯. ν•¨μˆ˜μ™€ 일급 객체

λ…Έμ˜μ™„Β·2023λ…„ 11μ›” 1일
0

JavaScript(Deep Dive)

λͺ©λ‘ 보기
13/23

ν•¨μˆ˜μ™€ 일급 객체

1. 일급 객체

❗ λ‹€μŒκ³Ό 같은 쑰건을 λ§Œμ‘±ν•˜λŠ” 객체λ₯Ό 일급 객체라고 ν•œλ‹€.

βœ” 무λͺ…μ˜ λ¦¬ν„°λŸ΄λ‘œ 생성할 수 μžˆλ‹€. 즉, λŸ°νƒ€μž„μ— 생성이 κ°€λŠ₯ν•˜λ‹€.
βœ” λ³€μˆ˜λ‚˜ 자료ꡬ쑰(객체, λ°°μ—΄ λ“±)에 μ €μž₯ν•  수 μžˆλ‹€.
βœ” ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ— 전달할 수 μžˆλ‹€.
βœ” ν•¨μˆ˜μ˜ λ°˜ν™˜ κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.

πŸ‘‰ μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ ν•¨μˆ˜λŠ” μœ„μ˜ 쑰건을 λͺ¨λ‘ λ§Œμ‘±ν•˜λ―€λ‘œ 일급 객체닀.

// 1. ν•¨μˆ˜λŠ” 무λͺ…μ˜ λ¦¬ν„°λŸ΄λ‘œ 생성할 수 μžˆλ‹€.
// 2. ν•¨μˆ˜λŠ” λ³€μˆ˜μ— μ €μž₯ν•  수 μžˆλ‹€.
// λŸ°νƒ€μž„(ν• λ‹Ή 단계)에 ν•¨μˆ˜ λ¦¬ν„°λŸ΄μ΄ ν‰κ°€λ˜μ–΄ ν•¨μˆ˜ 객체가 μƒμ„±λ˜κ³  λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.
const increase = function (num) {
  return ++num;
}

const decrease = function(num) {
  return --num;
}

// 2. ν•¨μˆ˜λŠ” 객체에 μ €μž₯ν•  수 μžˆλ‹€.
const auxs = {increase, decrease};

// 3. ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ— 전달할 수 μžˆλ‹€.
// 4. ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.
function makeCounter(aux) {
	let num = 0;
  
  	return function() {
	num = aux(num);
    return num
    };
}

// 3. ν•¨μˆ˜λŠ” λ§€κ°œλ³€μˆ˜μ—κ²Œ ν•¨μˆ˜λ₯Ό 전달할 수 μžˆλ‹€.
const increaser = makeCounter(auxs.increase);
console.log(increaser()); // 1
console.log(increaser()); // 2

// 3. ν•¨μˆ˜λŠ” λ§€κ°œλ³€μˆ˜μ—κ²Œ ν•¨μˆ˜λ₯Ό 전달할 수 μžˆλ‹€.
const decreaser = makeCounter(auxs.decrease);
console.log(decreaser()); // -1
console.log(decreaser()); // -2

ν•¨μˆ˜κ°€ 일급 κ°μ²΄λΌλŠ” 것은 ν•¨μˆ˜λ₯Ό 객체와 λ™μΌν• κ²Œ μ‚¬μš©ν•  수 μžˆλ‹€λŠ” 의미. 즉, κ°μ²΄λŠ” κ°’μ΄λ―€λ‘œ ν•¨μˆ˜λŠ” κ°’κ³Ό λ™μΌν•˜κ²Œ μ·¨κΈ‰.

ν•¨μˆ˜λŠ” 값을 μ‚¬μš©ν•  수 μžˆλŠ” κ³³(λ³€μˆ˜ ν• λ‹Ήλ¬Έ, 객체의 ν”„λ‘œνΌν‹° κ°’, λ°°μ—΄μ˜ μš”μ†Œ, ν•¨μˆ˜ 호좜의 인수, ν•¨μˆ˜ λ°˜ν™˜λ¬Έ)이라면 μ–΄λ””μ„œλ“ μ§€ λ¦¬ν„°λŸ΄λ‘œ μ •μ˜ν•  수 있으며 λŸ°νƒ€μž„μ— ν•¨μˆ˜ 객체둜 평가

일급 κ°μ²΄λ‘œμ„œ ν•¨μˆ˜κ°€ κ°€μž₯ κ°€μ§€λŠ” κ°€μž₯ 큰 νŠΉμ§•μ€
1. ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜μ— 전달할 수 μžˆλ‹€.
2. ν•¨μˆ˜μ˜ λ°˜ν™˜κ°’μœΌλ‘œ μ‚¬μš©ν•  수 μžˆλ‹€.


μ΄λŠ” ν•¨μˆ˜ν˜• ν”„λ‘œκ·Έλž˜λ°μ„ κ°€λŠ₯μΌ€ ν•˜λŠ” μžλ°”μŠ€ν¬λ¦½νŠΈμ˜ μž₯점 쀑 ν•˜λ‚˜

일반 객체 ν˜ΈμΆœν•  수 μ—†κ³ , ν•¨μˆ˜ κ°μ²΄λŠ” ν˜ΈμΆœν•  수 있으며 ν•¨μˆ˜ κ°μ²΄λŠ” 일반 κ°μ²΄μ—λŠ” μ—†λŠ” ν•¨μˆ˜ 고유의 ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ ν•œλ‹€.

2. ν•¨μˆ˜ 객체의 ν”„λ‘œνΌν‹°

ν•¨μˆ˜λŠ” κ°μ²΄μ΄λ―€λ‘œ ν”„λ‘œνΌν‹°λ₯Ό κ°€μ§ˆ 수 μžˆλ‹€. console.dir λ©”μ„œλ“œλ‘œ ν•¨μˆ˜ 객체의 ν”„λ‘œνΌν‹°λ₯Ό λ³Ό 수 μžˆλ‹€.

function square(number) {
  	return number * number
}

console.dir(square);

square ν•¨μˆ˜μ˜ λͺ¨λ“  ν”„λ‘œνΌν‹°μ˜ ν”„λ‘œνΌν‹° μ–΄νŠΈλ¦¬λ·°νŠΈλ₯Ό Object.getOwnPropertyDescriptors λ©”μ„œλ“œλ‘œ 확인할 수 μžˆλ‹€.

function square(number) {
  	return number * number
}

console.log(Object.getOwnPropertyDescriptors(square));

__proto__λŠ” square ν•¨μˆ˜μ˜ ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλ‹€. __proto__λŠ” Object.prototype 객체의 μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ‹€.

console.log(Object.getOwnPropertyDescriptor(square, '__proto__'));
// undefined

// square ν•¨μˆ˜λŠ” Object.prototype κ°μ²΄λ‘œλΆ€ν„° __proto__ μ ‘κ·Όμž ν”„λ‘œνΌν‹°λ₯Ό μƒμ†λ°›λŠ”λ‹€.
console.log(Object.getOwnPropertyDescriptor(Object.prototype, '__proto__'));

arguments call length name prototype ν”„λ‘œνΌν‹°λŠ” λͺ¨λ‘ ν•¨μˆ˜ 객체의 데이터 ν”„λ‘œνΌλ‹€. 이 ν”„λ‘œνΌν‹°λŠ” 일반 κ°μ²΄μ—λŠ” μ—†λŠ” ν•¨μˆ˜ 객체 고유의 ν”„λ‘œνΌν‹°

__proto__λŠ” μ ‘κ·Όμž ν”„λ‘œνΌν‹°μ΄λ©°, ν•¨μˆ˜ 객체 고유의 ν”„λ‘œνΌν‹°κ°€ μ•„λ‹ˆλΌ Object.prototype 객체의 ν”„λ‘œνΌν‹°λ₯Ό 상속받은 것을 μ•Œ 수 μžˆλ‹€.

2-1. arguments ν”„λ‘œνΌν‹°

ν•¨μˆ˜ 객체의 arguments ν”„λ‘œνΌν‹° 값은 arguments 객체닀. arguments κ°μ²΄λŠ” ν•¨μˆ˜ ν˜ΈμΆœμ‹œ μ „λ‹¬λœ μΈμˆ˜λ“€μ˜ 정보λ₯Ό λ‹΄κ³  μžˆλŠ” 순회 κ°€λŠ₯ν•œ μœ μ‚¬ λ°°μ—΄ 객체이며, ν•¨μˆ˜ λ‚΄λΆ€μ—μ„œ 지역 λ³€μˆ˜μ²˜λŸΌ μ‚¬μš©λœλ‹€. 즉, ν•¨μˆ˜ μ™ΈλΆ€μ—μ„œλŠ” μ°Έμ‘°ν•  수 μ—†λ‹€.

ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μ„ μ–Έν•œ λ§€κ°œλ³€μˆ˜λŠ” ν•¨μˆ˜ λͺΈμ²΄ λ‚΄λΆ€μ—μ„œ λ³€μˆ˜μ™€ λ™μΌν•˜κ²Œ μ·¨κΈ‰. 즉, ν•¨μˆ˜κ°€ 호좜되면 ν•¨μˆ˜ λͺΈμ²΄ λ‚΄μ—μ„œ μ•”λ¬΅μ μœΌλ‘œ λ§€κ°œλ³€μˆ˜κ°€ μ„ μ–Έλ˜κ³  undefined둜 μ΄ˆκΈ°ν™”λœ 이후 인수 ν• λ‹Ή.

πŸ’‘ arguments 객체의 Symbol(Symbol.iterator)ν”„λ‘œνΌν‹°

arguments 객체λ₯Ό 순회 κ°€λŠ₯ν•œ 자료ꡬ쑰인 μ΄ν„°λŸ¬λΈ”λ‘œ λ§Œλ“€κΈ° μœ„ν•œ ν”„λ‘œνΌν‹°λ‹€. Symbol.iteratorλ₯Ό ν”„λ‘œνΌν‹° ν‚€λ‘œ μ‚¬μš©ν•œ λ©”μ„œλ“œλ₯Ό κ΅¬ν˜„ν•˜λŠ” 것에 μ˜ν•΄ μ΄ν„°λŸ¬λΈ”μ΄ λœλ‹€.

function mulitply(x,y) {
  // μ΄ν„°λ ˆμ΄ν„°
  const iterator = arguments[Symbol.iterator]();

  // μ΄ν„°λ ˆμ΄ν„°μ˜ next λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ΄ν„°λŸ¬λΈ” 객체 arguments λ₯Ό 순회
 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;
}

multiply(1,2,3);

❗ arguments κ°μ²΄λŠ” λ§€κ°œλ³€μˆ˜ 개수λ₯Ό ν™•μ •ν•  수 μ—†λŠ” κ°€λ³€ 인자 ν•¨μˆ˜λ₯Ό κ΅¬ν˜„ν•  λ•Œ μœ μš©ν•˜λ‹€.

function sum() {
  let sum = 0;
  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

arguments κ°μ²΄λŠ” λ°°μ—΄ ν˜•νƒœλ‘œ 인자 정보λ₯Ό λ‹΄κ³  μžˆμ§€λ§Œ μ‹€μ œ 배열이 μ•„λ‹Œ μœ μ‚¬ λ°°μ—΄ 객체닀

πŸ’‘ μœ μ‚¬ λ°°μ—΄ 객체와 μ΄ν„°λŸ¬λΈ”

ES6μ—μ„œ λ„μž…λœ μ΄ν„°λ ˆμ΄μ…˜ ν”„λ‘œν† μ½œμ„ μ€€μˆ˜ν•˜λ©΄ 순회 κ°€λŠ₯ν•œ 자료ꡬ쑰인 μ΄ν„°λŸ¬λΈ”μ΄ λœλ‹€. ES5μ—μ„œ arguments κ°μ²΄λŠ” μœ μ‚¬ λ°°μ—΄ 객체둜 κ΅¬λΆ„λ˜μ—ˆμ§€λ§Œ μ΄ν„°λŸ¬λΈ”μ΄ λ„μž…λœ ES6λΆ€ν„° arguments κ°μ²΄λŠ” μœ μ‚¬ λ°°μ—΄ κ°μ²΄μ΄λ©΄μ„œ λ™μ‹œμ— μ΄ν„°λŸ¬λΈ”μ΄ λœλ‹€.

πŸ’‘ Rest νŒŒλΌλ―Έν„°

μœ μ‚¬ λ°°μ—΄ κ°μ²΄λŠ” 배열이 μ•„λ‹ˆλ―€λ‘œ λ°°μ—΄ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•  경우 μ—λŸ¬κ°€ λ°œμƒ. λ”°λΌμ„œ λ°°μ—΄ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λ €λ©΄ Function.prototype.call Function.prototype.applyλ₯Ό μ‚¬μš©ν•΄ κ°„μ ‘ ν˜ΈμΆœν•΄μ•Όν•˜λŠ” λ²ˆκ±°λ‘œμ›€μ΄ μžˆλ‹€.

μ΄λŸ¬ν•œ λ²ˆκ±°λ‘œμ›€μ„ ν•΄κ²°ν•˜κΈ° μœ„ν•΄ ES6μ—μ„œλŠ” Rest νŒŒλΌλ―Έν„°λ₯Ό λ„μž…ν–ˆλ‹€.

function sum() {
   // arguments 객체λ₯Ό λ°°μ—΄λ‘œ λ³€ν™˜
  const array = Array.prototype.slice.call(arguments);
  return array.reduce(function (pre, cur) {
    return pre + cur;
  }, 0);
}

console.log(sum(1,2)) // 3
console.log(sum(1,2,3,4,5)); // 15
function sum(...args) {
  return args.reduce((pre,cur) =>  pre + cur, 0);
}

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

2.2 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

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

ν•¨μˆ˜ 객체의 length ν”„λ‘œνΌν‹°λŠ” ν•¨μˆ˜λ₯Ό μ •μ˜ν•  λ•Œ μ„ μ–Έν•œ λ§€κ°œλ³€μˆ˜μ˜ 개수λ₯Ό 가리킨닀.

function foo() {}
console.log(foo.length); // 0

function bar(x) {
	return x;
}
console.log(bar.length); // 1

function baz(x, y) {
	return x * y;
}
console.log(baz.length)

arguments 객체의 length ν”„λ‘œνΌν‹°μ™€ ν•¨μˆ˜ 객체의 length ν”„λ‘œνΌν‹°μ˜ 값은 λ‹€λ₯Ό 수 μžˆμœΌλ―€λ‘œ 주의

arguments 객체의 length ν”„λ‘œνΌν‹°λŠ” 인자의 개수λ₯Ό 가리킀고, ν•¨μˆ˜μ˜ 객체의 length ν”„λ‘œνΌν‹°λŠ” λ§€κ°œλ³€μˆ˜μ˜ 개수λ₯Ό 가리킨닀.

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

ν•¨μˆ˜ 객체의 name ν”„λ‘œνΌν‹°λŠ” ν•¨μˆ˜μ΄λ¦„μ„ λ‚˜νƒ€λ‚Έλ‹€. name ν”„λ‘œνΌν‹°λŠ” ES6 μ΄μ „κΉŒμ§€λŠ” λΉ„ν‘œμ€€μ΄μ—ˆλ‹€κ°€ ES6μ—μ„œ 정식 ν‘œμ€€μ΄ λ˜μ—ˆλ‹€.

name ν”„λ‘œνΌν‹°λŠ” ES5와 ES6μ—μ„œ λ™μž‘μ„ λ‹¬λ¦¬ν•˜λ―€λ‘œ μ€‘μ˜ 읡λͺ… ν•¨μˆ˜ ν‘œν˜„μ‹μ˜ 경우 ES5μ—μ„œ name ν”„λ‘œνΌν‹°λŠ” 빈 λ¬Έμžμ—΄ κ°’μœΌλ‘œ κ°–κ³  ES6μ—μ„œλŠ” ν•¨μˆ˜ 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” μ‹λ³„μžλ₯Ό κ°’μœΌλ‘œ κ°–λŠ”λ‹€.

// κΈ°λͺ… ν•¨μˆ˜ ν‘œν˜„μ‹
var namedFunc = function foo() {};
console.log(namedFunc.name); // foo

// 읡λͺ… ν•¨μˆ˜ ν‘œν˜„μ‹
var annoymousFunc = function() {};
// ES5: name ν”„λ‘œνΌν‹°λŠ” 빈 λ¬Έμžμ—΄μ„ κ°’μœΌλ‘œ κ°–λŠ”λ‹€.
// ES6: name ν”„λ‘œνΌν‹°λŠ” ν•¨μˆ˜ 객체λ₯Ό κ°€λ¦¬ν‚€λŠ” λ³€μˆ˜ 이름을 κ°’μœΌλ‘œ κ°–λŠ”λ‹€.
console.log(annoymousFunc.name); // annoymousFunc

// ν•¨μˆ˜ μ„ μ–Έλ¬Έ(Function declaration)
function bar() {}
console.log(bar.name_; // bar

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

λͺ¨λ“  κ°μ²΄λŠ” [[Prototype]]μ΄λΌλŠ” λ‚΄λΆ€ μŠ¬λ‘―μ„ κ°–λŠ”λ‹€. [[Prototype]] λ‚΄λΆ€ μŠ¬λ‘―μ€ 객체지ν–₯ ν”„λ‘œκ·Έλž˜λ°μ˜ 상속을 κ΅¬ν˜„ν•˜λŠ” ν”„λ‘œν† νƒ€μž… 객체λ₯Ό 가리킨닀.

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

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 λ©”μ„œλ“œ

hasOwnProperty λ©”μ„œλ“œλŠ” μ΄λ¦„μ—μ„œ μ•Œ 수 μžˆλ“―μ΄ 인수둜 전달받은 ν”„λ‘œνΌν‹° ν‚€κ°€ 객체 고유의 ν”„λ‘œνΌν‹° 킀인 κ²½μš°μ—λ§Œ trueλ₯Ό λ°˜ν™˜ν•˜κ³  μƒμ†λ°›λŠ” ν”„λ‘œν† νƒ€μž…μ˜ ν”„λ‘œνΌν‹° 킀인 경우 falseλ₯Ό λ°˜ν™˜

2-6. prototype ν”„λ‘œνΌν‹°

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

prototype ν”„λ‘œνΌν‹°λŠ” ν•¨μˆ˜κ°€ 객체λ₯Ό μƒμ„±ν•˜λŠ” λ™μ•ˆ μƒμ„±μž ν•¨μˆ˜λ‘œ 호좜될 λ•Œ μƒμ„±μž ν•¨μˆ˜κ°€ 생성할 μΈμŠ€ν„΄μŠ€μ˜ ν”„λ‘œν† νƒ€μž… 객체λ₯Ό 가리킨닀.

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

// 일반 κ°μ²΄λŠ” prototype ν”„λ‘œνΌν‹°λ₯Ό μ†Œμœ ν•˜μ§€ μ•ŠλŠ”λ‹€.
({}).hasOwnProperty('prototype') // fasle

0개의 λŒ“κΈ€