JavaScriptシンボルの調査。 文字を使用する

これは、文字とJavaScriptでの文字の使用に関するシリーズの2番目の記事です。 前のパート: 「シンボルはJavaScriptの新しいデータ型です。



文字の出現により、オブジェクトのすべての文字を取得できる1つのメソッドでオブジェクトObject



が拡張されました。



  var role = Symbol('role'); var score = Symbol('score'); var id = 100; var name = 'Moderator'; var user = { id: id, name: name }; user[role] = 'admin'; user[score] = 50000; Object.getOwnPropertySymbols( user ); // [Symbol(role), Symbol(score)]
      
      





このメソッドが存在するため、真にプライベートなプロパティを作成することはできません。



ここで、たとえば、ユーザーロールを取得する方法:



  var userSymbols = Object.getOwnPropertySymbols( user ); var roleSymbol = userSymbols[0]; user[ roleSymbol ]; // 'admin'
      
      





クライアント側でデータを非表示にできないという事実を考慮すると、この関数は、 Object.getOwnPropertyNames



を使用してObject.getOwnPropertyNames



のすべてのプロパティ名のリストを取得する状況と同様に、文字のリストを取得するために必要な補助と見なされる必要がありますObject.getOwnPropertyNames







また、ECMAScript 6仕様には、JavaScriptでのリフレクション(またはリフレクション)を許可する新しいReflect



オブジェクトが追加されていることにも注意してください。 また、 Reflect



オブジェクトのメソッドの1つを使用すると、文字列と文字の両方で宣言されているすべてのプロパティを取得できます。



  var properties = Reflect.ownKeys( user ); console.log( user ); // ['id', 'name', Symbol(role), Symbol(score)]
      
      





シンボルは、プロパティをパブリックと内部に分離する機会を提供します。これらは、内部情報を格納し、パブリックにアクセスするプロセスでのみ使用されます。



  var Project = (function () { var projectData = Symbol('project'); var projectStatus = Symbol('status'); var _getTitle = Symbol('title'); function Project( data, status ) { this[ projectData ] = data; this[ projectStatus ] = status; } Project.prototype.getProjectTitle = function () { return this[ _getTitle ](); }; Project.prototype[ _getTitle ] = function () { return this[ projectData ].name + ' (' + this[ projectData ].description + ')'; }; Project.prototype.getStatus = function () { return this[ projectStatus ]; }; Project.prototype.changeStatus = function ( status ) { this[ projectStatus ] = status; }; return Project; }()); var project = new Project({ name: 'Application', description: 'favorite project' }, 'open'); console.log( project.getStatus() ); // 'open' project.changeStatus('finished'); console.log( project.getStatus() ); // 'finished' console.log( project.getProjectTitle() ); // 'Application (favorite project)'
      
      





この例では、プロジェクト情報とそのステータスがシンボルを介して追加されているため、直接読み取り/変更することはできません。 文字によってのみ参照できる内部_getTitle



メソッドもあります。これは、パブリックAPIから非表示にし、 getProjectTitle



呼び出されたときにのみ使用されます。 また、シンボルにより、すべてのメソッドをオブジェクトのプロトタイプに入れることができました。



それでも、文字を追加する主な理由は、プライベートプロパティを作成する必要がないことです(ちなみに、このような可能性も提案されました- プライベート名オブジェクトですが、何らかの理由で仕様の現在のバージョンには含まれていません)。 シンボルが解決する主な問題は、一意のプロパティの作成です。 シンボルを使用するライブラリ開発者は、一意であることが保証されているプロパティを追加できます。これは、他のプロパティと競合しないことを意味します(他のモジュールによって追加されるプロパティをオーバーライドせず、ユーザーコードがこれらのプロパティを誤ってオーバーライドすることはできません)。



  var Request = (function () { var requestState = Symbol('state'); var states = { NOT_INITIALIZED: Symbol(), RECEIVED: Symbol(), PROCESSING: Symbol(), FINISHED: Symbol() }; function Request() { this[ requestState ] = states.NOT_INITIALIZED; } Request.prototype.getStates = function () { return states; }; Request.prototype.close = function () { this[ requestState ] = states.FINISHED; }; Request.prototype.changeState = function ( state ) { this[ requestState ] = state; }; return Request; }()) var request = new Request(); var handledState = Symbol('state'); request[ handledState ] = false; // code request[ handledState ] = true; request.close();
      
      





