Object
Object의 두가지 형식.
constructed가 property를 하나씩 추가 가능하다는 것 외엔 전부 동일.
//literal
var obj = {
key: value,
};
// constructed form
var myObj = new Object();
myObj.key = value;
language types
object sub-types
실제로 built-in function이다. constructor로 사용가능하다.(new를 사용하여 새로 constructed object가 만들어진다)
var strPrimitive = "I am a string";
typeof strPrimitive; // "string"
strPrimitive instanceof String; // false
var strObject = new String( "I am a string" );
typeof strObject; // "object"
strObject instanceof String; // true
// inspect the object sub-type
Object.prototype.toString.call( strObject ); // [object String]
"hi" 이런 것은 객체가 아니지만, 여기서 작업을 하기 위해서(길이, contents 접근) String 객체가 필요할 때가 있는데, 다행히도 필요하다면 자동으로 연결된다.
number, boolean 등 도 마찬가지인데 null, undefined는 wrapper form이 없고, Date 같은 경우에는 constructed object form으로만 생성이 가능하다.
construted form이 더 많은 옵션이 있지만 필요할 때가 아니면 사용하지 말자.
Error는 보통 자동으로 만들어진다.
객체의 property는 value가 저장되어 있는 곳에 대한 포인터처럼 동작한다.(속해 있기 보다는)
.
[""]
을 이용하여 접근가능하다.
property 이름은 항상 string이다. 다른 유형을 써도 자동으로 바뀐다.
literal 선언에서, key-name 위치에서[]
로 감싸면 표현식을 이용하여 이름을 만들 수 있다.
그리고 더 흔한 사용으로는 Symbol을 이용할 수 있다. 간단하게 말해서 추측 불가의 string 유형의 이름을 만들어 준다.?
var myObject = {
[Symbol.Something]: "hello world"
};
객체에 들어있는 함수를 method라고 한다.
array를 object로 쓸 거면 뭐하러..
var myArray = [ "foo", 42, "bar" ];
myArray.baz = "baz";
myArray.length; // 3
myArray.baz; // "baz"
//["foo", 42, "bar", baz: "baz"]
var myArray = [ "foo", 42, "bar" ];
myArray["3"] = "baz";
myArray.length; // 4
myArray[3]; // "baz"
//["foo", 42, "bar", "baz"]
function anotherFunction() { /*..*/ }
var anotherObject = {
c: true
};
var anotherArray = [];
var myObject = {
a: 2,
b: anotherObject, // reference, not a copy!
c: anotherArray, // another reference!
d: anotherFunction
};
anotherArray.push( anotherObject, myObject );
shallow copy라면, a는 2로 그대로 복사하겠지만 나머지는 그냥 기존 객체의 참조를 가져올 것 이다.
deep copy라면, myObject뿐 아니라 anotherObject, anotherArray도 복사하는데 그럼 circular reference. deep copy..
JSON 방법
var newObj = JSON.parse( JSON.stringify( someObj ) );
Object.assign()
으로 shallow copy를 할 수 있다.
var newObj = Object.assign( {}, myObject );
newObj.a; // 2
newObj.b === anotherObject; // true
newObj.c === anotherArray; // true
newObj.d === anotherFunction; // true
var myObject = {
a: 2
};
Object.getOwnPropertyDescriptor( myObject, "a" );
// {
// value: 2,
// writable: true,
// enumerable: true,
// configurable: true
// }
var myObject = {};
//보통 사용하지 않음
Object.defineProperty( myObject, "a", {
value: 2,
writable: true,
configurable: true,
enumerable: true
} );
myObject.a; // 2
var myObject = {};
Object.defineProperty( myObject, "a", {
value: 2,
writable: false, // not writable!
configurable: true,
enumerable: true
} );
myObject.a = 3;
//"use strict"; TypeError// setter와 비슷.
myObject.a; // 2
strict mode와 상관없이 해당 부분이 false라면 definedProperty
를 쓸 때, TypeError. 취소 불가능.
그런데 .. false여도 writable을 에러없이 true에서 false로 가능하다. 반대는 불가능.
그리고 delete
을 막을 수 있다. delete은 다른 언어에서처럼 메모리 해제하는 것이 아니라 지울 수 있는 객체 속성을 지우는 것 뿐이다.
myObject.a; // 2
delete myObject.a;
myObject.a; // 2
열거 가능한지에 대한....
property에 다른 참조가 포함되어 있는 경우, 해당 property가 변경 불가능이라고 해도, 값을 바꿀 수 있다.
writable:false
&& configurable:false
객체 내부가 변하는 것을 막고 싶다면 Object.preventExtensions(객체)
. strict mode에서 시도하면 TypeError
Object.seal()
는 sealed 객체를 만든다. 즉, Object.preventExtensions(객체)
와 configurable:false
를 적용한다.
Object.freeze()
seal에서 writable:false
를 추가하지만 처음에 언급했듯이 참조된 객체는 영향을 받지 않는다.
[[Get]]
var myObject = {
a: 2,
c: undefined
};
myObject.a; // 2
myObject.b; // undefined// No Error
myObject.c; // undefined// 윗줄과 결과가 똑같은데 어떻게 구별?
실제로 [[Get]]()
이 동작한 것. 처음에 요청받은 이름의 속성에 대해 객체 property를 조사하고, 찾았다면 value를 반환한다. 찾지 못했다면 "undefined" return.
[[Put]]
이미 있거나 새로운 property 설정 방법을 통제한다.
property가 존재할 경우,
1. Is the property an accessor descriptor? 맞으면 setter call.
2. Is the property a data descriptor with writable of false? 맞으면 실패.
3. 다른 경우엔, 정상작동.
ES5부터 getter, setter를 이용하여 객체 수준이 아닌 property 수준의 default 작동을 override할 수 있게 되었다.
getter는 값을 찾기 위해, setter는 값을 설정하기 위해 함수를 호출하는 property.
이런 getter나 setter를 속성으로 정의하면 이것을 "accessor descriptor"라고 하고, 이 경우 value, writable이 무시되고 대신에 JS는 get, set을 사용한다.
var myObject = {
// define a getter for `a`
get a() {
return 2;
}
};
Object.defineProperty(
myObject, // target
"b", // property name
{ // descriptor
// define a getter for `b`
get: function(){ return this.a * 2 },
// make sure `b` shows up as an object property
enumerable: true
}
);
myObject.a; // 2
myObject.b; // 4
myObject.a = 3;//setter가 유효하다고 하더라도 .... 결과는 아래와 같다.
myObject.a; // 2
getter와 setter는 같이.
var myObject = {
// define a getter for `a`
get a() {
return this._a_;
},
// define a setter for `a`
set a(val) {
this._a_ = val * 2;
}
};
myObject.a = 2;
myObject.a; // 4
아까 위에서 실제로 없는지, 혹은 값이 undefined인지 구별을 어떻게 할까?
in은 property가 [[Prototype]] 수준에서 존재하는지, 객체 안에 존재하는지. (property name)
hasOwnProperty()
는 후자만. 이는 Object.prototype에 연결되어 있는데 Object.create(null)을 이용하면 실패할 것.그럼 확실하게 Object.prototype.hasOwnProperty.call(myObject,"a")
var myObject = {
a: 2
};
("a" in myObject); // true
("b" in myObject); // false
myObject.hasOwnProperty( "a" ); // true
myObject.hasOwnProperty( "b" ); // false
var myObject = { };
Object.defineProperty(
myObject,
"a",
// make `a` enumerable, as normal
{ enumerable: true, value: 2 }
);
Object.defineProperty(
myObject,
"b",
// make `b` NON-enumerable
{ enumerable: false, value: 3 }
);
myObject.b; // 3
("b" in myObject); // true
myObject.hasOwnProperty( "b" ); // true
// .......
for (var k in myObject) {
console.log( k, myObject[k] );
}
// "a" 2
//직접적으로 알려줌
myObject.propertyIsEnumerable( "a" ); // true
myObject.propertyIsEnumerable( "b" ); // false
//key는 가능한 것들만 나옴.
Object.keys( myObject ); // ["a"]
Object.getOwnPropertyNames( myObject ); // ["a", "b"]
forEach()
: 배열의 모든 값들을 반복, 콜백 반환값 무시
every()
: 끝까지, 콜백이 falsy값을 반환하면 멈춘다.
some()
: 끝가지, 콜백이 truthy 값을 줄 때까지 돈다.
for...of
array의 value에 직접.
@@iterator
var myObject = {
a: 2,
b: 3
};
Object.defineProperty( myObject, Symbol.iterator, {
enumerable: false,
writable: false,
configurable: true,
value: function() {
var o = this;
var idx = 0;
var ks = Object.keys( o );
return {
next: function() {
return {
value: o[ks[idx++]],
done: (idx > ks.length)
};
}
};
}
} );
// iterate `myObject` manually
var it = myObject[Symbol.iterator]();
it.next(); // { value:2, done:false }
it.next(); // { value:3, done:false }
it.next(); // { value:undefined, done:true }
// iterate `myObject` with `for..of`
for (var v of myObject) {
console.log( v );
}
// 2
// 3