이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

게시글

강좌19 - JavaScript - 2년 전 등록 / 9일 전 수정

Object 객체

조회수:
0
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ
이 블로그는 광고 클릭 수익으로 운영됩니다!
괜찮으시다면 광고 차단을 풀어주세요 ㅠㅠ

안녕하세요. 중급 강좌 첫 번째 시간이네요! 자바스크립트는 객체 지향 프로그래밍 언어이니만큼 Object 객체에 대해 알아보겠습니다. Object가 객체이니까 Object 객체는 객체 객체이겠네요! 사실 Object 그 자체도 객체입니다. 모든 객체의 최종 prototype이기도 하죠.

예시를 하나 들어 객체의 prototype이 뭔지 볼까요? 이미 구현된 객체의 prototype을 확인할 때는 __proto__를 사용합니다.

Math.__proto__; // Object { ... }

네 바로 Object 객체입니다. 생성자를 통해 만든 객체의 prototype의 prototype도 Object 객체입니다.

function Person(name) { this.name = name; }
Person.prototype.sayHello = function() {
  alert(this.name);
};
var zero = new Person('zero');
zero.__proto__; // { sayHello: function() }
zero.__proto__.__proto__; // Object { ... }

그렇다면 Object 객체 자체의 prototype은 뭘까요?

Math.__proto__.__proto__; // null

네 없습니다. Object가 최종이기 때문이죠. Object 객체의 생성자는 window 객체에 저장되어 있습니다. 모든 객체가 Object 객체로부터 상속받기 때문에 모든 객체는 Object 객체의 메소드들을 사용할 수 있습니다.

Object

객체.hasOwnProperty(속성명)

객체의 속성이 상속받지 않은 속성인지 알려줍니다. 자신의 속성이면 true, 부모의 속성이거나 아예 속성이 아니면 false를 반환합니다.

var obj = {
  example: 'yes',
};
obj.example; // yes
obj.hasOwnProperty('example'); // true
obj.toString; // function toString() { [native code] }
obj.hasOwnProperty('toString'); // false

객체.isPrototypeOf(대상)

객체가 대상의 조상인지 알려줍니다.

var GrandParent = function() { };

var Parent = function() { };
Parent.prototype = new GrandParent();

var Child = function() { };
Child.prototype = new Parent();

var child = new Child();
Parent.prototype.isPrototypeOf(child); // true
GrandParent.prototype.isPrototypeOf(child); // true

Object.getPrototypeOf(객체), Object.setPrototypeOf(객체, prototype)

객체의 prototype을 조회하거나 설정할 수 있습니다.

Object.getPrototypeOf(child); // GrandParent
Object.getPrototypeOf(new GrandParent()); // 빈 객체 { }
Object.setPrototypeOf(child, new Parent());

instanceof

객체가 특정 생성자의 자식인지 조회할 수 있습니다.

child instanceof Parent; // true
child instanceof GrandParent; // true

객체.propertyIsEnumerable(속성)

해당 속성이 열거 가능한 속성인지 알려줍니다. 열거 가능이란 for ... in과 같은 반복문 안에서 쓸 수 있는지를 말합니다. 상속받은 속성과 해당 객체의 속성이 아닌 것은 기본적으로 제외됩니다.

var a = [false, 1, '2'];
a.propertyIsEnumerable(0); // true
a.propertyIsEnumerable('length'); // false
for (var value in a) {
  console.log(value); // 0, 1, 2
}

객체.toString

가끔 객체를 alert하거나 console.log할 때 원하는 결과는 안 나오고, [object Object] 이런 게 나올 때가 있습니다. 내부적으로 toString 메소드가 호출된 결과입니다. 문자열끼리 더할 때 주로 호출됩니다. 기본적으로는 객체의 종류를 알려주고, 사용자가 임의로 바꿀 수 있습니다.

var obj = { a: 'hi', b: 'zero' };
obj.toString(); // [object Object]
Math.toString(); // [object Math]
obj.toString = function() {
  return this.a + ' ' + this.b;
}; // 임의로 바꿈
obj.toString(); // 'hi zero';
obj + ' cho'; // 'hi zero cho'

객체.valueOf

객체의 기본 값을 의미합니다. 숫자 계산을 할 때 내부적으로 호출됩니다. toString처럼 내부적으로 호출되기 때문에 관리하기 어렵습니다.

var obj = { a: 'hi', b: 'zero' };
obj.valueOf(); // { a: 'hi', b: 'zero' }
obj + 5; // '[object Object]5' <-- 내부적으로 toString이 호출됨
obj.valueOf = function() {
  return 3;
}
obj + 5; // 8 <-- 내부적으로 valueOf가 호출됨

