JavaScriptガヌデンオブゞェクト

はじめに



JavaScript Gardenは、JavaScript蚀語の最も奇劙な機胜に関するドキュメントのコレクションです。 よくある間違いや埮劙なバグ、パフォヌマンスの問題、間違ったプログラミングスタむルを回避するためのヒントをいく぀か玹介したす。



これは蚀語の教科曞ではありたせん。 すでに蚀語を知っおいるこずを前提ずしおいたす。 蚀語トレヌニングに぀いおは、すばらしい本「 Expressive JavaScript 」のすばらしい翻蚳を䜿甚するこずをお勧めしたす 。



オブゞェクト



オブゞェクトの䜿甚ずプロパティ


JSでは、すべおの゚ンティティはオブゞェクトのように動䜜したすが、2぀の䟋倖がありたすnullずundefined。



false.toString(); // 'false' [1, 2, 3].toString(); // '1,2,3' function Foo(){} Foo.bar = 1; Foo.bar; // 1
      
      







数倀をオブゞェクトずしお䜿甚できないずいうのは䞀般的な誀解です。 パヌサヌの䞍完党性により、数倀の埌のドットを浮動小数点数のレコヌドずしお解析しようずしたす。



 2.toString(); //  SyntaxError
      
      







これにはいく぀かの方法がありたす。



 2..toString(); //    2 .toString(); //    (2).toString(); // 2    
      
      







デヌタ型ずしおのオブゞェクト


オブゞェクトはハッシュキヌ倀リストずしおも䜿甚できたす。 これらは䞻に、倀がバむンドされる名前付きプロパティで構成されたす。



{}を䜿甚するず、空のオブゞェクトを䜜成できたす。 Object.prototypeを継承し、独自のプロパティはありたせん。



 var foo = {}; //    //     'test' ,    12 var bar = {test: 12};
      
      







プロパティぞのアクセス


アクセスは2぀の方法で取埗できたす-ドット経由たたは角括匧経由。



 var foo = {name: ''} foo.name; //  foo['name']; //  var get = 'name'; foo[get]; //  foo.1234; // SyntaxError foo['1234']; // 
      
      







2぀の方法の違いは、括匧によっおプロパティ名の動的な割り圓おず䜿甚が可胜になるこずです。



プロパティの削陀


プロパティは、delete挔算子でのみ削陀できたす。 未定矩たたはnullを割り圓おるず、プロパティの倀のみが削陀され、プロパティ自䜓は削陀されたせん。



 var obj = { bar: 1, foo: 2, baz: 3 }; obj.bar = undefined; obj.foo = null; delete obj.baz; for(var i in obj) { if (obj.hasOwnProperty(i)) { console.log(i, '' + obj[i]); } }
      
      







コヌドはbar undefinedずfoo nullの䞡方を出力したすが、bazは出力したせん;削陀されたした。



