• <sub id="h4knl"><ol id="h4knl"></ol></sub>
    <sup id="h4knl"></sup>
      <sub id="h4knl"></sub>

      <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
      1. <strong id="h4knl"></strong>

      2. 抽象語法樹在JavaScript中的應用

        時間:2024-08-18 04:30:19 JavaScript 我要投稿
        • 相關推薦

        抽象語法樹在JavaScript中的應用

          抽象語法樹是什么?在 JavaScript 中該如何應用?下面YJBYS小編為大家講解!

          在計算機科學中,抽象語法樹(abstract syntax tree 或者縮寫為 AST),或者語法樹(syntax tree),是源代碼的抽象語法結構的樹狀表現形式,這里特指編程語言的源代碼。樹上的每個節點都表示源代碼中的一種結構。之所以說語法是「抽象」的,是因為這里的語法并不會表示出真實語法中出現的每個細節。1

          果然比較抽象,不如先看幾個例子:

          抽象語法樹舉例

          foo = 'hello world';

          /*

          +-------------+

          | assign(=) |

          +-------------+

          X X

          X X

          +-------+ +-----------------+

          | foo | | 'hello world' |

          +-------+ +-----------------+

          */

          if (foo === true) {

          bar = 'hello world';

          alert(bar);

          }

          /*

          +------+

          | if |

          +------+

          X X

          X X

          +--------------+ +-------------+

          | equal(===) | | if_body |

          +--------------+ +-------------+

          X X X X

          X X X X

          +-------+ +--------+ +-------------+ +------------+

          | foo | | true | | assign(=) | | alert() |

          +-------+ +--------+ +-------------+ +------------+

          X X X

          X X X

          +-------+ +-----------------+ +-------+

          | bar | | 'hello world' | | bar |

          +-------+ +-----------------+ +-------+

          */

          從上述兩個例子可以看出,抽象語法樹是將源代碼根據其語法結構,省略一些細節(比如:括號沒有生成節點),抽象成樹形表達。

          抽象語法樹在計算機科學中有很多應用,比如編譯器、IDE、壓縮優化代碼等。下面介紹一下抽象語法樹在 JavaScript 中的應用。

          JavaScript 抽象語法樹

          構造 JavaScript 抽象語法樹有多種工具,比如 v8、SpiderMonkey、UglifyJS 等,這里重點介紹 UglifyJS。

          UglifyJS

          UglifyJS 是使用最廣的 JavaScript 壓縮工具之一,而且自身也是用 JavaScript 寫的,使用它的方法很簡單(需要 nodejs 環境):

          首先全局安裝:

          [sudo ]npm install -g uglify-js

          然后就可以使用了:

          uglifyjs -m srcFileName.js -o destFileName.min.js

          關于 UglifyJS 的用法這里就不多介紹了,我們要做的是一些更有趣的事情。

          UglifyJS Tools

          UglifyJS 提供了一些工具用于分析 JavaScript 代碼,包括:

          parser,把 JavaScript 代碼解析成抽象語法樹

          code generator,通過抽象語法樹生成代碼

          mangler,混淆 JavaScript 代碼

          scope analyzer,分析變量定義的工具

          tree walker,遍歷樹節點

          tree transformer,改變樹節點

          生成抽象語法樹

          使用 UglifyJS 生成抽象語法樹很簡單:

          首先安裝 UglifyJS 為 npm 包:

          npm install uglify-js --save-dev

          然后使用 parse 方法即可:

          var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

          這樣生成的 ast 即為那一段代碼的抽象語法樹。那么我們怎么使用呢?

          使用 mangler 壓縮代碼

          使用 mangler 可以通過將局部變量都縮短成一個字符來壓縮代碼。

          var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

          ast.figure_out_scope();

          ast.mangle_names();

          console.log(ast.print_to_string());// function sum(a,b){return a+b}

          使用 walker 遍歷抽象語法樹

          使用 walker 可以遍歷抽象語法樹,這種遍歷是深度遍歷。

          var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

          ast.figure_out_scope();

          ast.walk(new UglifyJS.TreeWalker(function(node) {

          console.log(node.print_to_string());

          }));/*

          function sum(foo,bar){return foo+bar}

          function sum(foo,bar){return foo+bar}

          sum

          foo

          bar

          return foo+bar

          foo+bar

          foo

          bar

          */

          UglifyJS 已經提供了直接壓縮代碼的腳本,walker 看上去貌似也沒啥用,那么這些工具有什么使用場景呢?

          抽象語法樹的應用

          利用抽象語法樹重構 JavaScript 代碼

          假如我們有重構 JavaScript 的需求,它們就派上用場啦。

          下面考慮這樣一個需求:

          我們知道,parseInt 用于將字符串變成整數,但是它有第二個參數,表示以幾進制識別字符串,若沒有傳第二個參數,則會自行判斷,比如:

          parseInt('10.23'); // 10 轉換成正整數parseInt('10abc'); // 10 忽略其他字符parseInt('10', 10); // 10 轉換成十進制parseInt('10', 2); // 2 轉換成二進制parseInt('0123'); // 83 or 123 不同瀏覽器不一樣,低版本瀏覽器會轉換成八進制parseInt('0x11'); // 17 轉換成十六進制

          因為有一些情況是和我們預期不同的,所以建議任何時候都加上第二個參數。

          下面希望有一個腳本,查看所有 parseInt 有沒有第二個參數,沒有的話加上第二個參數 10,表示以十進制識別字符串。

          使用 UglifyJS 可以實現此功能:

          #! /usr/bin/env nodevar U2 = require("uglify-js");function replace_parseint(code) {

          var ast = U2.parse(code); // accumulate `parseInt()` nodes in this array

          var parseint_nodes = [];

          ast.walk(new U2.TreeWalker(function(node){

          if (node instanceof U2.AST_Call

          && node.expression.print_to_string() === 'parseInt'

          && node.args.length === 1) {

          parseint_nodes.push(node);

          }

          })); // now go through the nodes backwards and replace code

          for (var i = parseint_nodes.length; --i >= 0;) { var node = parseint_nodes[i]; var start_pos = node.start.pos; var end_pos = node.end.endpos;

          node.args.push(new U2.AST_Number({

          value: 10

          })); var replacement = node.print_to_string({ beautify: true });

          code = splice_string(code, start_pos, end_pos, replacement);

          } return code;

          }function splice_string(str, begin, end, replacement) {

          return str.substr(0, begin) + replacement + str.substr(end);

          }// test itfunction test() {

          if (foo) { parseInt('12342');

          } parseInt('0012', 3);

          }

          console.log(replace_parseint(test.toString()));/*

          function test() {

          if (foo) {

          parseInt("12342", 10);

          }

          parseInt('0012', 3);

          }

          */

          在這里,使用了 walker 找到 parseInt 調用的地方,然后檢查是否有第二個參數,沒有的話,記錄下來,之后根據每個記錄,用新的包含第二個參數的內容替換掉原內容,完成代碼的重構。

          也許有人會問,這種簡單的情況,用正則匹配也可以方便的替換,干嘛要用抽象語法樹呢?

          答案就是,抽象語法樹是通過分析語法實現的,有一些正則無法(或者很難)做到的優勢,比如,parseInt() 整個是一個字符串,或者在注釋中,此種情況會被正則誤判:

          var foo = 'parseInt("12345")';// parseInt("12345");

          抽象語法樹在美團中的應用

          在美團前端團隊,我們使用 YUI 作為前端底層框架,之前面臨的一個實際問題是,模塊之間的依賴關系容易出現疏漏。比如:

          YUI.add('mod1', function(Y) {

          Y.one('#button1').simulate('click');

          Y.Array.each(array, fn);

          Y.mod1 = function() {/**/};

          }, '', {

          requires: [ 'node', 'array-extras'

          ]

          });

          YUI.add('mod2', function(Y) {

          Y.mod1(); // Y.io(uri, config);}, '', {

          requires: [ 'mod1', 'io'

          ]

          });

          以上代碼定義了兩個模塊,其中 mod1 模擬點擊了一下 id 為 button1 的元素,執行了 Y.Array.each,然后定義了方法 Y.mod1,最后聲明了依賴 node 和 array-extras;mod2 執行了 mod1 中定義的方法,而 Y.io 被注釋了,最后聲明了依賴 mod1 和 io。

          此處 mod1 出現了兩個常見錯誤,一個是 simulate 是 Y.Node.prototype 上的方法,容易忘掉聲明依賴 node-event-simulate3,另一個是 Y.Array 上只有部分方法需要依賴 array-extras,故此處多聲明了依賴 array-extras4;mod2 中添加注釋后,容易忘記刪除原來寫的依賴 io。

          故正確的依賴關系應該如下:

          YUI.add('mod1', function(Y) {

          Y.one('#button1').simulate('click');

          Y.Array.each(array, fn);

          Y.mod1 = function() {/**/};

          }, '', {

          requires: [ 'node', 'node-event-simulate'

          ]

          });

          YUI.add('mod2', function(Y) {

          Y.mod1(); // Y.io(uri, config);}, '', {

          requires: [ 'mod1'

          ]

          });

          為了使模塊依賴關系的檢測自動化,我們創建了模塊依賴關系檢測工具,它利用抽象語法樹,分析出定義了哪些接口,使用了哪些接口,然后查找這些接口應該依賴哪些模塊,進而找到模塊依賴關系的錯誤,大致的過程如下:

          找到代碼中模塊定義(YUI.add)的部分

          分析每個模塊內函數定義,變量定義,賦值語句等,找出符合要求(以 Y 開頭)的輸出接口(如 mod1 中的 Y.mod1)

          生成「接口 - 模塊」對應關系

          分析每個模塊內函數調用,變量使用等,找出符合要求的輸入接口(如 mod2 中的 Y.one,Y.Array.each,Y.mod1)

          通過「接口 - 模塊」對應關系,找到此模塊應該依賴哪些其他模塊

          分析 requires 中是否有錯誤

          使用此工具,保證每次提交代碼時,依賴關系都是正確無誤的,它幫助我們實現了模塊依賴關系檢測的自動化。

          總結

          抽象語法樹在計算機領域中應用廣泛,以上僅討論了抽象語法樹在 JavaScript 中的一些應用,期待更多的用法等著大家去嘗試和探索。

        《&.doc》
        将本文的Word文档下载到电脑,方便收藏和打印
        推荐度:
        点击下载文档

        【抽象語法樹在JavaScript中的應用】相關文章:

        在Java中執行JavaScript代碼04-01

        Javascript中typeof 用法歸納04-01

        JavaScript中的with關鍵字03-25

        整理Javascript基礎語法學習筆記欣賞04-01

        perl- javascript中class的機制03-25

        JavaScript中的三種對象04-01

        javascript閉包的定義及應用實例分析04-01

        JavaScript中push(),join() 函數實例詳解03-31

        詳解JavaScript中的splice()使用方法04-01

        在线咨询
        国产高潮无套免费视频_久久九九兔免费精品6_99精品热6080YY久久_国产91久久久久久无码
      3. <sub id="h4knl"><ol id="h4knl"></ol></sub>
        <sup id="h4knl"></sup>
          <sub id="h4knl"></sub>

          <sub id="h4knl"><ol id="h4knl"><em id="h4knl"></em></ol></sub><s id="h4knl"></s>
          1. <strong id="h4knl"></strong>

          2. 亚洲专区首页在线观看 | 亚洲国产v高清在线观看 | 日本免费线上A∨ | 日韩精品动漫在线观看一区 | 熟女中文字幕乱码 | 漂亮人妇中出中文字幕在线 |

            抽象語法樹在JavaScript中的應用

              抽象語法樹是什么?在 JavaScript 中該如何應用?下面YJBYS小編為大家講解!

              在計算機科學中,抽象語法樹(abstract syntax tree 或者縮寫為 AST),或者語法樹(syntax tree),是源代碼的抽象語法結構的樹狀表現形式,這里特指編程語言的源代碼。樹上的每個節點都表示源代碼中的一種結構。之所以說語法是「抽象」的,是因為這里的語法并不會表示出真實語法中出現的每個細節。1

              果然比較抽象,不如先看幾個例子:

              抽象語法樹舉例

              foo = 'hello world';

              /*

              +-------------+

              | assign(=) |

              +-------------+

              X X

              X X

              +-------+ +-----------------+

              | foo | | 'hello world' |

              +-------+ +-----------------+

              */

              if (foo === true) {

              bar = 'hello world';

              alert(bar);

              }

              /*

              +------+

              | if |

              +------+

              X X

              X X

              +--------------+ +-------------+

              | equal(===) | | if_body |

              +--------------+ +-------------+

              X X X X

              X X X X

              +-------+ +--------+ +-------------+ +------------+

              | foo | | true | | assign(=) | | alert() |

              +-------+ +--------+ +-------------+ +------------+

              X X X

              X X X

              +-------+ +-----------------+ +-------+

              | bar | | 'hello world' | | bar |

              +-------+ +-----------------+ +-------+

              */

              從上述兩個例子可以看出,抽象語法樹是將源代碼根據其語法結構,省略一些細節(比如:括號沒有生成節點),抽象成樹形表達。

              抽象語法樹在計算機科學中有很多應用,比如編譯器、IDE、壓縮優化代碼等。下面介紹一下抽象語法樹在 JavaScript 中的應用。

              JavaScript 抽象語法樹

              構造 JavaScript 抽象語法樹有多種工具,比如 v8、SpiderMonkey、UglifyJS 等,這里重點介紹 UglifyJS。

              UglifyJS

              UglifyJS 是使用最廣的 JavaScript 壓縮工具之一,而且自身也是用 JavaScript 寫的,使用它的方法很簡單(需要 nodejs 環境):

              首先全局安裝:

              [sudo ]npm install -g uglify-js

              然后就可以使用了:

              uglifyjs -m srcFileName.js -o destFileName.min.js

              關于 UglifyJS 的用法這里就不多介紹了,我們要做的是一些更有趣的事情。

              UglifyJS Tools

              UglifyJS 提供了一些工具用于分析 JavaScript 代碼,包括:

              parser,把 JavaScript 代碼解析成抽象語法樹

              code generator,通過抽象語法樹生成代碼

              mangler,混淆 JavaScript 代碼

              scope analyzer,分析變量定義的工具

              tree walker,遍歷樹節點

              tree transformer,改變樹節點

              生成抽象語法樹

              使用 UglifyJS 生成抽象語法樹很簡單:

              首先安裝 UglifyJS 為 npm 包:

              npm install uglify-js --save-dev

              然后使用 parse 方法即可:

              var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

              這樣生成的 ast 即為那一段代碼的抽象語法樹。那么我們怎么使用呢?

              使用 mangler 壓縮代碼

              使用 mangler 可以通過將局部變量都縮短成一個字符來壓縮代碼。

              var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

              ast.figure_out_scope();

              ast.mangle_names();

              console.log(ast.print_to_string());// function sum(a,b){return a+b}

              使用 walker 遍歷抽象語法樹

              使用 walker 可以遍歷抽象語法樹,這種遍歷是深度遍歷。

              var UglifyJS = require('uglify-js');var ast = UglifyJS.parse('function sum(foo, bar){ return foo + bar; }');

              ast.figure_out_scope();

              ast.walk(new UglifyJS.TreeWalker(function(node) {

              console.log(node.print_to_string());

              }));/*

              function sum(foo,bar){return foo+bar}

              function sum(foo,bar){return foo+bar}

              sum

              foo

              bar

              return foo+bar

              foo+bar

              foo

              bar

              */

              UglifyJS 已經提供了直接壓縮代碼的腳本,walker 看上去貌似也沒啥用,那么這些工具有什么使用場景呢?

              抽象語法樹的應用

              利用抽象語法樹重構 JavaScript 代碼

              假如我們有重構 JavaScript 的需求,它們就派上用場啦。

              下面考慮這樣一個需求:

              我們知道,parseInt 用于將字符串變成整數,但是它有第二個參數,表示以幾進制識別字符串,若沒有傳第二個參數,則會自行判斷,比如:

              parseInt('10.23'); // 10 轉換成正整數parseInt('10abc'); // 10 忽略其他字符parseInt('10', 10); // 10 轉換成十進制parseInt('10', 2); // 2 轉換成二進制parseInt('0123'); // 83 or 123 不同瀏覽器不一樣,低版本瀏覽器會轉換成八進制parseInt('0x11'); // 17 轉換成十六進制

              因為有一些情況是和我們預期不同的,所以建議任何時候都加上第二個參數。

              下面希望有一個腳本,查看所有 parseInt 有沒有第二個參數,沒有的話加上第二個參數 10,表示以十進制識別字符串。

              使用 UglifyJS 可以實現此功能:

              #! /usr/bin/env nodevar U2 = require("uglify-js");function replace_parseint(code) {

              var ast = U2.parse(code); // accumulate `parseInt()` nodes in this array

              var parseint_nodes = [];

              ast.walk(new U2.TreeWalker(function(node){

              if (node instanceof U2.AST_Call

              && node.expression.print_to_string() === 'parseInt'

              && node.args.length === 1) {

              parseint_nodes.push(node);

              }

              })); // now go through the nodes backwards and replace code

              for (var i = parseint_nodes.length; --i >= 0;) { var node = parseint_nodes[i]; var start_pos = node.start.pos; var end_pos = node.end.endpos;

              node.args.push(new U2.AST_Number({

              value: 10

              })); var replacement = node.print_to_string({ beautify: true });

              code = splice_string(code, start_pos, end_pos, replacement);

              } return code;

              }function splice_string(str, begin, end, replacement) {

              return str.substr(0, begin) + replacement + str.substr(end);

              }// test itfunction test() {

              if (foo) { parseInt('12342');

              } parseInt('0012', 3);

              }

              console.log(replace_parseint(test.toString()));/*

              function test() {

              if (foo) {

              parseInt("12342", 10);

              }

              parseInt('0012', 3);

              }

              */

              在這里,使用了 walker 找到 parseInt 調用的地方,然后檢查是否有第二個參數,沒有的話,記錄下來,之后根據每個記錄,用新的包含第二個參數的內容替換掉原內容,完成代碼的重構。

              也許有人會問,這種簡單的情況,用正則匹配也可以方便的替換,干嘛要用抽象語法樹呢?

              答案就是,抽象語法樹是通過分析語法實現的,有一些正則無法(或者很難)做到的優勢,比如,parseInt() 整個是一個字符串,或者在注釋中,此種情況會被正則誤判:

              var foo = 'parseInt("12345")';// parseInt("12345");

              抽象語法樹在美團中的應用

              在美團前端團隊,我們使用 YUI 作為前端底層框架,之前面臨的一個實際問題是,模塊之間的依賴關系容易出現疏漏。比如:

              YUI.add('mod1', function(Y) {

              Y.one('#button1').simulate('click');

              Y.Array.each(array, fn);

              Y.mod1 = function() {/**/};

              }, '', {

              requires: [ 'node', 'array-extras'

              ]

              });

              YUI.add('mod2', function(Y) {

              Y.mod1(); // Y.io(uri, config);}, '', {

              requires: [ 'mod1', 'io'

              ]

              });

              以上代碼定義了兩個模塊,其中 mod1 模擬點擊了一下 id 為 button1 的元素,執行了 Y.Array.each,然后定義了方法 Y.mod1,最后聲明了依賴 node 和 array-extras;mod2 執行了 mod1 中定義的方法,而 Y.io 被注釋了,最后聲明了依賴 mod1 和 io。

              此處 mod1 出現了兩個常見錯誤,一個是 simulate 是 Y.Node.prototype 上的方法,容易忘掉聲明依賴 node-event-simulate3,另一個是 Y.Array 上只有部分方法需要依賴 array-extras,故此處多聲明了依賴 array-extras4;mod2 中添加注釋后,容易忘記刪除原來寫的依賴 io。

              故正確的依賴關系應該如下:

              YUI.add('mod1', function(Y) {

              Y.one('#button1').simulate('click');

              Y.Array.each(array, fn);

              Y.mod1 = function() {/**/};

              }, '', {

              requires: [ 'node', 'node-event-simulate'

              ]

              });

              YUI.add('mod2', function(Y) {

              Y.mod1(); // Y.io(uri, config);}, '', {

              requires: [ 'mod1'

              ]

              });

              為了使模塊依賴關系的檢測自動化,我們創建了模塊依賴關系檢測工具,它利用抽象語法樹,分析出定義了哪些接口,使用了哪些接口,然后查找這些接口應該依賴哪些模塊,進而找到模塊依賴關系的錯誤,大致的過程如下:

              找到代碼中模塊定義(YUI.add)的部分

              分析每個模塊內函數定義,變量定義,賦值語句等,找出符合要求(以 Y 開頭)的輸出接口(如 mod1 中的 Y.mod1)

              生成「接口 - 模塊」對應關系

              分析每個模塊內函數調用,變量使用等,找出符合要求的輸入接口(如 mod2 中的 Y.one,Y.Array.each,Y.mod1)

              通過「接口 - 模塊」對應關系,找到此模塊應該依賴哪些其他模塊

              分析 requires 中是否有錯誤

              使用此工具,保證每次提交代碼時,依賴關系都是正確無誤的,它幫助我們實現了模塊依賴關系檢測的自動化。

              總結

              抽象語法樹在計算機領域中應用廣泛,以上僅討論了抽象語法樹在 JavaScript 中的一些應用,期待更多的用法等著大家去嘗試和探索。