Object.create(prototype, 속성들)

객체를 생성하는 방법 중 하나입니다. 속성들 부분은 writable, configurable, enumerable, get, set ,value의 옵션이 있는데 아래 defineProperties를 참고하세요.

var obj = {}; // Object.create(Object.prototype); 과 같음
var obj2 = Object.create(null, {
  a: {
    writable: true,
    configurable: false,
    value: 5,
  }
});
obj2.a; // 5

Object.defineProperties(객체, 속성들), Object.defineProperty(객체, 속성, 설명)

객체의 속성을 자세하게 정의할 수 있습니다. 속성의 설명을 따로 설정할 수 있는데, writable은 속성값을 변경할 수 있는지, enumerable은 for ... in 반복문 안에서 사용할 수 있는지, configurable은 속성의 설명을 바꿀 수 있는지를 설정합니다. false인 경우 delete 동작도 불가능합니다. 기본적으로 writable, enumerable, configurable은 false입니다. value는 속성의 값, get은 속성의 값을 가져올 때, set은 속성의 값을 설정할 때를 의미합니다.

var obj = {};
Object.defineProperties(obj, {
  a: {
    value: 5,
    writable: false,
    enumerable: true,
  },
  b: {
    get: function() {
      return 'zero';
    },
    set: function(value) {
      console.log(this, value);
      this.a = value;
    },
    enumerable: false,
    configurable: false,
  },
});
obj.a; // 5
obj.b; // 'zero'
obj.a = 10;
obj.a; // writable이 false라 그대로 5
for (var key in obj) {
  console.log(key); // b의 enumerable이 false이니까 a만 log됨
}
obj.b = 15; // 15로 설정되는 대신 set의 내용이 실행됨. set의 value는 15
obj.a; // this.a = value로 인해 15로 바뀌어야 하나 writable이 false라 무시됨
obj.b; // 그대로 'zero'
Object.defineProperty(obj, 'b', {
  value: 5
}); // Uncaught TypeError: Cannot redefine property: b

마지막은 configurable이 false기 때문에 b 속성의 설명을 재정의할 수 없습니다.

Object.defineProperty(obj, 'c', {
  value: { x: 3, y: 4 },
  writable: false,
  enumerable: true,
});
obj.c; // { x: 3, y: 4 }
obj.c = 'zero';
obj.c; // writable이 false라 그대로 { x: 3, y: 4 }
obj.c.x = 5; // 값이 객체인 경우 그 객체의 속성을 바꿈
obj.c; // { x: 5, y: 4 }로 바뀜

writable은 속성 값을 바꾸는 것을 막지만 만약 속성의 값이 객체인 경우에는 그 객체 안의 속성을 바꾸는 것은 막지 못합니다. 바꾸는 것을 전체적으로 막기 위해서 Object.freeze 메소드가 있습니다.

Object.getOwnPropertyDescriptor(객체, 속성)

속성의 설명 값을 불러옵니다. 위의 예시를 그대로 사용해보겠습니다.

Object.getOwnPropertyDescriptor(obj, 'b'); // { enumerable: false, configurable: false, get: function() {}, set: function(value) {} }

Object.freeze, Object.seal, Object.preventExtensions

위의 예시에서 writable을 false로 해도, value가 객체인 경우에는 객체의 속성을 바꾸는 것을 막지 못합니다. Object.freeze를 사용하면 객체 전체를 바꾸지 못하게 고정할 수 있습니다. 값도 못 바꿀뿐더러, 속성을 추가 또는 제거할 수도 없고, 속성의 설명을 바꿀 수도 없습니다.

var frozenObj = Object.freeze(obj);
frozenObj.a = 10;
frozenObj.a; // 그대로 5
delete frozenObj.c; // false
Object.freeze(obj.c); // 이것까지 해야 내부 객체까지 완전히 얼려짐

Object.seal의 경우는 속성의 추가, 제거를 막고, configurable을 false로 바꿉니다. 대신 속성의 값은 writable이 true이기만 하면 바꿀 수 있습니다.

var sealedObj = Object.seal(obj);
sealedObj.a = 10;
sealedObj.a; // 5로 변경이 안 되지만 writable이 true면 변경 가능
delete sealedObj.c; // false

그냥 속성의 추가만 막고 싶다면 Object.preventExtensions가 있습니다. 그 외의 속성 제거, 값 변경, 설정 변경은 가능합니다.

var nonExtensible = Object.preventExtensions(obj);
nonExtensible.d = 'new';
nonExtensible.d; // undefined

