John Rezigの自己呌び出しコンストラクタヌず、この決定が根付かなかった理由に関する考察

異垞に䟿利なjQueryラむブラリヌの著名な䜜成者であるJohn Rezigのブログからのブログ投皿「 Simple」クラス「Instantiation 」で、4幎以䞊も粟神的に戻る時が来たした。 そしお戻っおきたす。



ただし、Habrahabr の怜玢結果には「Resig」ずいう単語がたったく衚瀺されないため、過去4幎間にわたっおこの䟿利なブログ投皿を翻蚳するたたは少なくずも再語するこずを誰も気にせずに考えなければなりたせん。 、Rezigのブログ投皿を私が自分の䞻な意図を果たす前に再語するこずRezigによっお提案された問題を解決するためにRezigによっお提案された方法が広たっおいない理由を考え出すこず。 そしお、私は蚀い盎したす。 読み盎し自䜓は、読者に䜕も远加しなかったずしおも、読者にずっおはすでに有甚です。远加したす。






2007幎12月6日に、Rezigはjavascriptで「new」操䜜を䜿甚しおオブゞェクトを䜜成した堎合に䜕が起こるかを調べたしたクラスを持぀蚀語では、「クラスむンスタンス」ず蚀いたす。



function User(first, last){ this.name = first + " " + last; } var user = new User("John", "Resig");
      
      





Rezigは、javascriptの初心者にずっお、関数コヌド内の「this」の出珟がオブゞェクトコンストラクタヌを持っおいるこずを瀺しおいるこずは明らかではないこずを正しく指摘したした。 自分で括匧を付けたす関数がラむブラリの腞内にある堎合、この状況も文曞化する必芁がありたす-そうでない堎合、ラむブラリナヌザヌは初心者ずそれほど倉わりたせん誰もが関数の本䜓で゜ヌスコヌドを読むわけではありたせん。倚くの堎合、瞮小された読み取り䞍胜な圢匏で䜿甚されたす。



したがっお、Rezigは、遅かれ早かれ誰かが 「 new 」なしで「 User 」を呌び出そうずし、それによっお頭に2぀の䞍快な問題が䞀床に生じるず掚論したした。 たず、倉数「 user 」は未定矩のたたです。関数「 User 」はコンストラクタヌずしお意図されおいたすが、倀を返したせん。 第二に、さらに悪いこずに、そのような誀っお呌び出されたコンストラクタヌ内からこれにアクセスしようずするず、必然的にグロヌバル名前空間が詰たりたす。これは、䞍吉でずらえどころのない結果に満ちおいたす。 John Resigは䟋を䜿甚しお䞡方の問題を瀺したした。



 var name = "Resig"; var user = User("John", name); //   «user»   //  :  «name»  é  «Resig»! if ( name == "John Resig" ) { // !
 }
      
      





それでも、Resigはさらに指摘し、コンストラクタヌの呌び出しは䟿利です。 プロトタむプの継承プロトタむプからオブゞェクトのプロパティを取埗する、぀たり実際のコンストラクタヌを呌び出すこずは、単玔な関数を呌び出しおオブゞェクトず同じプロパティを「構築」するよりもはるかに高速に動䜜するずいう利点がありたす。



 //    : function User(){} User.prototype = { /* 
 
 */ }; //     : function User(){ return { /* 
 
 */ }; }
      
      





Rezigは、䞀方ではコンストラクタヌずしお機胜しクむックプロトタむプの継承を提䟛する、他方では" new "なしで呌び出され、その堎合はリゟヌトずしお機胜するたびに関数を䜜成するのが良いず、ここから自然な結論を出したした。コンストラクタずしお自分自身に。 jQueryネむティブラむブラリの独自の関数$の䟋を䜿甚しお、Rezigは合理的に瀺しおいたす。たあ、ラむブラリナヌザヌが「 $「div」の代わりに「 new $「div」 」ず曞く必芁があるず䟿利でしょうか もちろん違いたす。



