搜尋
首頁web前端js教程揭示JavaScript的魔力

揭示JavaScript的魔力

Feb 21, 2025 am 09:38 AM

揭示JavaScript的魔力

>我們每天使用大量工具。不同的圖書館和框架是我們日常工作的一部分。我們之所以使用它們,是因為我們不想為每個項目重新發明輪子,即使我們不了解引擎蓋下的情況。在本文中,我們將揭示最受歡迎的圖書館中發生的一些神奇過程。我們還將查看是否可以復制他們的行為。

>

鑰匙要點

  • > jQuery(例如jQuery)簡化dom操縱(例如,從字符串創建元素),正確處理複雜的情況(如嵌套元素)(如嵌套元素)。 ember.js使用計算屬性增強JavaScript對象,允許屬性像函數一樣行為,在依賴性更改時自動更新。 React的JSX語法允許將HTML嵌入JavaScript中,然後由React的JSX Transformer處理以創建動態UI組件。
  • >本文展示了用於依賴注入和計算屬性的自定義解決方案,展示了開發人員如何在其項目中實施相似的功能。
  • 了解流行的JavaScript框架的基本力學可以使開發人員能夠編寫更有效和可維護的代碼。
  • >從字符串創建DOM元素
  • 隨著單頁應用程序的興起,我們正在使用JavaScript做很多事情。應用程序邏輯的很大一部分已移至瀏覽器。在頁面上生成或替換元素是一項常見的任務。與下面顯示的相似的代碼已經變得非常普遍。
  • 結果是在文檔正文中添加了一個新的
    元素。這個簡單的操作僅使用一行jQuery完成。沒有jQuery,代碼有些複雜,但沒有太多:
  • >
  • 我們定義了創建臨時
    元素的自己的實用程序方法字符串。我們更改了其InnerHTML屬性,最後我們簡單地退回了第一個孩子,實際上我們需要的是我們所需要的。它以同樣的方式工作。但是,我們將通過以下代碼觀察不同的結果:

    >

    在頁面上,在頁面上沒有差異。但是,如果我們使用Chrome的開發人員工具檢查生成的標記,我們將獲得一個有趣的結果:>

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

    >看起來我們的字符串todom函數僅創建了一個文本節點,而不是實際的

    標籤。但與此同時,jQuery以某種方式設法這樣做。問題在於,包含HTML元素的字符串通過瀏覽器中的解析器運行。解析器忽略了未放置在正確上下文中的標籤,而我們只會得到一個文本節點。沒有表格的表行對於瀏覽器無效。

    > jQuery通過創建正確的上下文並僅提取所需部分來成功解決問題。如果我們挖掘了庫的代碼,我們將看到這樣的地圖:>

    <span>var text = $('<div>Simple text</div>');
    </span>
    <span>$('body').append(text);</span>
    需要特殊處理的每個元素都分配了一個陣列。這個想法是構造正確的DOM元素,並依賴嵌套的級別來獲取我們需要的東西。例如,對於 元素,我們需要用 child創建一個表。因此,我們有兩個層次的嵌套。

    有一個地圖,我們必須找出最終想要的標籤。以下代碼從 簡單的文本

    提取TR

    <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元素。這是函數stringTodom的最終變體:

    <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>
    請注意,我們正在檢查字符串中是否有標籤 - 匹配! = null。如果不是,我們只是返回文本節點。仍然有一個臨時
    的用法,但是這次我們傳遞了正確的標籤,因此瀏覽器可以創建有效的DOM樹。最後,通過使用一段時間循環,我們將越來越深,直到達到想要的標籤為止。

    這是一個codepen,顯示了我們的實現:

    參見codepen上的krasimir tsonev(@krasimir)的筆xlcgn。

    讓我們繼續探索奇妙的AngularJS依賴注入。

    揭示agnularjs依賴注射

    當我們開始使用AngularJs時,它的雙向數據綁定給人留下深刻的印象。我們注意到的第二件事是它的神奇依賴注入。這是一個簡單的示例:

    >這是一個典型的AngularJS控制器。它執行HTTP請求,從JSON文件中獲取數據,然後將其傳遞給當前範圍。我們沒有執行todoctrl函數 - 我們沒有機會通過任何參數。框架確實如此。那麼,這些$範圍和$ http變量來自哪裡?這是一個超級酷的功能,非常類似於黑魔法。讓我們看看它是如何完成的。

    >我們有一個JavaScript函數,可以在系統中顯示用戶。相同的功能需要訪問DOM元素才能放置生成的HTML和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>

    當然,如果我們運行顯示器(正文,AjaxWrapper),我們將在頁面上看到三個名稱,以及在我們的控制台中請求的 /api /用戶。我們可以說我們的方法具有兩個依賴性 - 身體和AjaxWrapper。因此,現在的想法是使該函數在不傳遞參數的情況下工作,即,我們必須通過調用DisplayUser()來獲得相同的結果。如果到目前為止,我們使用代碼執行此操作,則結果將是:

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

    >正常,因為未定義Ajax參數。

    >提供依賴性注入機制的大多數框架具有一個模塊,通常命名為

    >噴油器。要使用依賴關係,我們需要在此處註冊。後來,在某個時候,我們的資源由同一模塊提供給應用程序的邏輯。 >

    讓我們創建我們的噴油器:

    <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>
    使用該方法,我們將有機會使用所需的依賴項調用該功能。同時,我們沒有更改應用程序的工作流程。噴油器仍然是獨立的,並且不具有與邏輯相關的功能。

    >

    當然,將顯示器的功能傳遞到Resolve方法無濟於事。

    >我們仍然遇到相同的錯誤。下一步是找出傳遞的目標需求。它的依賴性是什麼?這是我們可以從Angularjs中採用的棘手部分。我再次對框架的代碼進行了一些挖掘,並找到了以下內容:
    <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數組的第二個元素,我們將找到所需依賴項的名稱。這正是我們需要的,因為擁有名稱我們將能夠從噴油器的存儲中傳遞資源。這是有效的版本並成功涵蓋了我們的目標:

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

    請注意,我們正在使用.split(/,?/g)將字符串Domel,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包裝器。我們甚至可以這樣分發應用程序的配置。無需將對像從類傳遞到類。這只是寄存器和解決方法。

    > 當然,我們的噴油器並不完美。仍然有一些改進的空間,例如支持範圍定義。目前,目標功能通過新創建的範圍調用,但通常我們將要通過自己的範圍。我們應該支持還發送自定義參數以及依賴關係。

    > 如果我們想在縮小後保持代碼工作,則噴油器會變得更加複雜。眾所周知,縮影替換了函數,變量甚至方法的參數的名稱。而且,由於我們的邏輯依賴於這些名稱,因此我們需要考慮解決方法。一種可能的解決方案再次來自AngularJS:

    >

    而不是僅顯示顯示器的顯示器,我們正在傳遞實際依賴的名稱。
    <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是當今最受歡迎的框架之一。它具有許多有用的功能。有一個特別有趣的 - 計算屬性。總而言之,計算的屬性是充當屬性的函數。讓我們看看一個簡單的示例從灰燼的文檔中獲取:

    >有一個具有名稱和姓氏屬性的類。計算的屬性fullname返回包含人的全名的串聯字符串。奇怪的是,我們使用.property方法來針對應用於fullname的函數的部分。我個人在其他任何地方都沒有看到。而且,快速查看框架的代碼揭示了魔術:

    庫通過添加新屬性來調整全局函數對象的原型。這是在類的定義期間運行一些邏輯的好方法。
    <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與對象的數據一起操作。這簡化了計算屬性的實現,因為我們之前還有一層可以達到實際變量。但是,如果我們能夠使用普通的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方法可以接受範圍,屬性的名稱,getter和setter。我們要做的就是寫這兩種方法的主體。就是這樣。我們將能夠運行上面的代碼,我們將獲得預期的結果:

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

    object.defineproperty正是我們所需要的,但是我們不想迫使開發人員每次編寫它。我們可能需要提供多填充,運行其他邏輯或類似的東西。在理想情況下,我們希望提供與Ember類似的界面。只有一個函數是類定義的一部分。在本節中,我們將編寫一個稱為Computize的實用程序函數,該函數將處理我們的對象,並以某種方式將名稱函數轉換為具有相同名稱的屬性。

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

    >我們想將名稱方法用作設置器,同時與Getter一起使用。這類似於Ember的計算屬性。

    > 現在

    >一旦添加上述行,我們將能夠將.compented()添加到每個函數定義的末尾:>
    <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>
    結果,名稱屬性不再包含函數,而是計算出等於true and func屬性的對象填充了舊功能。真正的魔術發生在計算助手的實現中。它通過對象的所有屬性並使用對象。 DefineProperty我們已經計算出屬性:

    >

    <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>
    請注意,我們正在刪除原始屬性名稱。在某些瀏覽器對像中。 defineProperty僅在尚未定義的屬性上起作用。

    >

    這是使用.competed()函數的用戶對象的最終版本。
    <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>

    以下codepen在實踐中顯示了我們的工作:

    參見codepen上的krasimir tsonev(@krasimir)的筆Ahpqo。

    瘋狂的反應模板

    >您可能已經聽說過Facebook的框架反應。它圍繞著一切都是組成部分的想法。有趣的是組件的定義。讓我們來看看以下示例:

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

    >我們開始考慮的第一件事是這是JavaScript,但這是無效的。有一個渲染功能,它可能會丟失錯誤。但是,訣竅是將此代碼放在帶有自定義類型屬性的<script>標籤中。瀏覽器沒有處理它,這意味著我們免受錯誤的安全。 React有自己的解析器,將我們寫的代碼轉換為有效的JavaScript。 Facebook的開發人員稱為XML Like Language <ancland> jsx<em>。他們的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>
    和使用它的組件:

    >

    <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>
    的想法是,我們指出了模板的ID並定義了應應用的數據。我們實施的最後一部分是將兩個要素合併的實際引擎。讓我們稱其為引擎,然後以這樣的方式啟動:

    <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>
    >我們正在獲取
    '], col: [2, '', '
    '],
    td: [3, '', '
    '],
    _default: [1, '
    ', '
    ']
    }; wrapMap.optgroup = wrapMap.option; wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; wrapMap.th = wrapMap.td; var element = document.createElement('div'); var match = /\s*\w.*?>/g.exec(str); if(match != null) { var tag = match[0].replace(/, '').replace(/>/g, ''); var map = wrapMap[tag] || wrapMap._default, element; str = map[1] + str + map[2]; element.innerHTML = str; // Descend through wrappers to the right content var j = map[0]+1; while(j--) { element = element.lastChild; } } else { // if only text is passed element.innerHTML = str; element = element.lastChild; } return element; }

    >而不是創建複雜的解析器,幾乎發明了我們可能使用純JavaScript的新語言。我們要做的唯一一件事是使用新函數語法。

    >
    <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 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>
    >我們不能僅僅使表達式加入,並期望列出顏色。因此,而不是將字符串附加到字符串中,而是將它們收集在數組中。這是Parse函數的更新版本:

    >

    <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操作員。如果是,那麼我們不是將其添加到數組中,而只是將其刪除為新行。末端輸出的控制台。

    好,不是嗎?正確格式化的工作JavaScript,在我們組件的上下文中執行將產生所需的HTML標記。
    <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>
    剩下的最後一件事是我們虛擬創建的函數的實際運行:>

    >我們將代碼包裹在語句中,以便在組件的上下文中運行它。毫無疑問,我們需要使用this.title和this.colors而不是標題和顏色。

    >

    這是一個codepen,演示了最終結果:
    <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上的krasimir tsonev(@krasimir)的筆

    摘要

    大型框架和圖書館後面的

    是明智的開發人員。他們發現並使用了棘手的解決方案,這些解決方案並非微不足道,甚至是神奇的。在本文中,我們揭示了一些魔術。在JavaScript世界中,我們能夠從最好的代碼中學習並使用其代碼。

    本文中的代碼可從github

    下載

    經常詢問有關JavaScript

    魔法的問題(常見問題解答)

    > JavaScript中的魔術方法是什麼?它們如何工作?它們不是直接調用的,而是在執行某些動作時被調用。例如,ToString()方法是一種魔術方法,當需要將對象表示為文本值時,它會自動調用。另一個示例是valueof()方法,當對像被表示為原始值時,該方法稱為。

    >如何在JavaScript中使用魔術方法?例如,您可以在對像中定義toString()方法,以自定義對象將如何表示為字符串。這是一個簡單的示例:

    讓Person = {lastname:“ doe”, tostring:function() “ this.lastName;
    }
    };
    console.log(person.toString()); //“ John Doe”

    > JavaScript中魔術功能的意義是什麼?它們可以使您的代碼更加直觀,更易於理解,並提供一種封裝和保護您數據的方法。
    >
    您可以在JavaScript中提供一些魔術功能的示例?以下是JavaScript中魔術函數的一些示例:

    1。 ToString():此方法返回代表對象的字符串。

    > 1。 valueof():此方法返回對象的原始值。


    1。 HasownProperty():此方法返回一個布爾值,指示對像是否具有指定的屬性。


      > >> >是否有任何限製或缺點,用於在Javascript中使用魔法方法?魔術方法可能非常有用,它們也有一些局限性。首先,它們可以使您的代碼更加複雜和更難進行調試,尤其是如果您不熟悉它們的工作方式。如果不正確使用,它們也可以導致出乎意料的行為。
        與其他編程語言相比,JavaScript如何處理魔法方法?
        與其他一些編程語言不同,JavaScript沒有正式的概念“魔法方法”。但是,它的確具有類似行為的某些方法,例如tostring()和valueof( )。這些方法會在某些情況下自動調用,就像其他語言中的魔術方法一樣。
          在JavaScript中使用魔法方法的一些最佳實踐是什麼?包括理解何時以及為什麼使用它們,很少使用它們以避免複雜性,並始終徹底測試代碼以確保其行為的行為。可以與諸如react或vue?

          之類的JavaScript框架一起使用,是的,可以將魔術方法與JavaScript框架(如React或Vue)一起使用。但是,使用它們的方式可能會因框架而異。始終最好參考特定框架的文檔以進行指導。

          >

          >如何在JavaScript中了解有關魔法方法的更多信息?您可以從官方的JavaScript文檔以及在線教程和課程開始。您還可以在自己的項目中練習使用它們來獲得動手體驗。

          >是否有任何工具或庫可以幫助使用JavaScript中的魔法方法?可以在JavaScript中使用魔法方法的工具。例如,Lodash是一個流行的JavaScript實用程序庫,它為使用數組,對象和其他類型的數據提供了有用的方法。

        以上是揭示JavaScript的魔力的詳細內容。更多資訊請關注PHP中文網其他相關文章!

        陳述
        本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
        JavaScript評論:使用//和 / * * / * / * /JavaScript評論:使用//和 / * * / * / * /May 13, 2025 pm 03:49 PM

        JavaScriptusestwotypesofcomments:single-line(//)andmulti-line(//).1)Use//forquicknotesorsingle-lineexplanations.2)Use//forlongerexplanationsorcommentingoutblocksofcode.Commentsshouldexplainthe'why',notthe'what',andbeplacedabovetherelevantcodeforclari

        Python vs. JavaScript:開發人員的比較分析Python vs. JavaScript:開發人員的比較分析May 09, 2025 am 12:22 AM

        Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

        Python vs. JavaScript:選擇合適的工具Python vs. JavaScript:選擇合適的工具May 08, 2025 am 12:10 AM

        選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

        Python和JavaScript:了解每個的優勢Python和JavaScript:了解每個的優勢May 06, 2025 am 12:15 AM

        Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

        JavaScript的核心:它是在C還是C上構建的?JavaScript的核心:它是在C還是C上構建的?May 05, 2025 am 12:07 AM

        javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

        JavaScript應用程序:從前端到後端JavaScript應用程序:從前端到後端May 04, 2025 am 12:12 AM

        JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

        Python vs. JavaScript:您應該學到哪種語言?Python vs. JavaScript:您應該學到哪種語言?May 03, 2025 am 12:10 AM

        選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

        JavaScript框架:為現代網絡開發提供動力JavaScript框架:為現代網絡開發提供動力May 02, 2025 am 12:04 AM

        JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

        See all articles

        熱AI工具

        Undresser.AI Undress

        Undresser.AI Undress

        人工智慧驅動的應用程序,用於創建逼真的裸體照片

        AI Clothes Remover

        AI Clothes Remover

        用於從照片中去除衣服的線上人工智慧工具。

        Undress AI Tool

        Undress AI Tool

        免費脫衣圖片

        Clothoff.io

        Clothoff.io

        AI脫衣器

        Video Face Swap

        Video Face Swap

        使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

        熱門文章

        熱工具

        MantisBT

        MantisBT

        Mantis是一個易於部署的基於Web的缺陷追蹤工具,用於幫助產品缺陷追蹤。它需要PHP、MySQL和一個Web伺服器。請查看我們的演示和託管服務。

        EditPlus 中文破解版

        EditPlus 中文破解版

        體積小,語法高亮,不支援程式碼提示功能

        VSCode Windows 64位元 下載

        VSCode Windows 64位元 下載

        微軟推出的免費、功能強大的一款IDE編輯器

        ZendStudio 13.5.1 Mac

        ZendStudio 13.5.1 Mac

        強大的PHP整合開發環境

        PhpStorm Mac 版本

        PhpStorm Mac 版本

        最新(2018.2.1 )專業的PHP整合開發工具