亚洲最大看欧美片,亚洲图揄拍自拍另类图片,欧美精品v国产精品v呦,日本在线精品视频免费

  • 站長(zhǎng)資訊網(wǎng)
    最全最豐富的資訊網(wǎng)站

    深入了解Node.js中的VM模塊

    VM模塊是NodeJS里面的核心模塊,支撐了require方法和NodeJS的運(yùn)行機(jī)制,我們有些時(shí)候可能也要用到VM模板來(lái)做一些特殊的事情。本篇文章就來(lái)帶大家詳細(xì)了解下Node中的VM模塊,希望對(duì)大家有所幫助!

    深入了解Node.js中的VM模塊

    參考文獻(xiàn) vm 虛擬機(jī) | Node 官網(wǎng)

    http://nodejs.cn/api/vm.html

    在上一篇文章中,我們提到了一個(gè)問(wèn)題。

    字符串如何能變成 JS 執(zhí)行呢?

    我們?cè)敿?xì)介紹了兩種方法,分別是 eval函數(shù) 和 new Function 。

    在這里我們需要再?gòu)?qiáng)調(diào)一下, 由 Function 構(gòu)造器創(chuàng)建的函數(shù)不會(huì)創(chuàng)建當(dāng)前環(huán)境的閉包,它們總是被創(chuàng)建于全局環(huán)境,因此在運(yùn)行時(shí)它們只能訪(fǎng)問(wèn)全局變量和自己的局部變量,不能訪(fǎng)問(wèn)它們被 Function 構(gòu)造器創(chuàng)建時(shí)所在的作用域的變量。這一點(diǎn)與使用 eval 執(zhí)行創(chuàng)建函數(shù)的代碼不同。

    global.a = 100; // 掛在到全局對(duì)象global上 var b = 200; // this !== global new Function("console.log(a)")() // 100 new Function("console.log(b)")() // b is not defined

    Function 可以獲取全局變量,所以他還是可能會(huì)有變量污染的情況出現(xiàn)。Function模塊引擎的實(shí)現(xiàn)原理 ,后續(xù)我會(huì)出一篇文章進(jìn)行單獨(dú)講解。

    還有一種解決方案,我們?cè)谏弦淮挝恼轮袥](méi)有進(jìn)行詳細(xì)的展開(kāi),那就是 vm模塊

    vm模塊

    在上述文字中,我一直在強(qiáng)調(diào)一個(gè)概念,那就是 變量的污染

    VM的特點(diǎn)就是不受環(huán)境的影響,也可以說(shuō)他就是一個(gè) 沙箱環(huán)境 (沙箱模式給模塊提供一個(gè)環(huán)境運(yùn)行而不影響其它模塊和它們私有的沙箱)。

    const vm = require('vm') global.a = 100; // 運(yùn)行在當(dāng)前環(huán)境中[當(dāng)前作用域] vm.runInThisContext('console.log(a)'); // 100 // 運(yùn)行在新的環(huán)境中[其他作用域] vm.runInNewContext('console.log(a)'); // a is not defined

    在這里我們要強(qiáng)調(diào)一下,因?yàn)?在Node.js中全局變量是在多個(gè)模塊下共享的,所以盡量不要在global中定義屬性。 Demo中的定義是為了方便理解。

    假設(shè)我們?cè)谕?jí)目錄下有一個(gè)文件 1.js ,里面定義了 global.a = 100;。 現(xiàn)在我們引入這個(gè)文件

    requrie(./1); console.log(a); // 100

    我們可以發(fā)現(xiàn),在當(dāng)前文件中我們并沒(méi)有定義變量a,僅僅只是把兩個(gè)模塊文件關(guān)聯(lián)在了一起。這就是我上面提到的,Node中全局變量是在多個(gè)模塊下共享的。

    他的原理是因?yàn)樵?Node 的環(huán)境中,全局中有一個(gè)執(zhí)行上下文。

    // 模擬一下Node的全局環(huán)境 // vm.runInThisContext在當(dāng)前全局環(huán)境執(zhí)行,但不會(huì)產(chǎn)生新函數(shù) - function(exports, module, require, __dirname, __filename){ // ... } - vm.runInThisContext ... // vm.runInNewContext在全局環(huán)境之外執(zhí)行 vm.runInNewContext ...

    所以,vm.runInThisContext 可以訪(fǎng)問(wèn)到 global上的全局變量,但是訪(fǎng)問(wèn)不到自定義的變量。而 vm.runInNewContext 訪(fǎng)問(wèn)不到 global,也訪(fǎng)問(wèn)不到自定義變量,他存在于一個(gè)全新的執(zhí)行上下文。

    而我們require 就是通過(guò) vm.runInThisContext 實(shí)現(xiàn)的。

    實(shí)現(xiàn)require 主要可以分為以下四步。

    • 讀取需要引入的文件。

    • 讀取到文件后,將代碼封裝成一個(gè)函數(shù)。

    • 通過(guò) vm.runInThisContext 將他轉(zhuǎn)變成 JS 語(yǔ)法。

    • 代碼調(diào)用。

    假設(shè)我們現(xiàn)在有以下兩個(gè)文件。分別是 a.jsb.js

    // 文件a通過(guò)module.exports導(dǎo)出一個(gè)變量,在文件b中使用require進(jìn)行接收。 // a.js module.exports = "a" // b.js let a = require('./a'); console.log(a); // a

    我們可以通過(guò)上面的四個(gè)步驟,分析一下導(dǎo)入導(dǎo)出的實(shí)現(xiàn)邏輯是什么樣的。

    • 讀取文件。

      將需要引入的文件內(nèi)容引入到需要接收的文件里,就會(huì)變成這個(gè)樣子

      let a = module.exports = "a";

      但是這種形式,Node根本解析不了,所以我們就需要進(jìn)行第二步。

    • 將讀取的文件封裝成函數(shù)。

      let a = (function(exports, module, require, __dirname, __filename){   module.exports = "a";   return module.exports })(...args) // exports, module, require, __dirname, __filename 將五個(gè)參數(shù)傳入

      封裝成函數(shù)的原因,我們可以參考下面這個(gè)例子。

      假設(shè)我們現(xiàn)在傳入的不是字符串,而是一個(gè)函數(shù)。

      // a.js var a = 100; module.exports = function(){}

      這樣我們?cè)诮馕龅臅r(shí)候,就會(huì)被解析成下面這種格式

      let a = (function(exports, module, require, __dirname, __filename){   var a = 100;   module.exports = function(){};   return module.exports })(...args) // exports, module, require, __dirname, __filename 將五個(gè)參數(shù)傳入

      我們導(dǎo)出的是 module.exports,所以在模塊文件中定義的變量a,也只屬于當(dāng)前這個(gè)執(zhí)行上下文。

      在解析的時(shí)候,變量a 會(huì)被放到函數(shù)中。真正的實(shí)現(xiàn)了 作用域分離。

    • vm.runInThisContext 解析成可執(zhí)行的Js代碼

      我們處理過(guò)的代碼會(huì)以字符串的形式存在,所以我們需要通過(guò)vm.runInThisContext將字符串進(jìn)行解析。

    • 進(jìn)行代碼調(diào)用

      在此之前,我們其實(shí)還需要對(duì)代碼進(jìn)行調(diào)試。

    贊(0)
    分享到: 更多 (0)
    網(wǎng)站地圖   滬ICP備18035694號(hào)-2    滬公網(wǎng)安備31011702889846號(hào)