読者です 読者をやめる 読者になる 読者になる

プロパティの操作,確認,列挙

JavaScriptの言語仕様(ES5)

プロパティ操作の基本

オブジェクトのプロパティは原則的に、いつでもその内容を変更できる。
後から新しいプロパティを追加したり、既存のプロパティを削除することも出来る。

var person = {
    name: 'Tom'
};

person.age = 30;    // プロパティを追加
console.log(person.age);    // 30

person.name = 'Bob';   // プロパティの値を変更
console.log(person.name);   // Bob

delete person.name;   // プロパティを削除
console.log(person.name);   // undefined

なお、そのようなプロパティの操作を防止することも出来る。詳細は下記を参照。
プロパティの内部属性
オブジェクトの変更防止

プロパティの存在確認

オブジェクトが、ある名前のプロパティを持っているかを確認する方法として、in演算子hasOwnProperty()がある。

in演算子は、対象となっているプロパティを持っていればtrueを、持っていなければfalseを返す。
先ほどのコードでin演算子を使ってみる。

var person = {
    name: 'Tom'
};

person.age = 30;    // プロパティを追加
console.log('age' in person);    // true

person.name = 'Bob';   // プロパティの値を変更
console.log('name' in person);   // true

delete person.name;   // プロパティを削除
console.log('name' in person);   // false

in演算子では、そのオブジェクト自身が持つプロパティだけでなく、プロトタイプ継承しているプロパティも対象とする。
自身が持つプロパティだけを確認したい場合は、全てのオブジェクトで使用可能なメソッドであるhasOwnProperty()を使う。
このメソッドの引数にプロパティの名前を与えると、オブジェクト自身がそのプロパティ持っていればtrueを、そうでなければfalseを返す。

下記の例では、person自身はtoStringを持っていないが、プロトタイプ継承しているため、in演算子trueを返す。
だがhasOwnProperty()では、falseを返す。

var person = {
    name: 'Tom'
};

console.log('name' in person);   // true
console.log('age' in person);    // false
console.log('toString' in person);   // true
console.log(person.hasOwnProperty('toString'));    // false

プロパティの列挙

プロパティを列挙していく方法としては、for-inループ、Object.keys()メソッド、Object.getOwnPropertyNames()メソッドがある。

for-inループ

これは、そのオブジェクトが持っているプロパティをループで走査していく。
この方法では、プロトタイプ継承かどうかは問われず、内部属性で列挙可能になっているものが対象になる。なお、ビルトインされているほとんどのプロパティは、列挙不可になっている。
内部属性については、下記を参照。
プロパティの内部属性

var person = {
    name: 'Tom',
    age: 30,
    mail: 'tom@example.com'
};

for(var key in person){
    console.log(key);
    console.log(person[key]);
};
// name
// Tom
// age
// 30
// mail
// tom@example.com

Object.keys()メソッド

Object.keys()は、引数に与えたオブジェクトが持っているプロパティのリストを、配列にして返す。
対象となるのは、列挙可能かつ、自身が持っているプロパティ。列挙可能であっても、プロトタイプ継承されたものは、対象とはならない。

var person = {
    name: 'Tom',
    age: 30,
    mail: 'tom@example.com'
};

var properties = Object.keys(person);

console.log(properties);
// [ 'name', 'age', 'mail' ]

for(var i=0; i < properties.length; i++){
    console.log(properties[i]);
    console.log(person[properties[i]]);
};
// name
// Tom
// age
// 30
// mail
// tom@example.com

Object.getOwnPropertyNames()メソッド

Object.getOwnPropertyNames()は、Object.keys()とほぼ同じ機能を持つ。
違いは、Object.getOwnPropertyNames()は、列挙不可であるプロパティも対象とするということ。
つまり、列挙可能かどうかは問わず、自身のプロパティのみを全て返す。プロトタイプ継承されたものは、全て対象外となる。

var person = {
    name: 'Tom',
    age: 30,
    mail: 'tom@example.com'
};

// ここで、ageを列挙不可にする
Object.defineProperty(person, 'age', {
    enumerable: false
})

var properties = Object.keys(person);
console.log(properties);
// [ 'name', 'mail' ]

properties = Object.getOwnPropertyNames(person);
console.log(properties);
// [ 'name', 'age', 'mail' ]

プロパティの存在確認と列挙の方法一覧

自身のプロパティ
列挙可能
継承されたプロパティ
列挙可能
自身のプロパティ
列挙不可
継承されたプロパティ
列挙不可
in
hasOwnProperty() × ×
for-in × ×
Object.keys() × × ×
Object.getOwnPropertyNames() × ×

出典 オブジェクト指向JavaScriptの原則 p80