検索

JavaScriptの魔法を明らかにします

毎日たくさんのツールを使用しています。さまざまなライブラリとフレームワークが私たちの毎日の仕事の一部です。ボンネットの下で何が起こっているのかわからなくても、すべてのプロジェクトのホイールを再発明したくないので、それらを使用します。この記事では、最も人気のあるライブラリで起こっている魔法のプロセスのいくつかを明らかにします。また、彼らの動作を再現できるかどうかも確認します

キーテイクアウト

    jqueryのようなJavaScriptライブラリは、ネストされた要素のような複雑なケースを正しく処理することにより、文字列から要素を作成するなど、DOM操作を簡素化します。
  • AngularJSの依存関係注入システムは、明示的な合格せずに依存関係を魔法のように管理します。インジェクターパターンを使用して、実行時に依存関係を動的に提供します。
  • ember.jsは、計算されたプロパティでJavaScriptオブジェクトを強化し、プロパティが機能のように動作できるようにし、依存関係が変更されたときに自動的に更新します。
  • ReactのJSX構文により、JavaScriptにHTMLを埋め込むことができます。HTMLは、ReactのJSXトランスによって処理され、動的UIコンポーネントを作成します。
  • この記事は、依存関係の注入と計算された特性のためのカスタムソリューションを示しており、開発者がプロ​​ジェクトで同様の機能をどのように実装できるかを示しています。
  • 人気のあるJavaScriptフレームワークの基礎となるメカニズムを理解することで、開発者がより効率的で保守可能なコードを作成できるようになります。
  • 文字列からdom要素を作成
  • シングルページアプリケーションの増加により、JavaScriptで多くのことを行っています。アプリケーションのロジックの大部分がブラウザに移動されました。ページ上の要素を生成または交換することは一般的なタスクです。以下に示すものと同様のコードは非常に一般的になりました。
  • 結果は、ドキュメントの本文に追加された新しい
    要素です。この単純な操作は、1行のjQueryで行われます。 jQueryがなければ、コードはもう少し複雑ですが、それほど多くはありません:

    一時的な
    要素を作成する独自のユーティリティメソッドStringtodomを定義しました。私たちはそのinnerhtmlプロパティを変更し、最終的に私たちは実際に必要なものである最初の子供を単に返しました。同じように機能しました。ただし、次のコードではさまざまな結果が見られます。

    視覚的には、ページに違いはありません。ただし、Chromeの開発者ツールで生成されたマークアップを確認すると、興味深い結果が得られます。

    <span>var text = $('<div>Simple text</div>');
    </span>
    <span>$('body').append(text);</span>

    stringtodom関数は、実際の

    タグではなく、テキストノードのみを作成したようです。しかし、同時に、jQueryはなんとかそれをすることができました。問題は、HTML要素を含む文字列がブラウザのパーサーを介して実行されることです。そのパーサーは、正しいコンテキストに配置されていないタグを無視し、テキストノードのみを取得します。テーブルのないテーブルの列は、ブラウザには無効です。 jQueryは、正しいコンテキストを作成することで問題を正常に解決し、必要な部分のみを抽出します。ライブラリのコードを少し掘り下げると、このようなマップが表示されます:

    <span>var text = $('<div>Simple text</div>');
    </span>
    <span>$('body').append(text);</span>
    特別な処理を必要とするすべての要素には、配列が割り当てられています。アイデアは、適切なDOM要素を構築し、必要なものを取得するためにネストのレベルに依存することです。たとえば、 要素の場合、 子供を持つテーブルを作成する必要があります。したがって、2つのレベルのネストがあります

    マップがあるため、最終的にどのようなタグが必要かを確認する必要があります。次のコードでは、

    のtrを抽出します

    残りは適切なコンテキストを見つけて、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。そうでない場合は、単にテキストノードを返します。一時的な
    の使用はまだありますが、今回はブラウザが有効なDOMツリーを作成できるように適切なタグを渡しています。最終的には、時間ループを使用することで、必要なタグに到達するまで深く深く進んでいます。
    <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があります:

    CodepenでKrasimir Tsonev(@krasimir)によるPen xlcgnを参照してください。

    素晴らしいAngularJS依存関係の注入を調査して続けましょう

    AngularJS依存性注入を明らかにします

    angularjsの使用を開始すると、双方向のデータバインディングに感銘を与えます。 2番目のことは、その魔法の依存噴射です。簡単な例を次に示します:

    それは典型的なAngularJSコントローラーです。 HTTP要求を実行し、JSONファイルからデータを取得し、現在のスコープに渡します。 TODOCTRL関数を実行しません。引数を渡す機会はありません。フレームワークはそうします。それで、これらの$スコープと$ http変数はどこから来たのでしょうか?それは非常にクールな機能であり、ブラックマジックに非常に似ています。それがどのように行われているか見てみましょう。

    システムにユーザーを表示する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>
    そしてもちろん、displayUsers(body、ajaxwrapper)を実行すると、コンソールでリクエストされているページに3つの名前が表示されます。私たちの方法には、ボディとajaxwrapperの2つの依存関係があると言えます。したがって、アイデアは、議論を渡さずに関数を機能させることです。つまり、DisplayUsers()を呼び出すことで同じ結果を得る必要があります。これまでのところコードでそれを行うと、結果は次のとおりです。

    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>', '</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>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>', '</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>/\s*\w.*?></span>/g</span>.exec(str);
    
      <span>if(match != null) {
    </span>    <span>var tag = match[0].replace(<span>/</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>
    このような実装の利点は、多くの機能にDOM要素とAjaxラッパーを注入できることです。そのようなアプリケーションの構成を配布することもできます。クラスからクラスにオブジェクトを渡す必要はありません。それはただの登録と解決方法です。

    もちろん、私たちのインジェクターは完璧ではありません。たとえば、スコープ定義のサポートなど、改善の余地がまだあります。現在、ターゲット関数は新しく作成されたスコープで呼び出されますが、通常は独自のスコープを渡したいと思うでしょう。また、依存関係とともにカスタム引数を送信することもサポートする必要があります。

    削除後にコードを動作させたい場合、インジェクターはさらに複雑になります。私たちが知っているように、ミニファイヤーは関数、変数、さらにはメソッドの引数の名前を置き換えます。そして、私たちのロジックはこれらの名前に依存しているため、回避策について考える必要があります。考えられる解決策の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>', '</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メソッドは、スコープ、プロパティの名前、ゲッター、セッターを受け入れることができます。私たちがしなければならないのは、2つの方法の本体を書くことです。そして、それだけです。上記のコードを実行できるようになり、期待される結果が得られます。

    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>', '</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>var tag = match[0].replace(<span>/</g</span>, '').replace(<span >/>/g</span>, '');</span>
    元のプロパティ名を削除していることに注意してください。一部のブラウザObject.DefinePropertyでは、まだ定義されていないプロパティでのみ動作します。

    .computed()関数を使用するユーザーオブジェクトの最終バージョンはあります。

    <span>var stringToDom = function(str) {
    </span>  <span>var wrapMap = {
    </span>    <span>option: [1, '<select 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>/\s*\w.*?></span>/g</span>.exec(str);
    
      <span>if(match != null) {
    </span>    <span>var tag = match[0].replace(<span>/</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>

    '], col: [2, '', '
    '],
    td: [3, '', '
    '],
    _default: [1, '
    ', '
    ']
    }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td;さあ、解析機能を書きましょう。私たちの最初のタスクは、HTMLを式と区別することです。式とは、の間に置かれる文字列を意味します。正規表現を使用してそれらを見つけます。また、すべてのマッチを通過するためにシンプルな間ループを使用します。

    上記のコードの結果は次のとおりです

    式は1つだけで、そのコンテンツはタイトルです。私たちが取ることができる最初の直感的なアプローチは、JavaScriptの置換機能を使用し、を渡されたCOMPオブジェクトのデータに置き換えることです。ただし、これは単純なプロパティでのみ機能します。ネストされたオブジェクトがある場合、または関数を使用する場合でもどうでしょう。たとえば、
    <span>var match = <span>/<<span >\s*\w.*?></span>/g</span>.exec(str);
    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span >/>/g</span>, '');</span>
    のように

    複雑なパーサーを作成し、ほとんど新しい言語を発明する代わりに、純粋なJavaScriptを使用できます。私たちがしなければならない唯一のことは、新しい関数の構文を使用することです。
    <span>var stringToDom = function(str) {
    </span>  <span>var wrapMap = {
    </span>    <span>option: [1, '<select 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>/\s*\w.*?></span>/g</span>.exec(str);
    
      <span>if(match != null) {
    </span>    <span>var tag = match[0].replace(<span>/</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>var text = $('<div>Simple text</div>');
    </span>
    <span>$('body').append(text);</span>

    コンソールの出力は、私たちが正しい軌道に乗っていることを示しています:

    <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>

    コード配列は、関数の本体となる文字列に変換する必要があります。たとえば、

    <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>

    この結果を達成するのは非常に簡単です。コード配列のすべての要素を通過して、アイテムが文字列またはオブジェクトであるかどうかをチェックするループを作成する場合があります。ただし、これは再びケースの一部のみをカバーします。次のテンプレートを持っている場合はどうなりますか:

    <span>var wrapMap = {
    </span>  <span>option: [1, '<select 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 match = <span>/<<span >\s*\w.*?></span>/g</span>.exec(str);
    <span>var tag = match[0].replace(<span>/</g</span>, '').replace(<span >/>/g</span>, '');</span>

    コード配列が入力されたら、関数の本体の構築を開始します。テンプレートのすべての行は、配列rに保存されます。行が文字列の場合、引用符を逃れ、新しい行とタブを削除することで、少しクリアしています。プッシュメソッドを介して配列に追加されます。コードスニペットがある場合は、有効なJavaScriptオペレーターではないかどうかを確認します。はいの場合、それを配列に追加するのではなく、単に新しいラインとしてドロップするだけです。エンド出力のconsole.log:

    <span>var stringToDom = function(str) {
    </span>  <span>var wrapMap = {
    </span>    <span>option: [1, '<select 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>/\s*\w.*?></span>/g</span>.exec(str);
    
      <span>if(match != null) {
    </span>    <span>var tag = match[0].replace(<span>/</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>

    いいねコンポーネントのコンテキストで実行される適切にフォーマットされた作業JavaScriptは、目的のHTMLマークアップを生成します。

    残っている最後のものは、実質的に作成された機能の実際の実行です:

    <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>
    コンポーネントのコンテキストで実行するために、コードをステートメントでラップしました。それなしでは、タイトルと色の代わりにthis.titleとthis.colorsを使用する必要があります。

    ここに、最終結果を示すCodepenがあります:

    CodepenでKrasimir Tsonev(@krasimir)によるペンガヘイを参照してください。

    要約

    大きなフレームワークとライブラリの背後には、スマート開発者がいます。彼らは、些細なことではなく、魔法のようなトリッキーなソリューションを見つけて使用しています。この記事では、その魔法のいくつかを明らかにしました。 JavaScriptの世界では、私たちが最高から学び、彼らのコードを使用できるのは素晴らしいことです。 この記事のコードは、github

    からダウンロードできます。 JavaScriptの魔法に関するよくある質問(FAQ)

    JavaScriptの魔法の方法とは何ですか?それらはどのように機能しますか?

    ​​

    JavaScriptの魔法の方法は、クラスの動作にフックを提供する特別な方法です。それらは直接呼び出されませんが、特定のアクションが実行されると呼び出されます。たとえば、toString()メソッドは、オブジェクトをテキスト値として表現する必要がある場合に自動的に呼び出される魔法の方法です。別の例は、valueof()メソッドです。これは、オブジェクトがプリミティブ値として表される場合に呼び出されます。

    JavaScriptで魔法のメソッドを使用するにはどうすればよいですか?

    JavaScriptのマジックメソッドは、オブジェクトまたはクラスでそれらを定義することで使用できます。たとえば、オブジェクトにtoString()メソッドを定義して、オブジェクトが文字列として表現される方法をカスタマイズできます。簡単な例は次のとおりです。

    let person = {
    firstName: "john"、
    lastName: "doe"、
    toString:function(){
    return this.firstname " "this.lastname;
    }
    };
    console.log(person.tostring()); // "John doe"

    javascriptの魔法の機能の重要性は何ですか?

    javascriptの魔法機能は、特定の状況でオブジェクトの動作を制御およびカスタマイズできるため、重要です。彼らはあなたのコードをより直感的で理解しやすくすることができ、あなたのデータをカプセル化して保護する方法を提供することができます。 JavaScriptの魔法の機能の例をいくつか紹介します。 toString():このメソッドは、オブジェクトを表す文字列を返します。 valueof():このメソッドは、オブジェクトのプリミティブ値を返します。 hasownProperty():このメソッドは、オブジェクトに指定されたプロパティがあるかどうかを示すブール値を返します。魔法の方法は非常に便利であり、いくつかの制限もあります。 1つは、特にそれらがどのように機能するかに慣れていない場合、コードをより複雑でデバッグしにくくすることができます。また、正しく使用されないと予期しない動作につながる可能性があります。 「魔法の方法」。ただし、toString()やvalueof()など、同様に動作する特定の方法があります。これらの方法は、他の言語の魔法の方法によく似た特定の状況で自動的に呼び出されます。それらを使用する時期を理解し、それらを控えめに使用して複雑さを避け、常にコードを徹底的にテストして、予想どおりに動作するようにしてください。 ReactやvueなどのJavaScriptフレームワーク?

    はい、Magic Methodは、ReactやVueなどのJavaScriptフレームワークで使用できます。ただし、それらの使用方法は、フレームワークによって異なる場合があります。特定のフレームワークのドキュメントをガイダンスするためのドキュメントを参照することが常に最善です。

    javascriptで魔法の方法についてもっと知るにはどうすればよいですか?

    ​​

    JavaScriptの魔法の方法について詳しく知るために利用できるリソースがたくさんあります。公式のJavaScriptドキュメント、およびオンラインチュートリアルやコースから始めることができます。また、自分のプロジェクトでそれらを使用して実践的な体験を得ることもできます。 JavaScriptでマジックメソッドの使用に役立つツール。たとえば、Lodashは人気のJavaScriptユーティリティライブラリで、配列、オブジェクト、その他の種類のデータを使用するための役立つ方法を提供します。

以上がJavaScriptの魔法を明らかにしますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
Webサイトからアプリまで:JavaScriptの多様なアプリケーションWebサイトからアプリまで:JavaScriptの多様なアプリケーションApr 22, 2025 am 12:02 AM

JavaScriptは、Webサイト、モバイルアプリケーション、デスクトップアプリケーション、サーバー側のプログラミングで広く使用されています。 1)Webサイト開発では、JavaScriptはHTMLおよびCSSと一緒にDOMを運用して、JQueryやReactなどのフレームワークをサポートします。 2)ReactNativeおよびIonicを通じて、JavaScriptはクロスプラットフォームモバイルアプリケーションを開発するために使用されます。 3)電子フレームワークにより、JavaScriptはデスクトップアプリケーションを構築できます。 4)node.jsを使用すると、JavaScriptがサーバー側で実行され、高い並行リクエストをサポートします。

Python vs. JavaScript:ユースケースとアプリケーションと比較されますPython vs. JavaScript:ユースケースとアプリケーションと比較されますApr 21, 2025 am 12:01 AM

Pythonはデータサイエンスと自動化により適していますが、JavaScriptはフロントエンドとフルスタックの開発により適しています。 1. Pythonは、データ処理とモデリングのためにNumpyやPandasなどのライブラリを使用して、データサイエンスと機械学習でうまく機能します。 2。Pythonは、自動化とスクリプトにおいて簡潔で効率的です。 3. JavaScriptはフロントエンド開発に不可欠であり、動的なWebページと単一ページアプリケーションの構築に使用されます。 4. JavaScriptは、node.jsを通じてバックエンド開発において役割を果たし、フルスタック開発をサポートします。

JavaScript通訳者とコンパイラにおけるC/Cの役割JavaScript通訳者とコンパイラにおけるC/Cの役割Apr 20, 2025 am 12:01 AM

CとCは、主に通訳者とJITコンパイラを実装するために使用されるJavaScriptエンジンで重要な役割を果たします。 1)cは、JavaScriptソースコードを解析し、抽象的な構文ツリーを生成するために使用されます。 2)Cは、Bytecodeの生成と実行を担当します。 3)Cは、JITコンパイラを実装し、実行時にホットスポットコードを最適化およびコンパイルし、JavaScriptの実行効率を大幅に改善します。

JavaScript in Action:実際の例とプロジェクトJavaScript in Action:実際の例とプロジェクトApr 19, 2025 am 12:13 AM

現実世界でのJavaScriptのアプリケーションには、フロントエンドとバックエンドの開発が含まれます。 1)DOM操作とイベント処理を含むTODOリストアプリケーションを構築して、フロントエンドアプリケーションを表示します。 2)node.jsを介してRestfulapiを構築し、バックエンドアプリケーションをデモンストレーションします。

JavaScriptとWeb:コア機能とユースケースJavaScriptとWeb:コア機能とユースケースApr 18, 2025 am 12:19 AM

Web開発におけるJavaScriptの主な用途には、クライアントの相互作用、フォーム検証、非同期通信が含まれます。 1)DOM操作による動的なコンテンツの更新とユーザーインタラクション。 2)ユーザーエクスペリエンスを改善するためにデータを提出する前に、クライアントの検証が実行されます。 3)サーバーとのリフレッシュレス通信は、AJAXテクノロジーを通じて達成されます。

JavaScriptエンジンの理解:実装の詳細JavaScriptエンジンの理解:実装の詳細Apr 17, 2025 am 12:05 AM

JavaScriptエンジンが内部的にどのように機能するかを理解することは、開発者にとってより効率的なコードの作成とパフォーマンスのボトルネックと最適化戦略の理解に役立つためです。 1)エンジンのワークフローには、3つの段階が含まれます。解析、コンパイル、実行。 2)実行プロセス中、エンジンはインラインキャッシュや非表示クラスなどの動的最適化を実行します。 3)ベストプラクティスには、グローバル変数の避け、ループの最適化、constとletsの使用、閉鎖の過度の使用の回避が含まれます。

Python vs. JavaScript:学習曲線と使いやすさPython vs. JavaScript:学習曲線と使いやすさApr 16, 2025 am 12:12 AM

Pythonは、スムーズな学習曲線と簡潔な構文を備えた初心者により適しています。 JavaScriptは、急な学習曲線と柔軟な構文を備えたフロントエンド開発に適しています。 1。Python構文は直感的で、データサイエンスやバックエンド開発に適しています。 2。JavaScriptは柔軟で、フロントエンドおよびサーバー側のプログラミングで広く使用されています。

Python vs. JavaScript:コミュニティ、ライブラリ、リソースPython vs. JavaScript:コミュニティ、ライブラリ、リソースApr 15, 2025 am 12:16 AM

PythonとJavaScriptには、コミュニティ、ライブラリ、リソースの観点から、独自の利点と短所があります。 1)Pythonコミュニティはフレンドリーで初心者に適していますが、フロントエンドの開発リソースはJavaScriptほど豊富ではありません。 2)Pythonはデータサイエンスおよび機械学習ライブラリで強力ですが、JavaScriptはフロントエンド開発ライブラリとフレームワークで優れています。 3)どちらも豊富な学習リソースを持っていますが、Pythonは公式文書から始めるのに適していますが、JavaScriptはMDNWebDocsにより優れています。選択は、プロジェクトのニーズと個人的な関心に基づいている必要があります。

See all articles

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

Video Face Swap

Video Face Swap

完全無料の AI 顔交換ツールを使用して、あらゆるビデオの顔を簡単に交換できます。

ホットツール

ZendStudio 13.5.1 Mac

ZendStudio 13.5.1 Mac

強力な PHP 統合開発環境

mPDF

mPDF

mPDF は、UTF-8 でエンコードされた HTML から PDF ファイルを生成できる PHP ライブラリです。オリジナルの作者である Ian Back は、Web サイトから「オンザフライ」で PDF ファイルを出力し、さまざまな言語を処理するために mPDF を作成しました。 HTML2FPDF などのオリジナルのスクリプトよりも遅く、Unicode フォントを使用すると生成されるファイルが大きくなりますが、CSS スタイルなどをサポートし、多くの機能強化が施されています。 RTL (アラビア語とヘブライ語) や CJK (中国語、日本語、韓国語) を含むほぼすべての言語をサポートします。ネストされたブロックレベル要素 (P、DIV など) をサポートします。

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

PhpStorm Mac バージョン

PhpStorm Mac バージョン

最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール