3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

JavaScriptAdvent Calendar 2015

Day 19

プロパティ記述子のDataDescriptorの各プロパティをよく分かっていないためまとめた

Last updated at Posted at 2016-01-15

JavaScript Advent Calendar 2015の19日目の記事です。
JavaScript初心者のため勉強中。

プロパティ記述子とは

ある本を読んでいたのだが、こんなようなことが書かれていた。

JavaScriptでのオブジェクトは「名前」と「値」の組み合わせである__プロパティ__の集合。(中略)厳密にはプロパティ名と属性群の組み合わせで、これらの属性のセットを__プロパティ記述子__という。

…はい?属性群?
よく分からんし、見たことない。

とりあえずgetOwnPorpertyDescriptionメソッドで設定内容を参照できるらしいので確認。

var obj = {};
obj.a = 1;
Object.getOwnPropertyDescriptor(obj, "a");

// 結果
Object {
    value: 1, 
    writable: true, 
    enumerable: true, 
    configurable: true
}

ほー、なんかvalue以外にもwritable, enumerable, configurableとか設定されとるが、わしそんなもの設定しとらんぞ?というわけで各属性の特徴を調べてみた。

DataDescriptorの各属性の説明

  • Value  → 文字通り値。

  • Writable  → Value属性を更新できるか否かを指定。

  • Enumerable  → for-in文で補足するか否かを指定。

  • Configurable  → プロパティ記述子を変更できるか否かを指定。(ただしWritable以外)

頭を大文字で記載したが、使う時は小文字で使うルールらしい。
以下、各属性の使い方。(Value属性は省く)

Writable属性

オブジェクトを定義し、value, wraitableを設定。

// オブジェクトの定義
obj = {};

// プロパティ"a"の設定
Object.defineProperty(obj, "a", {
    value: 1,
    writable: false
});

// プロパティ"b"の設定
Object.defineProperty(obj, "b", {
    value: "hoge",
    writable: true
});

console.log(obj.a);
console.log(obj.b);

// プロパティ"a"のvalueを変更
obj.a = 200;
// プロパティ"b"のvalueを変更
obj.b = "fuga";

console.log(obj.a);
console.log(obj.b);


// 結果
1
hoge
1
fuga

はい、aではvalueが更新されないこと、bでは更新されることが確認できた。
ちなみに、この後もう一度definePropertyメソッドからwritabletrueに変更しようとしたが、エラーとなった。一度定義すると後からは変更できないらしい。

※指定しないとデフォルトでfalseに設定される。

Enumerable属性

オブジェクトを定義し、それをfor-in文で表示してみると、なんか余計なものが表示される。

// プロパティ"hoge"の設定
Object.prototype.hoge = function() { console.log("fuga") };
// オブジェクトの定義
var obj = {};

for (var key in obj){ console.log(key) };

// 結果
hoge
undefined

ん?hogeが表示されている。 これがいわゆる__オブジェクト汚染__というやつか。
これを回避するためにEnumerable属性をfalseにするといいと。

// プロパティ"hoge"の設定
Object.defineProperty(Object.prototype, "hoge",{
    value: function() { console.log("fuga") },
    enumerable: false
});

// オブジェクトの定義
var obj = {};

for (var key in obj) { console.log(key) };
obj.hoge();

// 結果
undefined
fuga

よし。これでfor-in文ではundifinedが表示され、obj.hoge()にてfugaが表示された。

Configure属性

オブジェクトを定義し、それを更新・削除してみる。

// オブジェクトの定義
var obj = {};
// プロパティ"hoge"の設定
Object.defineProperty(Object.prototype, "hoge",{
    value: 1,
    enumerable: false,
    configurable: false
});

// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// "hoge"プロパティの更新
Object.defineProperty(obj, "hoge", {
    enumerable: true,
    configurable: true,
    writable: true
});
// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// "hoge"プロパティの削除
delete obj.hoge;
// "hoge"プロパティの属性確認
Object.getOwnPropertyDescriptor(obj, "hoge");


// 結果
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}

TypeError発生
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}

false
Object {
    value: 1, 
    writable: false, 
    enumerable: false, 
    configurable: false
}

よし。こちらも各属性を更新しようとするとTypeErrorとなり、プロパティが削除されないことが確認できた。

※1 初期設定でconfigurableをtrueにしていた場合、変更できることも確認済み。
※2 一度falseにすると、今後更新できないことも確認済み。

終わりに

今回はデータプロパティのみ扱ったが、アクセサプロパティと言うものも存在し、そちらではGet, Set関数を持つ。
プロパティ記述子の活用法はまだ模索段階らしく、この時はこれを使う、という体系化はなされていないそうな。まぁ使う頻度はそんなにはなさそうだが、知っていて損はないかな。

※何か間違っている記述がございましたら、ご指摘いただけますと幸いです!

3
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?