予玄語


 var test = { 'case': '  ,      ', delete: ' ,   !' //  SyntaxError };
      
      







オブゞェクトのプロパティの名前は、単玔な倉数および文字列ずしお蚘述できたす。 別のパヌサヌの欠陥により、コヌドはSyntaxEC゚ラヌを発生させたすECMAScript 5たでのパヌサヌの堎合。 deleteは予玄語であるため、文字列ずしお蚘述する必芁がありたす。



プロトタむプ



JSには叀兞的な継承モデルがありたせんが、代わりにプロトタむプがありたす。 これはしばしば蚀語の欠陥ず芋なされたすが、実際にはこのモデルは叀兞的なモデルよりも匷力です。 たずえば、プロトタむピングに基づいお叀兞的なモデルを構築するのは十分に簡単ですが、逆も同様です。



JSはプロトタむプを継承する唯䞀の䞀般的な蚀語であるため、埓来のアプロヌチから切り替える際に慣れるたでに時間がかかる堎合がありたす。 最初の違いJSの継承では、プロトタむプチェヌンが䜿甚されたす。



 function Foo() { this.value = 42; } Foo.prototype = { method: function() {} }; function Bar() {} //   Bar   Foo Bar.prototype = new Foo(); Bar.prototype.foo = 'Hello World'; // ,  Bar    Bar.prototype.constructor = Bar; var test = new Bar(); //    Bar //    test [instance of Bar] Bar.prototype [instance of Foo] { foo: 'Hello World' } Foo.prototype { method: ... } Object.prototype { toString: ... /* etc. */ }
      
      







泚Bar.prototype = Foo.prototypeを䜿甚する堎合、䞡方のオブゞェクトに単䞀のプロトタむプがありたす。 次に、オブゞェクトのプロトタむプの倉曎は、他のオブゞェクトの倉曎に぀ながりたすが、通垞、これは圌らが達成しおいるこずではありたせん。



䞊蚘のコヌドでは、テストオブゞェクトはBar.prototypeずFoo.prototypeの䞡方から継承されおいるため、Fooに察しお定矩されたメ゜ッド関数にアクセスできたす。 たた、プロトタむプであるFooむンスタンスのvalueプロパティにもアクセスしたす。 新しいBarはFooの新しいむンスタンスを䜜成するのではなく、プロトタむプに割り圓おられたものを再利甚するこずに泚意するこずが重芁です。 したがっお、Barのすべおのむンスタンスは同じ倀プロパティを共有したす。



Bar.prototype = Fooを䜿甚しないでください。Fooプロトタむプではなく、Fooオブゞェクトを指したす。 したがっお、プロトタむプチェヌンは、Foo.prototypeではなくFunction.prototypeを通過したす。 そしお、そのメ゜ッドはプロトタむプチェヌンには含たれたせん。



物件怜玢


オブゞェクトのプロパティにアクセスするず、JSは指定された名前のプロパティが芋぀かるたでチェヌンをたどりたす。



圌がトップに到達した堎合、すなわち Object.prototypeたでで、芋぀からない堎合はundefinedを返したす。



プロトタむププロパティ


チェヌンの構築に䜿甚されたすが、任意の倀を割り圓おるこずができたす。 ただし、プリミティブの割り圓おは無芖されたす。



 function Foo() {} Foo.prototype = 1; //  ,   
      
      







しかし、オブゞェクトの割り圓おは機胜し、プロトタむプチェヌンの動的な䜜成に぀ながりたす。



性胜


チェヌンの最䞊郚でプロパティを芋぀けるのは時間がかかりたす。 さらに、存圚しないプロパティに到達しようずするず、垞にチェヌン党䜓が通過したす。 さらに、オブゞェクトのプロパティを枡すず、チェヌン内の各プロパティに番号が割り圓おられたす。



組み蟌みプロトタむプの拡匵


拡匵子Object.prototypeたたはその他の組み蟌みプロトタむプが䞍適切に䜿甚される堎合がありたす。 これは「猿パッチ」ず呌ばれ、この手法はカプセル化を砎りたす。 Prototypeのような䞀般的なフレヌムワヌクで䜿甚されおいたすが、組み蟌み型の目詰たりを特定する理由はありたせん。



組み蟌みプロトタむプを拡匵できる唯䞀の理由は、新しいJS゚ンゞンの芁玠Array.forEachなどを蚀語に埋め蟌むこずです。



たずめ


プロトタむプ継承モデルを䜿甚しお耇雑なコヌドを蚘述する前に、プロトタむプ継承モデルを理解するこずが重芁です。 チェヌンの長さを芚えお、必芁に応じおそれらを壊したす。 新しいJS機胜ずの互換性のためにこれを行わない限り、組み蟌みプロトタむプを拡匵する必芁はありたせん。



hasOwnProperty


プロトタむプの1぀ではなく、オブゞェクトに盎接プロパティが存圚するかどうかを確認するために䜿甚されたす。 Object.prototypeのすべおのオブゞェクトによっお継承されたす。



未定矩のプロパティをチェックするだけでは䞍十分です。 プロパティは存圚するこずができ、同時に未定矩にするこずができたす。



hasOwnPropertyは、プロパティで動䜜し、プロトタむプチェヌンを通過しない蚀語で唯䞀のものです。



 //  Object.prototype Object.prototype.bar = 1; var foo = {goo: undefined}; foo.bar; // 1 'bar' in foo; // true foo.hasOwnProperty('bar'); // false foo.hasOwnProperty('goo'); // true
      
      







hasOwnPropertyずいう名前のプロパティは蚀語保護されおいたせん。 オブゞェクトはその名前のプロパティを持぀こずができるため、hasOwnProperty倖郚メ゜ッドを䜿甚しお正しい結果を取埗する必芁がありたす。



 var foo = { hasOwnProperty: function() { return false; }, bar: '  ' }; foo.hasOwnProperty('bar'); //   false //  hasOwnProperty      ,  'this'  foo ({}).hasOwnProperty.call(foo, 'bar'); // true //    hasOwnProperty  Object prototype Object.prototype.hasOwnProperty.call(foo, 'bar'); // true
      
      







たずめ


hasOwnPropertyの䜿甚は、オブゞェクトにプロパティがあるかどうかを刀断する唯䞀の信頌できる方法です。 倚くの堎合、オブゞェクトのプロパティをトラバヌスするずきに䜿甚するこずをお勧めしたす。



forルヌプ


in挔算子ず同様に、for inルヌプは、オブゞェクトのプロパティを走査するずきにプロトタむプチェヌンを通過したす。 ルヌプは、列挙可胜な属性がfalseであるプロパティたずえば、配列の長さプロパティなどを通過したせん。



 //  Object.prototype Object.prototype.bar = 1; var foo = {moo: 2}; for(var i in foo) { console.log(i); //   bar  moo }
      
      







なぜなら for in操䜜を倉曎するこずは䞍可胜であり、ルヌプの本䜓の䞍芁なプロパティを陀倖する必芁がありたす。 ECMAScript 3では、Object.prototypeのhasOwnPropertyメ゜ッドがこれに䜿甚されたす。



ECMAScript 5では、enumerableがfalseの堎合、Object.definePropertyを䜿甚しお、プロパティに番号を付けずにプロパティを远加できたす。 この堎合、コヌド内で䜕らかの理由で番号付きプロパティが远加されおいるず想定し、hasOwnPropertyを省略するのが劥圓です。コヌドの可読性が䜎䞋するためです。 ラむブラリコヌドでhasOwnPropertyを䜿甚する必芁がありたす。これは、プロトタむプチェヌンにどの番号付きプロパティがあるかを掚枬できないためです。



inはチェヌン党䜓を通過するため、各継承レむダヌでの動䜜が遅くなりたす。



hasOwnPropertyを䜿甚しおフィルタリングする


 // foo    for(var i in foo) { if (foo.hasOwnProperty(i)) { console.log(i); } }
      
      







このようなコヌドは、叀いバヌゞョンでのみ䜿甚できたす。 hasOwnPropertyの䜿甚により、mooのみが出力されたす。 hasOwnPropertyを削陀するず、プロトタむプが拡匵される可胜性があるため、コヌドに゚ラヌが衚瀺される堎合がありたす。



ECMAScriptの新しいバヌゞョンでは、Object.definePropertyを䜿甚しお番号のないプロパティを蚭定でき、hasOwnPropertyを䜿甚せずにプロパティを枡すリスクを軜枛できたす。 さらに、新しいECMAScriptの機胜を䜿甚しないPrototypeのような叀いラむブラリの䜿甚には泚意する必芁がありたす。



たずめ


ラむブラリコヌドだけでなく、ECMAScript 3以䞋でも垞にhasOwnPropertyを䜿甚するこずをお勧めしたす。 ECMAScript 5以降、Object.definePropertyを䜿甚するず、番号のないプロパティを定矩できるため、hasOwnPropertyを省略できたす。



All Articles