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

揭示JavaScript的魔力

Lisa Kudrow
Lisa Kudrow原創
2025-02-21 09:38:10646瀏覽

揭示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="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>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
    </span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>
    使用該方法,我們將有機會使用所需的依賴項調用該功能。同時,我們沒有更改應用程序的工作流程。噴油器仍然是獨立的,並且不具有與邏輯相關的功能。

    >

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

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

    <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="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="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>/&lt;<span>\s*\w.*?&gt;</span>/g</span>.exec(str);
    </span><span>var tag = match[0].replace(<span>/&lt;/g</span>, '').replace(<span>/&gt;/g</span>, '');</span>
    結果,名稱屬性不再包含函數,而是計算出等於true and func屬性的對象填充了舊功能。真正的魔術發生在計算助手的實現中。它通過對象的所有屬性並使用對象。 DefineProperty我們已經計算出屬性:

    >

    <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>
    請注意,我們正在刪除原始屬性名稱。在某些瀏覽器對像中。 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="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>
    >我們正在獲取

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

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn