CoffeeScript詳现なサむクルガむド

CoffeeScript詳现なサむクルガむド

ご存知のように、 CoffeeScriptはJavaScriptずは少し異なる制埡構造のセットを提䟛したす 。



蚀語開発者が文法を可胜な限り簡玠化し、すべおの指瀺の詳现な説明を行ったずいう事実にもかかわらず、倚かれ少なかれ非暙準のサむクルを䜜るこずは倧きな挑戊のたたです。









この蚘事では、 CoffeeScriptでルヌプを操䜜する原理ず密接に関連する制埡構造に぀いお可胜な限り詳现に説明しようずしたす。



すべおのコヌドには、 JavaScriptの比范䟋が付属しおいたす 。




For-in呜什


最も単玔なforルヌプから始めたしょう。



for (var i = 0; i < 10; i++) { //... } 

CoffeeScriptでは、次のように蚘述されたす。



 for i in [0...10] 

範囲は、反埩回数を決定するために䜿甚されたす。
この堎合、 0 ... 10の範囲は、ルヌプの10回の繰り返しを実行するこずを意味したす。


しかし、タむプi <= 10の条件を蚭定する必芁がある堎合はどうでしょうか



 for i in [0..10] 

䞀芋、䜕も倉わっおいたせんが、よく芋るず、範囲内で1぀のポむントが少なくなっおいるこずがわかりたす。



その結果、次の゚ントリが取埗されたす。



 for (var i = 0; i <= 10; i++) { //... } 

範囲の初期倀が最埌の[10..0]より倧きい堎合、結果が反転した逆サむクルが埗られたす。



 for (var i = 10; i >= 0; i--) { //.. } 

負の範囲倀の䜿甚も蚱容されるこずに泚意しおください



 for i in [-10..0] 

したがっお、配列に負の倀を入力できたす。

 [0..-3] #[0, -1, -2, -3] 

nの階乗を蚈算する関数の䟋を䜿甚しお、実際の状況を考えおみたしょう。



JavaScript

 var factorial = function(n) { var result = 1; for (i = 1; i <= n; i++) { result *= i; } return result; }; factorial(5) //120 


CoffeeScript

 factorial = (n) -> result = 1 for i in [1..n] result *= i result factorial 5 #120 

䞊蚘の䟋からわかるように、 CoffeeScriptコヌドはJavaScriptよりもコンパクトで読みやすいです。



ただし、このコヌドは少し簡略化できたす。



 factorial = (n) -> result = 1 result *= i for i in [1..n] result 

この蚘事では、これは階乗蚈算の最埌の䟋ではなく、より効果的な方法に぀いおは少し埌で怜蚎したす。



[...]

トピックから少し逞脱しお、構成の適甚に関連する別の興味深い点に蚀及するこずを蚱可したす[...]スラむス 。



他の誰かのコヌドには、次のような構造が芋぀かるこずがありたす。



 'a,b,c'[''...][0] 

もちろん、これは次のこずを意味したす。



 'a,b,c'.slice('')[0]; //a 

䞀芋したずころ、範囲をスラむスず区別するこずは非垞に困難です。 䞻に2぀の違いがありたす。



最初に、スラむスの1぀の極端な倀をスキップできたす



 [1...] 

ここでは、この衚珟の翻蚳埌に埗られるものに特に泚意を払いたいず思いたす。



 var __slice = Array.prototype.slice; __slice.call(1); 

これは、関数の匕数のリストを取埗するなど、倚くの状況で䟿利です。

 fn = -> [arguments...] fn [1..3] #0,1,2,3 


CoffeeScriptには、関数匕数のリストを取埗するためのより安党で゚レガントなオプション splats があるこずに泚意しおください。

 fn = (args...) -> args fn [1..3] #0,1,2,3 

算術挔算ず論理挔算を䜿甚するこずもできたす。

 [1 + 1...] 


第二に、スラむスの前にオブゞェクトが蚱可されたす



 [1..10][...2] #1,2 


第䞉に、スラむスでの列挙の䜿甚は蚱可されたす



 [1,2,3...] 

この䟋では、単玔な連結操䜜を実行したす。

 [1, 2].concat(Array.prototype.slice.call(3)); //[1,2,3] 

より䟿利な䟋



 list1 = [1,2,3] list2 = [4,5,6] [list1, list2 ...] #[1,2,3,4,5,6] 


リストの理解


CoffeeScriptでオブゞェクトを操䜜するための最も印象的な構文は、 リストの内包衚蚘です。



1からnたでのすべおの階乗蚈算のリストを取埗する方法の䟋



 factorial = (n) -> result = 1 result *= i for i in [1..n] factorial 5 #1,2,6,24,120 

次に、より興味深い䟋を芋お、 ロケヌションオブゞェクトの最初の5぀のメンバヌをリストしたす。



 (i for i of location)[0...5] # hash, host, hostname, href, pathname 

JavaScriptでは、このコヌドは次のようになりたす。



 var list = function() { var result = []; for (var i in location) { result.push(i); } return result; }().slice(0, 5); 

配列の芁玠むンデックスではないのリストを衚瀺するには、もう1぀のパラメヌタヌを蚭定する必芁がありたす。



 foo = (value for i, value of ['a', 'b', 'c'][0...2]) # [ a, b ] 

䞀方では、リスト匏はオブゞェクトを操䜜するための非垞に効率的でコンパクトな方法です。 䞀方、 JavaScriptで翻蚳した埌にどのコヌドを受け取るかを明確に理解する必芁がありたす 。



たずえば、 0〜2の芁玠のリストを衚瀺する䞊蚘のコヌドは、次のようにさらに効果的に曞き換えるこずができたす。



 foo = (value for value in ['a', 'b', 'c'][0...2]) 

たたは

 ['a', 'b', 'c'].filter (value, i) -> i < 2 

この時点で、メ゜ッド名ず開き括匧の間のスペヌスに特に泚意しおください。 このギャップが必芁です

スペヌスをスキップするず、次のようになりたす。

 ['a', 'b', 'c'].filter(value, i)(function() { return i < 2; }); //ReferenceError: value is not defined! 

今、あなたはおそらく.filterオプションが最も奜たれた理由を知りたいず思うでしょうか


実際のずころ、 for-ofステヌトメントを䜿甚するず、トランスレヌタヌは必芁なルヌプよりも遅いバヌゞョン、぀たりfor-inを眮き換えたす。



ブロヌドキャスト結果


 var i, value; [ (function() { var _ref, _results; _ref = ['a', 'b', 'c'].slice(0, 2); _results = []; for (i in _ref) { value = _ref[i]; _results.push(value); } return _results; })() ]; 

それに盎面しよう、結果のコヌドはひどいです。


ここで、 フィルタヌメ゜ッドを䜿甚しお取埗したコヌドを芋おみたしょう。



 ['a', 'b', 'c'].filter(function(value, i) { return i < 2; }); 

ご芧のずおり、完璧で効率的なコヌドが埗られたした



サヌバヌでCoffeeScriptを䜿甚する堎合、心配する必芁はありたせん。そうでない堎合は、 IE9-がフィルタヌメ゜ッドをサポヌトしおいないこずを芚えおおく必芁がありたす。 したがっお、あなた自身がその可甚性に泚意する必芁がありたす



その埌、挔算子


ご存知のように、 匏を解釈するために、 CoffeeScriptパヌサヌはむンデント、改行、キャリッゞリタヌンなどを解析したす。



以䞋は、数倀を1からnの2の环乗に増やす䞀般的なサむクルです。



 for i in [1...10] i * i 

わかりやすくするために、改行ずむンデントを䜿甚したした。


ただし、実際の状況では、ほずんどの開発者はこの匏を1行で蚘述するこずを奜みたす。



 for i in [1...10] then i * i 

while 、 if / else 、およびswitch / whenステヌトメントでは、 thenステヌトメントはパヌサヌに匏を分離するように指瀺したす。



オペレヌタヌ


ここたでは、「 単玔な 」サむクルのみを考慮しおきたしたが、特定のステップで倀が欠萜しおいるサむクルに぀いお説明したす。



2〜10の偶数のみを出力したす。



 alert i for i in [0..10] by 2 #0,2,4,6,8,10 

JavaScriptでは、このコヌドは次のようになりたす。



 for (var i = 2; i <= 10; i += 2) { alert(i); } 

by挔算子は、反埩ステップを蚭定できる芁玠の範囲に適甚されたす。



配列の数倀や芁玠だけでなく、文字列でも䜜業できたす。



 [i for i in 'Hello World' by 3] #H,l,W,l 

byおよびthen挔算子は䞀緒に䜿甚できたす。



 [for i in 'hello world' by 1 then i.toUpperCase()] # H,E,L,L,O, ,W,O,R,L,D 

この䟋は少し難解であり、実際の状況では「 1぀ 」のステップを単玔化する必芁がありたすが、それでも、 その埌の挔算子の共同䜜業により、非垞にコンパクトで効率的なコヌドを蚘述できたす。



自分のオペレヌタヌ


JavaScriptは倚くの堎合、 .hasOwnPropertyメ゜ッドを䜿甚したす。このメ゜ッドは、in挔算子ずは異なり、オブゞェクトプロトタむプチェヌンのプロパティをチェックしたせん。

 var object = { foo: 1 }; object.constructor.prototype.bar = 1; console.log('bar' in object); // true console.log(object.hasOwnProperty('bar')); // false 

for-inルヌプの本䜓で.hasOwnPropertyメ゜ッドを䜿甚する䟋を考えおみたしょう。

 var object = { foo: 1 }; object.constructor.prototype.toString = function() { return this.foo; }; for (i in object) { if (object.hasOwnProperty(i)) { console.log(i); //foo } } 

.toStringメ゜ッドをプロトタむプオブゞェクトに远加したにもかかわらず、ルヌプの本䜓にはリストされたせん。 盎接アクセスできたすが

 object.toString() //1 

CoffeeScriptは、これらの目的のために独自の特別な挔算子を提䟛したす

 object = foo: 1 object.constructor::toString = -> @foo for own i of object console.log i #foo 

for-ofステヌトメントの2番目のキヌを䜿甚する必芁がある堎合は、カンマで区切っお指定する必芁があり、 独自の挔算子を再床远加する必芁はありたせん。

 for own key, value of object console.log '#{key}, #{value}' #foo, 1 


条件付きif / elseステヌトメント


ここで、if / elseステヌトメントずルヌプを共有するこずに関連する非垞に重芁なポむントに泚目したいず思いたす。



JavaScriptアプリケヌションでは、同様のコヌドに遭遇する堎合がありたす。



 for (var i = 0; i < 10; i++) if (i === 1) break; 

この方法を曞いおいる開発者に぀いおは議論せず、特に非難したせん。


CoffeeScriptで匏を正しく蚘述する方法のみが重芁です。



最初に頭に浮かぶのは、これを行うこずです。



 for i in [0..10] if i is 1 break # Parse error on line 1: Unexpected 'TERMINATOR' 

しかし、 CoffeeScriptの 字句解析ルヌルによるず、 ifステヌトメントの前に予期しない端末倀が怜出され、解析゚ラヌが発生したす



前の資料から、 then挔算子を䜿甚しお匏を1行で実装できるこずを芚えおいたす。



 for i in [0..10] then if i is 1 break #Parse error on line 1: Unexpected 'POST_IF' 

ただし、これは圹に立ちたせんでした。解析゚ラヌが再び衚瀺されたす。



それを理解しおみたしょう...


実際には、 ifステヌトメントは、 thenステヌトメントを䜿甚できる他の呜什ず同じ芏則に埓いたす。 ぀たり、匏が正しく解析されるようにするには、匏の埌にif挔算子を再床远加する必芁がありたす。



 for i in [0..10] then if i is 1 then break 

したがっお、次のコヌドを取埗したす。



 for (i = 0; i <= 10; i++) { if (i === 1) { break; } } 

サむクルの前に、Cのパフォヌマンスを確認する必芁がある堎合がありたす。 条件



 if (foo === true) { for (i = 0; i <= 10; i++) { if (i === 1) { break; } } } 

非決定論的なデヌタ凊理ずリスト匏の䜿甚により、次のようにコヌドを衚珟できたす。



 (if i is 1 then break) for i in [0..10] if foo is on 

この堎合、解析゚ラヌは発生しなかったが、 then挔算子を䜿甚しなかったずいう事実に泚意しおください



When句


byおよびthenステヌトメントに぀いおはすでに説明したしたが、リストの次のステヌトメント、぀たり条件付きwhenステヌトメントに぀いお説明したす。



そしお、前の䟋の修正から始めたしょう。



 if foo is on then for i in [0..10] when i is 1 then break 

この堎合、コヌドは以前のバヌゞョンよりも少し倧きいこずが刀明したしたが、衚珟力ず意味がはるかに倚くなりたした。



正の敎数nを法ずしお1から10たでの数字の順序を掚定する方法の別の䟋を芋おみたしょう。



 alert i for i in [1..10] when i % 2 is 0 

JavaScriptコヌドに倉換した埌



 for (i = 1; i <= 10; i++) { if (i % 2 === 0) { alert(i); } } 

ご芧のずおり、when挔算子を䜿甚するず、配列を操䜜するためのオプションがさらに増えたす。



For-of呜什


リスト匏を芋おいるずきにfor-ofステヌトメントを䜿甚する䟋を芋おきたした。 次に、 for-ofステヌトメントを詳しく芋おみたしょう。for -inを䜿甚するず、オブゞェクトのプロパティを反埩凊理できたす。



JavaScriptの for-inステヌトメントず比范しお、すぐに比范しおみたしょう。



 var object = { foo: 0, bar: 1 }; for (var i in object) { alert(key + " : " + object[i]); //0 : foo, 1 : bar } 

ご芧のずおり、次の構文を䜿甚しおオブゞェクトプロパティの倀を取埗したした object [i] 。


CoffeeScriptでは、すべおがより簡単です。たず、リスト匏を䜿甚しおオブゞェクトの倀を取埗できたす。



 value for key, value of {foo: 1, bar: 2} 

第二に、より耇雑な匏の堎合、䜿い慣れた挔算子を䜿甚しおより広範な衚蚘法を適甚できたす。



 for key, value of {foo: 1, bar: 2} if key is 'foo' and value is 1 then break 

JavaScriptでは 、次のように同じ結果を取埗できたす。



 var object = { foo: 1, bar: 2 }; for (key in object) { if (key === 'foo' && object[i] === 1) { break; } } 

for-inを効果的に䜿甚する別の䟋



 (if value is 1 then alert "#{key} : #{value}") for key, value of document #ELEMENT_NODE : 1, #DOCUMENT_POSITION_DISCONNECTED : 1 

キヌメ゜ッドがオブゞェクトプロパティのリストを取埗する最も効果的な方法であるこずを思い出させおください。



 Object.keys obj {foo: 1, bar: 2} # foo, bar 

プロパティ倀を取埗するには、 keysメ゜ッドをmapメ゜ッドず組み合わせお䜿甚​​する必芁がありたす。



 object = foo: 1 bar: 2 Object.keys(object).map (key) -> object[key]; # 1, 2 


whileステヌトメント


for-of / inステヌトメントに加えお、 CoffeeScriptはwhileステヌトメントも実装したす。



for-inステヌトメントを芋たずき、 nの事実を蚈算するさらに効率的な方法を瀺すず玄束したした。時間がちょうどいいです



 factorial = (n) -> result = 1 while n then result *= n-- result 

率盎に蚀っお、最も゚レガントな階乗解は次のずおりです。



 factorial = (n) -> !n and 1 or n * factorial n - 1 


ルヌプ呜什


無限ルヌプを䜜成するこずが唯䞀の目的であるため、この呜什に぀いおは長い間説明したせん。



 loop then break if foo is bar 


Reltatブロヌドキャスト



 while (true) { if (foo === bar) { break; } } 


指導たで


untilステヌトメントはwhileむンストルメンテヌションに䌌おいたすが、1぀の䟋倖は吊定が匏に远加されるこずです。


これは、たずえば、文字列内の次の文字セットの䜍眮を芋぀けるのに圹立ちたす。



 expr = /foo/g; alert "#{array[0]} : #{expr.lastIndex}" until (array = expr.exec('foofoo')) is null 

Reltatブロヌドキャスト



 var array, expr; expr = /foo*/g; while ((array = expr.exec('foofoo')) !== null) { alert("" + array[0] + " : " + expr.lastIndex); } //foo : 3, foo : 6 

䟋からわかるように、匏の結果がれロになるたでルヌプが実行されたす。



Do-whileステヌトメント


CoffeeScriptには do-whileステヌトメントの実装がないこずをすぐに蚀いたす。 ただし、単玔な操䜜を䜿甚するず、 loopステヌトメントを䜿甚しお郚分的な動䜜を出力するこずができたす 。



 loop #... break if foo() 


配列メ゜ッドフィルタヌ、forEach、マップなど


ご存知のように、 CoffeeScriptでもJavaSctiptず同じメ゜ッドがすべお利甚可胜です。


メ゜ッドのこのグルヌプ党䜓を分析するこずは意味がありたせん;䟋ずしおmapメ゜ッドを䜿甚した䞀般的な動䜜原理のみを考慮したす。



3぀の芁玠の配列を䜜成し、それぞれを正方圢にしたす。



 [1..3].map (i) -> i * i 

Reltatブロヌドキャスト



 [1, 2, 3].map(function(i) { return i * i; }); 

別の䟋を考えおみたしょう



 ['foo', 'bar'].map (value, i) -> "#{value} : #{i}" #foo : 0, bar : 1 

2番目の匕数であるmapメ゜ッドは、呌び出しコンテキストを受け入れたす。



 var object = new function() { return [0].map(function() { return this }); }; // [Window map] 

マップ内でこれを芋るこずができるように、 Windowを指し、呌び出しのコンテキストを倉曎するには、明瀺的にこれを行う必芁がありたす。



 var object = new function() { return [0].map(function() { return this; }, this); }; // [Object {}] 

CoffeeScriptは、この目的のために特別な= =挔算子を䜿甚したす。



 object = new -> [0].map (i) => @ 

Reltatブロヌドキャスト



 var object = new function() { var _this = this; return [0].map(function() { return _this; }, this); }; 

぀たり、これらの配列メ゜ッドを可胜な限り䜿甚したす。



github'eに投皿したこれらのメ゜ッドのクロスブラりザヌ実装


CoffeeScriptで マップおよびフィルタヌメ゜ッドを䜿甚する実際の䟋は、 github'eの私のプロゞェクトの1぀でも芋るこずができたす。



指瀺/短絡を行う


ご存知のように、 JavaScriptはClosuresを積極的に䜿甚したすが、 CoffeeScriptもこの喜びを奪いたせん。



匿名の自己結合関数を䜜成するために、 CoffeeScriptはdoステヌトメントを䜿甚したす。このステヌトメントは任意の数の匕数を取りたす。



䟋を考えおみたしょう



 array = []; i = 2 while i-- then array[i] = do (i) -> -> i array[0]() #0 array[1]() #1 

このコヌドの本質は、配列を埋めるこずです。 同時に、配列の芁玠には基本的な倀は含たれたせんが、関数はそれぞれ芁玠のむンデックスを返したす。



JavaScriptでは、コヌドは次のようになりたす。



 var array = [], i = 2; while (i--) { array[i] = function(i) { return function() { return i; }; }(i); } array[0]() //0 array[1]() //1 


ネストされた呜什


ネストされた呜什は他の呜什ず違いはなく、同じ芏則に埓いたす。

たずえば、配列を1から3のペアの芁玠で埋めたす。

 list = [] for i in [0..2] for j in [1..2] list.push i list # [0,0,1,1,2,2] 

ご芧のずおり、耇雑なこずは䜕もありたせん

おそらく、これを1行で曞きたいず思うでしょう。 それでは、゚ントリを単玔化しおみたしょう。

 list = [] for i in [0..2] then for j in [1..2] then list.push i 

PS私は個人的にそのようなレコヌドを䜿甚したせんが、遅かれ早かれ他の誰かのコヌドを操䜜しなければならないので、これを曞くこずも蚱されるこずを知っおおくべきです。

しかし、2番目のサむクルの前に䜕らかの匏を远加する必芁がある堎合はどうでしょうか。

䟋ずしお、0〜3から芁玠の3぀のペアを導き出したす。

 list = [] for i in [0..2] list.push i for j in [1..1] list.push i list #[0,0,1,1,2,2] 


これは正しいオプションであり、改善すべき点はあたりありたせん。 2行目の前に明瀺的な識別が必芁なので、すべおを1行で曞くこずもできたせん。 しかし、サむクルの本䜓は短い衚蚘で曞くこずができたす。

 list = [] for i in [0..2] list.push i list.push i for j in [1..1] list #[0,1,2,3] 


3行目では、録音のプレフィックス圢匏ずポストフィックス圢匏の䞡方を䜿甚できたす。

jQueryなど


CoffeeScriptの堎合 、どのJavaScriptラむブラリを䜿甚しおも問題ありたせん。



最も重芁なjQuery関数-.readyから始めたしょう

.ready

 $ -> @ 

ブロヌドキャスト結果


 $(function() { return this; }); 

私はあなたのこずは知りたせんが、そのような蚘録はほずんどい぀も掻発な笑いを匕き起こしたす



リストの次のjQueryメ゜ッドは.eachです 。これは、暙準の.forEachメ゜ッドずほが同等です。

$ .each

 $.each [1..3], (i) -> i 

ブロヌドキャスト結果



 $.each([1, 2, 3], function(i) { return i; }); 


ECMASctipt 6


ECMASctipt 6暙準の将来の開発に興味がない堎合は、このセクションを安党にスキップできたす。

ご存知のように、将来のECMASctipt 6暙準では、ゞェネレヌタ、むテレヌタ、リスト匏を実装する予定です。
Firefoxは珟圚、ほずんどのドラフト暙準をサポヌトしおいたす。

なぜこれをしおいるのですか

実際、将来のES6構文は、今日のCoffeeScriptずほが完党に互換性がありたせん。

たずえば、呜什のfor ...は必芁以䞊に䞀般的になりたした。

 [value for key, value of [1,2,3]] 

出力では、次の異垞が発生したす。

 var key, value; [ (function() { var _ref, _results; _ref = [1, 2, 3]; _results = []; for (key in _ref) { value = _ref[key]; _results.push(value); } return _results; })() ]; //[1, 2, 3] 

将来の暙準では、オブゞェクトを介した反埩の䜿甚が可胜になりたすが、これははるかに簡単です。

 [for i of [1,2,3]] 

すごいですね。

匏ゞェネレヌタも利甚できたす

 [i * 2 for each (i in [1, 2, 3])]; //2,4,6 

このような蚘録も可胜になりたす。

 [i * 2 for each (i in [1, 2, 3]) if (i % 2 == 0)]; //2 

むテレヌタも利甚可胜になりたす

 var object = { a: 1, b: 2 }; var it = Iterator(lang); var pair = it.next(); //[a, 1] pair = it.next(); //[b, 2] 

むテレヌタは、匏ゞェネレヌタず組み合わせお䜿甚​​するこずもできたす。

 var it = Iterator([1,2,3]); [i * 2 for (i in it)]; //1, 4, 6 


新しい暙準のリリヌスにより、 CoffeScriptからの倚くのチップはそのようなものではなくなり、カヌネル開発者は砂糖の䜍眮を維持するために倚くの䜜業を行う必芁があるこずは明らかです。 圌らの幞運を祈りたす。

Source: https://habr.com/ru/post/J140764/


All Articles