31
32

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.

ES6 Symbol を使ってオレオレメソッドを拡張する

Last updated at Posted at 2015-10-26

ECMAScript6にシンボルができた理由 で紹介されている Symbol の使い方を見て、fmfm するためのエントリです。

似て非なる 2つの NativeObject 拡張ライブラリを同時に読み込むとどうなるか

Array に JSON.stringify(Array) 相当の機能を拡張するライブラリが2つ(AwesomeArray.js, ExArray.js)あります。これらを読み込むと Array#toJSON が拡張されます。
AwesomeArray.js と ExArray.js には、カンマの後ろにスペースがある/ない という違いがあります。

ES5 式

ES5 で書かれた AwesomeArray.js と ExArray.js です。

ES5 までは、AwesomeArray.js を読み込んだ後に ExArray.js を読み込むと、AwesomeArray.js で拡張した Array#toJSON が ExArray.js のそれに上書きされてしまいます。
AwesomeArray.js と ExArray.js が混在してしまう状況では、最終的にどちらが機能するかは、読み込み順に依存することになりカオスでした。

// AwesomeArray.js
(function(global) {
  Array.prototype.toJSON = function() {
    return "[" + this.join(",") + "]"; // without space
  };
})(this);
// ExArray.js
(function(global) {
  Array.prototype.toJSON = function() {
    return "[" + this.join(", ") + "]"; // with space
  };
})(this);
var array = [1,2,3];
console.log(array.toJSON()); // -> [1, 2, 3] (ExArray.js の Array#toJSON が機能している)

ES6 式

ES6 からは、Symbol を使う事でこれら2つのライブラリが共存可能になり、呼び分ける事も可能になります。

// AwesomeArray.js
(function(global) {
  // シンボルを作成します。文字列 "AwesomeArray Array#toJSON" はデバッグ時の識別用です
  var toJSON = Symbol("AwesomeArray Array#toJSON");

  // JSON.stringify(Array) 相当のメソッドを追加します。
  // Symbol で追加するため for in などの enum ではメソッド名は列挙されません
  Array.prototype[toJSON] = function() {
    return "[" + this.join(",") + "]"; // without space
  };

  // Symbol を export しライブラリの外から呼び出し可能にします
  global.AwesomeArray = { "toJSON": toJSON }; // export Symbol
})(this);
// ExArray.js
(function(global) {
  // シンボルを作成します。文字列 "ExArray Array#toJSON" はデバッグ時の識別用です
  var toJSON = Symbol("ExArray Array#toJSON");

  // JSON.stringify(Array) 相当のメソッドを追加します。
  // Symbol で追加するため for in などの enum ではメソッド名は列挙されません
  Array.prototype[toJSON] = function() {
    return "[" + this.join(", ") + "]"; // with space
  };

  // Symbol を export しライブラリの外から呼び出し可能にします
  global.ExArray = { "toJSON": toJSON }; // export Symbol
})(this);

Test

AwesomeArray.js と ExArray.js を読み込み、
AwesomeArray.js で追加した Array#toJSON と ExArray.js で追加した Array#toJSON が共存できているかテストします。

require("AwesomeArray.js");
require("ExArray.js");

var array = [1,2,3];
var toJSON = AwesomeArray.toJSON;

console.log( array[AwesomeArray.toJSON]() ); // -> "[1,2,3]"
console.log( array[ExArray.toJSON]() );      // -> "[1, 2, 3]"
console.log( array[toJSON]() );              // -> "[1,2,3]"

Object.getOwnPropertySymbols

for ... inObject.getOwnPropertyNames で Symbol が見えない事を確認します

console.log( Object.getOwnPropertyNames(Array.prototype) );
// -> [ "length", "constructor", "toString", "toLocaleString",
//      "join", "pop", "push", "concat", "reverse", "shift",
//      "unshift", "slice", "splice", "sort", "filter", "forEach",
//      "some", "every", "map", "indexOf", "lastIndexOf", "reduce",
//      "reduceRight", "entries", "keys", "copyWithin", "find",
//      "findIndex", "fill", "includes" ]

Object.getOwnPropertySymbols で、Symbol を可視化できます。

console.log( Object.getOwnPropertySymbols(Array.prototype) );
// -> [ Symbol(Symbol.unscopables),
//      Symbol(Symbol.iterator),
//      Symbol(AwesomeArray Array#toJSON),   <- 追加されている
//      Symbol(ExArray Array#toJSON) ]       <- 追加されている
31
32
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
31
32

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?