幞いなこずに、Resigは続けたした。これらすべおの問題は、関数本䜓の条件付き衚蚘を䜿甚した簡単な解決策に圹立ちたす。



 function User(first, last){ if ( this instanceof User ) { //    : this.name = first + " " + last; } else { //     : return new User(first, last); } }
      
      





ここでのinstanceof挔算子は、 新しい挔算子が関数呌び出しに関䞎しおいたかどうかを怜出するための最も重芁なツヌルです。これは簡単な䟋で簡単に衚瀺できたす。



 function test(){ alert( this instanceof test ); } test(); //   alert( false ); new test(); //   alert( true );
      
      





この゜リュヌションを芋぀けお、それが機胜しおいるこずを確認しおから、Rezig氏は次のように述べたした。次に、この゜リュヌションを「クラス」のコンストラクタヌを䜜成する䞀般的な方法でラップしたす。 この目的のために、John Rezigは次の無料のコヌドをレむアりトしたした。



 // makeClass - By John Resig (MIT Licensed) function makeClass(){ return function(args){ if ( this instanceof arguments.callee ) { if ( typeof this.init == "function" ) this.init.apply( this, args.callee ? args : arguments ); } else return new arguments.callee( arguments ); }; }
      
      





このコヌドを䜿甚する前の䟋は、前のコンストラクタヌの本䜓がプロトタむプの「 init 」メ゜ッドの本䜓になるように曞き盎す必芁がありたす。



 var User = makeClass(); User.prototype.init = function(first, last){ this.name = first + " " + last; }; var user = User("John", "Resig"); user.name //  «John Resig»
      
      





「 makeClass 」John Rezigの䜜業の論理も十分に詳现に説明されおいたす。 「 makeClass 」関数はコンストラクタヌではなく、コンストラクタヌを䜜成したす-このコンストラクタヌは、 「 makeClass 」 から返される匿名関数args関数です。 「クラス」の名前結果ずしおこの関数に䞎えられる名前はただ知られおいないため、実行時にサヌビスjavascriptプロパティ「 arguments.callee 」に頌り、そこから名前を取埗したす。 別のトリックは、この匿名関数が「 new 」なしで呌び出された堎合、コンストラクタヌの圹割で自分自身を呌び出すずきにその匕数「 arguments 」がその内郚に再枡されるこずです「 return new arguments.calleearguments 」 -そしお、この匕数のセットがargsパラメヌタヌになり、 initメ゜ッドに枡されたす 。






John Rezigの思慮深いブログの曞き盎しは終わりたした。 今、私は圌自身があたりにも賢いように思われる堎所に぀いお最終的に話すこずができたす。



圌のmakeClassアむデアの䞍快な芁玠は、 arguments.calleeプロパティの䜿甚です。 このプロパティは、ブラりザのパフォヌマンスの加速に関しお問題があるず考えられおいるため 䜕らかの理由で珟代のむンタプリタの最適化では察応できない、蚀語の新しいバヌゞョンECMAScript 5でニュアンスの1぀である「厳栌モヌド」も導入されたしたこれは、 「 arguments.callee 」の完党な拒吊です。 2009幎5月、ゞョン・レゞグ自身がこれに぀いお蚀及し 、 Habrahabrに移されたした 。



さたざたなjavascriptやラむブラリの䜜成者のコミュニティにおける「 arguments.callee 」に察するこの敵意は、時間の経過ずずもに、Rezigovの自己呌び出しコンストラクタヌ自䜓のアむデアに䞀郚シフトしおいるように思われたす。 " And" new $ "div" "は、この考えを支持する匷力で説埗力のある議論のようです。



自己呌び出しコンストラクタヌに察する敵意のもう1぀の理由は、 明らか に、「 new 」挔算子がJavaScript蚀語の重芁な郚分であるずいう考えです 。この挔算子の無知は非垞に恥ずかしいため、この挔算子の䞍圚によっお匕き起こされる゚ラヌを防ぐ必芁はありたせん。 コンピュヌタヌ科孊者の特に䟿利なツヌルに぀いおは、垞に自虐的なものがありたす。この感情は、助けを必芁ずする新参者に燃えるような嫌悪感を匕き起こす堎合がありたす。「いいえ、それはやりすぎ、簡単すぎたす。私はセックスをしたした。 



これは䜕床も芋たした。



私は、この2011幎5月にazproductionによっおコンパむルされたJavaScript FAQで 、次のように蚀われたこずを芚えおいたす 。



-新しいものを通しおオブゞェクトを䜜成するこずは、より良く、より身近で、むデオロギヌ的です。 デザむナヌは倧文字にする必芁がありたす。



-私は芏玄に基づいおいるこずを奜み、コンストラクタヌ内でこれをチェックしたせん-私は新しいコンストラクタヌを呌び出さず、したがっおグロヌバルに飛んでいたす-これは「愚か者自身」を意味したす。 そしお、決しお私はnewで゚ラヌを奚励したせん-䞀郚の人々はこれがグロヌバルなものであるかどうかを確認し、ナヌザヌがnewなしでコンストラクタを呌び出し、コンストラクタ内にオブゞェクトを䜜成しお返したす-これぱラヌぞの奚励であり、むデオロギヌ的に間違ったアプロヌチです。



匕甚の終わり。



たた、地図を衚瀺する矎しいリヌフレットラむブラリの䜜成者であるりラゞミヌルアガフォンキンの事䟋を芚えおいたす。 この2011幎8月に、圌はGithubでの合䜵のリク゚ストを受け取りたした。著者は、各デザむナヌの冒頭でこのコヌドのようなものを眮くこずを提案したした。



 if ( !(this instanceof arguments.callee) ){ return new arguments.callee(arguments); }
      
      





アガフォンキンはこれに答えた



-初心者のJS䜜成者が間違いを犯さないようにするこずは非垞に䟿利ですが、ナヌザヌに間違っおいるこずを䌝えるのではなく、誀った構文を蚱可するような鈍い蚀語のアむデアは奜きではありたせん。



-「new」がなくおもオブゞェクトのむンスタンスを䜜成するのではなく、「 new Error」「クラスコンストラクタヌの前に新しいキヌワヌドを眮くのを忘れた」のようなこずをした方が良いように思えたす。



-そしお、もう1぀ありたす。arguments.calleeは珟圚悪意があるず芋なされおいるため、クラス名を明瀺的に蚘述する方が安党です。



匕甚の終わり。



リク゚ストの䜜成者は、行っおarguments.calleeに぀いお読み、リク゚ストを取り消したした。 arguments.calleeの欠点ずnewの尊重により、再び自己呌び出しコンストラクタヌの実装が劚げられたこずがわかりたした。



どのリヌフレットナヌザヌが少なくずも「 クむックスタヌトガむド 」を読むかは、このラむブラリで定矩されおいるグロヌバルオブゞェクトが明らかに、簡朔にするために 単に 「 リヌフレット 」ではなく 単に「 L 」ず呌ばれるこずに気付くでしょう。 6文字が保存されたす。 ただし、コンストラクタヌの各呌び出しの前に「 new 」ずスペヌスを曞き蟌たないように、さらに4文字を保存するこずができたす。



John Rezigがarguments.calleeを完党に控え、自己呌び出しコンストラクタヌレコヌドの単なる良い䟋テンプレヌト、パタヌンに制限されおいれば、前向きに考えおいたず思うこずがありたす。



 function User(first, last){ if ( this instanceof User ) { //    : this.name = first + " " + last; } else { //     : return new User(first, last); } }
      
      





ただし、もちろん、関数党䜓に䜙分なif- wrapperを䜜成しないために、この䟋を単玔化する必芁がありたす。



 function User(first, last){ if (!(this instanceof User)) return new User(first, last); //         this.name = first + " " + last; // 
      
 }
      
      





そしお、 azproductionによっおコンパむルされたJavaScript FAQに敬意を衚する必芁がありたす。この簡略化もここにありたす。 そこではお勧めできたせん。



このような良い䟋に埓うのは簡単で楜しいです。 たた、コンストラクタヌコンストラクタヌよりも理解しやすくなっおいたす-javascriptオプティマむザヌをより明確に含みたす。



人生で同様の肯定的な䟋を最埌に芋たい堎合は、 ZIP ZIPアヌカむブを提䟛するパッケヌゞのzip.jsコヌドを芋おください-Node.jsの䞋に玔粋なjavascriptで曞かれおいたす  C ++の 1 行なし;私は知りたせんでしたそのようなクロスプラットフォヌムの傑䜜があるこず たったく同じコンストラクタヌの自己呌び出しが衚瀺されたす。



 var Reader = exports.Reader = function (data) { if (!(this instanceof Reader)) return new Reader(data); this._data = data; this._offset = 0; }
      
      





結論は簡単です。ゞョン・レゞグの䜜品を研究し、圌のアドバむスに埓い、圌の指瀺に埓っお行動しおください。 しかし、耇雑さの特定の制限にのみ。






付属物。 それにもかかわらず、2012幎7月末たでに、りラゞミヌルアゎンフォンキン  Mourner は、リヌフレットラむブラリで「新しい」オペレヌタヌなしで 実行できる機胜を実装したした 。 しかし、圌を玍埗させたのは私ではなく、 忘れられたハブラハブルのリヌフレットの批評を自分で批評しお投皿したのは、最埌に蚀ったに違いありたせん。



All Articles