毎日たくさんのツールを使用しています。さまざまなライブラリとフレームワークが私たちの毎日の仕事の一部です。ボンネットの下で何が起こっているのかわからなくても、すべてのプロジェクトのホイールを再発明したくないので、それらを使用します。この記事では、最も人気のあるライブラリで起こっている魔法のプロセスのいくつかを明らかにします。また、彼らの動作を再現できるかどうかも確認します
キーテイクアウト視覚的には、ページに違いはありません。ただし、Chromeの開発者ツールで生成されたマークアップを確認すると、興味深い結果が得られます。
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
stringtodom関数は、実際の
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
マップがあるため、最終的にどのようなタグが必要かを確認する必要があります。次のコードでは、
残りは適切なコンテキストを見つけて、DOM要素を返しています。これは、関数stringtodom:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
文字列にタグがあるかどうかを確認していることに注意してください - 一致!= null。そうでない場合は、単にテキストノードを返します。一時的な
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
CodepenでKrasimir Tsonev(@krasimir)によるPen xlcgnを参照してください。
素晴らしいAngularJS依存関係の注入を調査して続けましょう
AngularJS依存性注入を明らかにしますangularjsの使用を開始すると、双方向のデータバインディングに感銘を与えます。 2番目のことは、その魔法の依存噴射です。簡単な例を次に示します:
システムにユーザーを表示するJavaScript関数があります。同じ関数は、生成されたHTMLを配置するためにDOM要素にアクセスし、データを取得するAJAXラッパーにアクセスする必要があります。例を簡素化するために、データとHTTPの要求を模倣します。
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
コンテンツホルダーとして
タグを使用します。 AjaxWrapperはリクエストをシミュレートするオブジェクトであり、DataMockupはユーザーを含む配列です。使用する関数は次のとおりです<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
Ajaxパラメーターが定義されていないため、
そしてそれは正常です。<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
依存関係注入のメカニズムを提供するフレームワークのほとんどには、通常は
injectorという名前のモジュールがあります。依存関係を使用するには、そこに登録する必要があります。その後、ある時点で、当社のリソースは、同じモジュールによってアプリケーションのロジックに提供されます。 インジェクターを作成してみましょう:
2つの方法は必要です。最初のものである登録は、リソース(依存関係)を受け入れ、内部に保存します。 2番目のものは、注入のターゲット、つまり依存関係を持つ関数とパラメーターとして受信する必要がある関数を受け入れます。ここでの重要な瞬間は、インジェクターが関数を呼び出すべきではないことです。それが私たちの仕事であり、私たちはそれをコントロールできるはずです。 Resolveメソッドでできることは、ターゲットをラップして呼び出す閉鎖を返すことです。たとえば、
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
そのアプローチを使用して、必要な依存関係を持つ関数を呼び出す機会があります。同時に、アプリケーションのワークフローを変更していません。インジェクターはまだ独立したものであり、ロジック関連の機能を保持していません。
もちろん、displayUsers関数をResolveメソッドに渡すことは役に立ちません。<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>
それでも同じエラーが発生します。次のステップは、合格したターゲットが必要とするものを見つけることです。その依存関係は何ですか?そして、これがAngularjsから採用できるトリッキーな部分です。繰り返しますが、フレームワークのコードを少し掘り下げて、これを見つけました:
実装の詳細に似ているため、意図的にいくつかの部品をスキップしました。それが私たちにとって興味深いコードです。注釈関数は、Resolveメソッドのようなものです。渡されたターゲット関数を文字列に変換し、コメント(存在する場合)を削除し、引数を抽出します。それを使用して、結果を見てみましょう:
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>
ここにコンソールの出力があります:
<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>
<span>var dataMockup = ['John', 'Steve', 'David']; </span><span>var body = document.querySelector('body'); </span><span>var ajaxWrapper = { </span> <span>get: function(path<span>, cb</span>) { </span> <span>console.log(path + ' requested'); </span> <span>cb(dataMockup); </span> <span>} </span><span>}</span>
argdeclアレイの2番目の要素を取得すると、必要な依存関係の名前が見つかります。名前を使用すると、インジェクターのストレージからリソースを配信できるため、まさにそれが必要なものです。これが私たちの目標をうまくカバーするバージョンです:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
.split(/、?/g)を使用して文字列ドメル、ajaxを配列に変換していることに注意してください。その後、依存関係が登録されているかどうかを確認し、はいの場合はターゲット関数に渡すかどうかを確認します。インジェクターの外側のコードは次のようになります
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
もちろん、私たちのインジェクターは完璧ではありません。たとえば、スコープ定義のサポートなど、改善の余地がまだあります。現在、ターゲット関数は新しく作成されたスコープで呼び出されますが、通常は独自のスコープを渡したいと思うでしょう。また、依存関係とともにカスタム引数を送信することもサポートする必要があります。
削除後にコードを動作させたい場合、インジェクターはさらに複雑になります。私たちが知っているように、ミニファイヤーは関数、変数、さらにはメソッドの引数の名前を置き換えます。そして、私たちのロジックはこれらの名前に依存しているため、回避策について考える必要があります。考えられる解決策の1つは、Angularjsから再び登場することです:
displayUsersのみの代わりに、実際の依存関係の名前を渡しています。
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
実際の例:
CodepenでKrasimir Tsonev(@krasimir)によるペンBxdarを参照してください。 Emberの計算されたプロパティの採用
Emberは、最近で最も人気のあるフレームワークの1つです。たくさんの便利な機能があります。特に興味深いものがあります - 計算されたプロパティ。要約すると、計算されたプロパティは、プロパティとして機能する関数です。 Emberのドキュメントから撮影した簡単な例を見てみましょう:
FirstNameおよびLastNameプロパティを備えたクラスがあります。計算されたプロパティのフルネームは、その人のフルネームを含む連結文字列を返します。奇妙なことは、フルネームに適用された関数に対して.propertyメソッドを使用する部分です。私は個人的にそれを他のどこにも見ませんでした。そして、繰り返しになりますが、フレームワークのコードをすばやく見て、魔法が明らかになります:
<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
ライブラリは、新しいプロパティを追加することにより、グローバル関数オブジェクトのプロトタイプを微調整します。クラスの定義中にロジックを実行するのは素晴らしいアプローチです。
Emberは、GettersとSetterを使用して、オブジェクトのデータを使用して動作します。これにより、実際の変数に到達するために1つのレイヤーが1つあるため、計算されたプロパティの実装が簡素化されます。ただし、プレーンJavaScriptオブジェクトで計算されたプロパティを使用できれば、さらに興味深いでしょう。たとえば、
のように<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
名前は通常のプロパティとして使用されますが、実際には、firstNameとlastNameを取得または設定する関数です。
JavaScriptのビルドイン機能があり、そのアイデアを実現するのに役立ちます。次のスニペットをご覧ください:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
object.definePropertyはまさに必要なものですが、開発者に毎回それを書くことを強制したくありません。ポリフィルを提供したり、追加のロジックを実行したり、そのようなものを提供する必要がある場合があります。理想的なケースでは、Emberに似たインターフェイスを提供したいと考えています。クラス定義の一部は1つの関数のみです。このセクションでは、オブジェクトを処理し、何らかの形で名前関数を同じ名前のプロパティに変換するComputizeedというユーティリティ関数を書きます。
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
名前メソッドをセッターとして、同時にゲッターと同時に使用したいと考えています。これは、Emberの計算されたプロパティに似ています
ここで、関数オブジェクトのプロトタイプに独自のロジックを追加しましょう:<span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span><span>}; </span>wrapMap<span>.optgroup = wrapMap.option; </span>wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span>wrapMap<span>.th = wrapMap.td;</span>
上記の行を追加すると、すべての関数定義の最後に.computed()を追加できます。
その結果、名前プロパティには機能が含まれなくなりましたが、古い関数で満たされたTrueおよびFUNCプロパティに等しいプロパティを計算したオブジェクトです。本当の魔法は、コンピューターヘルパーの実装で起こります。オブジェクトのすべてのプロパティを通過し、Object.definePropertyを使用します。
<span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span><span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, '');</span>
.computed()関数を使用するユーザーオブジェクトの最終バージョンはあります。
<span>var stringToDom = function(str) { </span> <span>var wrapMap = { </span> <span>option: [1, '<select multiple="multiple">', '</select>'], </span> <span>legend: [1, '<fieldset>', '</fieldset>'], </span> <span>area: [1, '<map>', '</map>'], </span> <span>param: [1, '<object>', '</object>'], </span> <span>thead: [1, '<table>', '</table>'], </span> <span>tr: [2, '<table><tbody>', '</tbody></table>'], </span> <span>col: [2, '<table><tbody></tbody><colgroup>', '</colgroup></table>'], </span> <span>td: [3, '<table><tbody><tr>', '</tr></tbody></table>'], </span> <span>_default: [1, '<div>', '</div>'] </span> <span>}; </span> wrapMap<span>.optgroup = wrapMap.option; </span> wrapMap<span>.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; </span> wrapMap<span>.th = wrapMap.td; </span> <span>var element = document.createElement('div'); </span> <span>var match = <span>/<<span>\s*\w.*?></span>/g</span>.exec(str); </span> <span>if(match != null) { </span> <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span>/>/g</span>, ''); </span> <span>var map = wrapMap[tag] || wrapMap._default, element; </span> str <span>= map[1] + str + map[2]; </span> element<span>.innerHTML = str; </span> <span>// Descend through wrappers to the right content </span> <span>var j = map[0]+1; </span> <span>while(j--) { </span> element <span>= element.lastChild; </span> <span>} </span> <span>} else { </span> <span>// if only text is passed </span> element<span>.innerHTML = str; </span> element <span>= element.lastChild; </span> <span>} </span> <span>return element; </span><span>}</span>
フルネームを返す関数は、FirstNameとLastNameを変更するために使用されます。それは、合格した引数のチェックと最初の議論の処理の背後にあるアイデアです。それが存在する場合、私たちはそれを分割し、通常のプロパティに値を適用します。
すでに目的の使用法について言及しましたが、もう一度見てみましょう:<span>function <span>TodoCtrl</span>($scope<span>, $http</span>) { </span> $http<span>.get('users/users.json').success(function(data) { </span> $scope<span>.users = data; </span> <span>}); </span><span>}</span>
次のCodepenは、実際の作業を示しています
CodepenでKrasimir Tsonev(@krasimir)によるPen Ahpqoを参照してください。
おそらく、Facebookのフレームワークの反応について聞いたことがあるでしょう。それは、すべてがコンポーネントであるという考えを中心に構築されています。興味深いのは、コンポーネントの定義です。次の例を見てみましょう:
<span>var text = $('<div>Simple text</div>'); </span> <span>$('body').append(text);</span>
最初に考え始めるのは、これがJavaScriptであるということですが、それは無効なものです。レンダリング関数があり、おそらくエラーが発生します。ただし、このコードは、カスタムタイプ属性を備えた<script>タグに入れられることです。ブラウザはそれを処理しません。つまり、エラーから安全であることを意味します。 Reactには、有効なJavaScriptに書かれたコードを変換する独自のパーサーがあります。 Facebookの開発者は、XML Like Language <em> jsx と呼ばれていました。 JSXトランスは390Kで、約12000行のコードが含まれています。だから、それは少し複雑です。このセクションでは、シンプルなものを作成しますが、それでも非常に強力です。 ReactのスタイルでHTMLテンプレートを解析するJavaScriptクラス。 </script>
Facebookが行ったアプローチは、JavaScriptコードとHTMLマークアップを混合することです。したがって、次のテンプレートがあるとしましょうおよびそれを使用するコンポーネント:
<span>var stringToDom = function(str) { </span> <span>var temp = document.createElement('div'); </span> temp<span>.innerHTML = str; </span> <span>return temp.childNodes[0]; </span><span>} </span><span>var text = stringToDom('<div>Simple text</div>'); </span> <span>document.querySelector('body').appendChild(text);</span>
アイデアは、テンプレートのIDを指摘し、適用すべきデータを定義するということです。実装の最後の部分は、2つの要素をマージする実際のエンジンです。エンジンと呼んで、そのように起動しましょう:
<span>var tableRow = $('<tr><td>Simple text</td></tr>'); </span><span>$('body').append(tableRow); </span> <span>var tableRow = stringToDom('<tr><td>Simple text</td></tr>'); </span><span>document.querySelector('body').appendChild(tableRow);</span>
以上がJavaScriptの魔法を明らかにしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。