Object.keys

객체의 속성명을 모두 가져와 배열로 만듭니다. enumerable이 false인 것은 빠집니다.

Object.keys(obj); // ['a', 'c']

Object.isFrozen, Object.isSealed, Object.isExtensible

객체가 freeze 되었는지, sealed 되었는지 또는 preventExtension 상태인지 알려줍니다.

Object.isFrozen(frozenObj); // true
Object.isSealed(sealedObj); // true
Object.isExtensible(nonExtensible); // false

typeof

객체의 타입을 알려줍니다. 배열과 null도 object로 표시되기 때문에 배열을 구분하려면 Array.isArray 메소드를 사용하고, null을 구분하려면 따로 처리해야합니다. null이 object로 표시되는 것은 흔히 자바스크립트의 실수라고 여겨집니다.

var a = 1;
var b = 'zero';
var c = true;
var d = {};
var e = [];
var f = function() {};
var g;
var h = null;

typeof a; // 'number'
typeof b; // 'string';
typeof c; // 'boolean';
typeof d; // 'object';
typeof e; // 'object';
typeof f; // 'function';
typeof g; // 'undefined'
typeof h; // 'object';

delete

객체 내의 속성을 지울 수 있습니다. 성공하면 true를 실패하면 false를 반환합니다. configurable이 false거나 freeze된 상태면 실패합니다.

var obj = {
  a: 'hi',
  b: 'zero',
};
obj.b; // zero
delete obj.b;
obj.b; // undefined

후... 오늘 많은 것을 배웠습니다. 꼭 복습하셔야 합니다. 이제 객체의 속성은 마스터한 겁니다. 다음 시간에는 자바스크립트 함수의 범위에 대해 알아보겠습니다.

투표로 게시글에 관해 피드백을 해주시면 많은 도움이 됩니다. 오류가 있다면 어떤 부분에 오류가 있는지도 알려주세요! 잘못된 정보가 퍼져나가지 않도록 도와주세요.
Copyright © 2016- 무단 전재 및 재배포 금지

댓글

4개의 댓글이 있습니다.
9일 전
Object.preventExtensions 을 설명해주신 부분에 '설정 변경'이라는 말은 configurable 변경을 뜻하는 것인가요??
8일 전
네 맞습니다.
일 년 전
확실히 중급과정이라 어렵네요..
1. var sealedObject = Object.seal(obj);
sealedObj.a = 10;
sealedObj.a; // 10으로 변경됨
이 부분에서 sealedObj가 오타같습니다. 에러가 나길래..
sealedObject.a = 10; 로 바꿔서 써보니까 에러는 안나는데 이번에는 또
sealedObject.a; 이게 주석처럼 10으로 변경되지는 않더라구요..ㅠ 5로 반환됩니다.

2. Object.isExtensible(nonExtensible); // true
이것도 false로 반환하던데요.
아래는 코드는 잘 됐는데 뭐가 문제인지 잘 모르겠네요...ㅠ
var nonExtensible = Object.preventExtensions(obj);
nonExtensible.d = 'new';
nonExtensible.d; // undefined
일 년 전
오타 두 개를 찾아주셔서 감사합니다. 1번은 5고, 2번은 false가 맞습니다.
일 년 전
Object.seal() 메소드 예제에 보시면 선언한 변수랑 사용하는 변수랑 다르네요. 제가 잘못 이해한게 아니라면 혹시 오타가 아닌가 싶네요ㅋ
일 년 전
맞는 코드입니다. 위의 예제랑 이어지는 거에요.
일 년 전
그렇군요!
일 년 전
다시 복습해야겠네요
2년 전
제가 직접 타이핑해서 실행해보기도하고, 복붙해서 실행해보기도 했는데 브라우저에 아무것도 안나와서...뭔가 잘못된걸까요?
2년 전
고쳤습니다. 이제 다시 복사하시면 될 거에요. 죄송하네요 ㅠㅠ 저도 공부하는 학생이라 코드도 오류가 많고 서버도 자주 터집니다... 그래도 항상 제 글 봐주시고 오류 잡아주셔서 감사합니다!
2년 전
저는 설명해주셔도..몇번씩 다시봐야 하는데 이런 코드를 짜실 수 있다는게 대단하신거같아요 ㅠㅠ 많이배워가겠습니다! 좋은자료 항상 감사해요~!
2년 전
사실 코드보다 알고리즘이 더 중요합니다. 제가 이번 학기에 알고리즘에 대해 배운 후 해당 강좌도 올려볼게요.