Firefox 34 でES6の Object.assign() が実装されたが…
皆さん待望の、mixin をするメソッドである。
第一引数のtargetに、第二引数以降のプロパティの値を代入していく。
var obj = { foo: "FOO", }; var res = Object.assign(obj, { bar: "BAR" }, { piyo: "PIYO" }); obj.bar; // => "BAR"; obj.piyo; // => "PIYO" res === obj; // => true
代入されるプロパティは:
- ソースとなるオブジェクト自身のプロパティ(つまり、[[Prototype]]から継承したものは含まない)
- 列挙可能であること(enumerable属性がtrueであること)
簡易的には以下の様な実装
Object.assign = function(target, ...sources) { for (let source of sources) { let keys = Object.getOwnPropertyNames(source); for (let key of keys) { let desc = Object.getOwnPropertyDescriptor(source, key); if (desc && desc.enumerable) { target[key] = source[key]; } } } return target; }
大まかな話はこんな感じ。
次は細かい話。
デスクリプタのコピーではなく、代入(=)がされる
上記簡易コードで、target[key] = source[key];
と書いた。
本来、プロパティのコピーをするならObject.defineProperty(target, key, desc)
と書くところだが、仕様も実装もそうなっていない。(個人的には気に食わない点)
var obj = Object.assign({}, { get foo() { return "FOO"; }, });
というコードがあった場合、obj.fooはgetterではなく、ただプロパティとして代入される。
もっと酷い例を挙げると、
var obj = Object.assign({}, { get __proto__() { return null; }, });
これ、obj.__proto__ = null
しているのと同義になり、[[Prototype]&93;が書き換えられるというアレなことが起きる。
Symbolもあるんだよ
現状のFirefoxの実装( https://hg.mozilla.org/mozilla-central/diff/53769e48d35b/js/src/builtin/Object.js )では抜けているが、Symbol型のプロパティも代入の対象である。
上記の簡易実行コードは、下記のように書いたほうが正確である...(仕様が後で書き換わる可能性もあるが、現状では)
Object.assign = function(target, ...sources) { for (let source of sources) { let keys = [...Object.getOwnPropertyNames(source), ...Object.getOwnPropertySymbols(source)]; for (let key of keys) { let desc = Object.getOwnPropertyDescriptor(source, key); if (desc && desc.enumerable) { target[key] = source[key]; } } } return target; }
現状のFx34のコードは仕様に沿ってないので、 https://bugzilla.mozilla.org/show_bug.cgi?id=937855#c32 にコメントだけは残しておいた。何の反応もなく進んでしまうようなら、正式にバグ登録したい。