LoginSignup
9
6

More than 5 years have passed since last update.

JS で hoge.fuga = hoge.fuga すると元通りじゃない話

Posted at

まぁ C# みたいにセッター・ゲッターを好きに定義できる言語だと当たり前のような話なんですが…

ではなく、ではなく。

JavaScript でゲッターやセッターを定義した場合の話ではなく、そもそも見落としがちな言語仕様のことですよという。

以下のように hoge.fuga = hoge.fuga みたいなことをすると必ずしも元通りにならない。

// コンストラクタ関数
function Hoge() {
}
// prototype にメソッド定義
Hoge.prototype.fuga = function(){
    console.log('fuga');
};

// コンストラクタから生成したオブジェクト
var hoge = new Hoge();

hoge.fuga();

// fuga は hoge に含まれるが
console.log('\'fuga\' in hoge -> ' + ('fuga' in hoge));
// hoge 自身のプロパティではない
console.log('hoge.hasOwnProperty(\'fuga\') -> ' + hoge.hasOwnProperty('fuga'));

// hoge.fuga = hoge.fuga は何もしてないように見えるが…
console.log('hoge.fuga = hoge.fuga');

var fuga = hoge.fuga;
hoge.fuga = fuga;

hoge.fuga();

console.log('\'fuga\' in hoge -> ' + ('fuga' in hoge));
// hoge.hasOwnProperty('fuga') の結果が変わる
console.log('hoge.hasOwnProperty(\'fuga\') -> ' + hoge.hasOwnProperty('fuga'));

JSFiddle

これはプロパティの取得アクセス時に呼ばれる内部 [[Get]] メソッドがプロトタイプチェーンを辿るのに対して、代入アクセス時に呼ばれる内部 [[Put]] メソッドはオブジェクト自体にプロパティを設定してしまうから。

結果、hoge.[[prototype]].fugahoge.fuga に設定してしまうことになって元の通りにはならない。

一時的にメソッドの処理を差し替えるために元のプロパティを退避してどうこうするような黒魔法を使う場合は念のため上記の現象が問題ないかを確認する必要がある。

var hoge = getHoge();
// 退避
var orgFuga = hoge.fuga;
// 一時的に処理差し替え
hoge.fuga = function () {...};
// 差し替えた状態で何かする
hoge.doSomething();
// 退避した orgFuga を元に戻す
hoge.fuga = orgFuga; // ←元に戻してるつもりで、厳密には元通りじゃない
9
6
1

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
9
6