上記のコードは、 Request



エンティティを提供するサードパーティモジュールがある場合の状況を示しています。 このモジュールは、シンボルを使用してモジュールが機能するために必要なrequestState



状態を定義します。 また、開発者は、シンボルを使用して自分の状態(たとえば、表示される状態や要求が処理される状態)に入ります。 文字を介してプロパティを宣言するこの方法により、モジュールの動作が再定義されないことが保証されます。



この例は、文字を使用する別の方法も提供します。 states



オブジェクトは、一意の値を持つ列挙型と見なすことができます(これにより、正しい値を確認または渡すことができます)。



次に、グローバル文字レジストリに文字を作成できるメソッドを見てみましょう。



コードは、このコードが宣言されているグローバルコンテキストで実行されますが、別のコンテキストでコードを実行する機能があり、これにより既にいくつかの問題が発生する可能性があります。 たとえば、ブラウザでは、iframeで宣言されたコードは異なるグローバルコンテキストを持ち、各iframeはRegExp



Array



Date



などの独自のコピーを持ちます。 問題は、文字も存在し、宣言されたコンテキスト内でのみ一意であるということです。 コードがiframeのコードと相互作用する場合、このiframeには文字へのリンクがなく、これらの文字を介して宣言されるプロパティにアクセスできません。



この問題を解決するために、文字のグローバルレジストリが導入されました。 すべてのコンテキストで使用できるシンボルを作成するには、 Symbol.for



メソッドを使用する必要があります。



  var UUIDSymbol = Symbol.for('uuid');
      
      





このメソッドは、グローバルレジストリから文字を取得するためにも使用されます。 メソッドのロジックは次のとおりです。シンボルが見つかった場合、メソッドの結果として返されます。 レジストリにシンボルが見つからない場合、作成され、グローバルレジストリに追加され、結果として返されます。



サーバー側でグローバルレジストリを使用する必要がある同様の状況があります。 たとえば、Node.jsには、異なるコンテキストでコードを実行できるvm



モジュールがあります。



  var vm = require('vm'); var ourArray = Array; var ourSymbol = Symbol('uuid'); var theirArray = vm.runInNewContext('Array'); var theirSymbol = vm.runInNewContext('Symbol("uuid")'); ourArray === theirArray; // false ourSymbol === theirSymbol; // false
      
      





現在のコンテキストのArray



は、別のコンテキストのArray



と等しくないことがわかります(それぞれに独自のコピーがあります)。 iframeとシンボルを使用した場合と同様の動作は、異なるコンテキストで互いに等しくありません。



  var vm = require('vm'); var ourSymbol = Symbol.for('uuid'); var theirSymbol = vm.runInNewContext('Symbol.for("uuid")'); ourSymbol === theirSymbol; // true
      
      





Symbol.for



を介してシンボルを宣言するSymbol.for



、すべてのコンテキストでそれらを使用する機会が得られます。 プロジェクトが特定のコンテキストでコードを実行するvm



モジュールを使用している場合、 Symbol.for



を使用することはこの状況で優れたソリューションとなります。



レジストリにシンボルを追加するためのキーを取得できるメソッド、 Symbol.keyFor



あります。



  var UUIDSymbolKey = Symbol.keyFor( UUIDSymbol );
      
      





指定された文字がレジストリで見つからない場合、 undefined



が返されます。



もう一度、 Symbol('score')



を使用してシンボルを作成しても、グローバルレジストリにシンボルが作成されないことに注意してください。



次の部分では、 Symbol



オブジェクトについて引き続き検討し、よく知られているシンボルの概念に触れ、それらがどのような機会を私たちにもたらすかを見ていきます。



All Articles