# 執行`JavaScript`
### 穩定度: 2 - 穩定
要獲取這個模塊,你可以通過:
~~~
var vm = require('vm');
~~~
`JavaScript`代碼會被編譯且立刻執行 或 編譯,保存,并且稍后執行。
#### vm.runInThisContext(code[, options])
`vm.runInThisContext()`編譯代碼,運行它,然后返回結果。運行中的代碼不能訪問本地作用域,但是可以訪問當前的全局對象。
使用`vm.runInThisContext`和`eval`運行相同代碼的例子:
~~~
var vm = require('vm');
var localVar = 'initial value';
var vmResult = vm.runInThisContext('localVar = "vm";');
console.log('vmResult: ', vmResult);
console.log('localVar: ', localVar);
var evalResult = eval('localVar = "eval";');
console.log('evalResult: ', evalResult);
console.log('localVar: ', localVar);
// vmResult: 'vm', localVar: 'initial value'
// evalResult: 'eval', localVar: 'eval'
~~~
`vm.runInThisContext`不能訪問本地作用域,所以`localVar`沒有改變。`eval`可以訪問本地作用域,所以`localVar`改變了。
這種情況下,`vm.runInThisContext`更像是一個間接的`eval`調用,像`(0,eval)('code')`。但是,它還有以下這些額外的選項:
- filename: 允許你控制提供在堆棧追蹤信息中的文件名。
- displayErrors: 是否在拋出異常前向`stderr`打印任何的錯誤,并且造成錯誤的行會被高亮。會捕獲編譯代碼時的語法錯誤和編譯完的代碼運行時拋出的異常。默認為`true`。
- timeout: 在關閉之前,允許代碼執行的時間(毫秒)。如果超時,一個錯誤被會拋出。
#### vm.createContext([sandbox])
如果指定了一個`sandbox`對象,則將`sandbox`“上下文化”,這樣它才可以被`vm.runInContext`或`script.runInContext`使用。在腳本內部,`sandbox`將會是全局對象,保留了它自己所有的屬性,并且包含內建對象和標準全局對象的所有函數。在由`vm`模塊運行的腳本之外的地方,`sandbox`將不會被改變。
如果沒有指定`sandbox`對象,將會返回一個你可以使用的新的,無內容的`sandbox`對象。
這個函數在創建被用來運行多個腳本的沙箱時十分有用,例如,如果你正在模擬一個web瀏覽器,則可以創建一個代表了`window`全局對象的沙箱,然后在沙箱內運行所有的`<script>`標簽。
#### vm.isContext(sandbox)
返回一個沙箱是否已經通過調用`vm.createContext`上下文化。
#### vm.runInContext(code, contextifiedSandbox[, options])
`vm.runInContext`編譯代碼,然后將其在`contextifiedSandbox`中運行,然后返回結果。運行的代碼不能訪問本地作用域。`contextifiedSandbox`必須通過`vm.createContext`上下文化;它被用來當做代碼的全局對象。
`vm.runInContext`的選項和`vm.runInThisContext`相同。
例子:編譯并執行不同的腳本,在同一個已存在的上下文中。
~~~
var util = require('util');
var vm = require('vm');
var sandbox = { globalVar: 1 };
vm.createContext(sandbox);
for (var i = 0; i < 10; ++i) {
vm.runInContext('globalVar *= 2;', sandbox);
}
console.log(util.inspect(sandbox));
// { globalVar: 1024 }
~~~
注意,運行不受信任的代碼是一個十分棘手的工作,需要十分小心。`vm.runInContext`是十分有用的,但是為了安全的運行不受信任的代碼,還是將它們放在另一個單獨的進程中為好。
#### vm.runInNewContext(code[, sandbox][, options])
`vm.runInNewContext`編譯代碼,接著,如果傳遞了`sandbox`則上下文化`sandbox`,如果沒有就創建一個新的已上下文化的沙箱,然后將沙箱作為全局對象運行代碼并返回結果。
`vm.runInNewContext`的選項和`vm.runInThisContext`相同。
例子:編譯并執行一個 自增一個全局變量然后設置一個新的全局變量 的代碼。這些全局變量包含在沙箱中。
~~~
var util = require('util');
var vm = require('vm');
var sandbox = {
animal: 'cat',
count: 2
};
vm.runInNewContext('count += 1; name = "kitty"', sandbox);
console.log(util.inspect(sandbox));
// { animal: 'cat', count: 3, name: 'kitty' }
~~~
注意,運行不受信任的代碼是一個十分棘手的工作,需要十分小心。`vm.runInNewContext`是十分有用的,但是為了安全的運行不受信任的代碼,還是將它們放在另一個單獨的進程中為好。
#### vm.runInDebugContext(code)
`vm.runInDebugContext`編譯代碼,然后將它們在V8調試上下文中執行。主要的用途是訪問V8調試對象:
~~~
var Debug = vm.runInDebugContext('Debug');
Debug.scripts().forEach(function(script) { console.log(script.name); });
~~~
注意,調試上下文和對象與V8的調試實現聯系緊密,它們可能在沒有事先提醒的情況就發生改變(或被移除)。
調試對象也可以通過`--expose_debug_as= switch`被暴露。
#### Class: Script
一個包含預編譯代碼,然后將它們運行在指定沙箱中的類。
#### new vm.Script(code, options)
創建一個編譯代碼但不執行它的新`Script`類。也就是說,一個創建好的`vm.Script`對象代表了它的編譯完畢的代碼。這個腳本已經通過下文的方法在晚些時候被調用多次。返回的腳本沒有被綁定在任何的全局對象上。它可以在每次運行前被綁定,所以只在那次運行時有效。
`options`可以有以下屬性:
- filename: 允許你控制提供在堆棧追蹤信息中的文件名。
- displayErrors: 是否在拋出異常前向`stderr`打印任何的錯誤,并且造成錯誤的行會被高亮。會捕獲編譯代碼時的語法錯誤和運行時由腳本的方法的配置所控制的代碼拋出的錯誤。
#### script.runInThisContext([options])
與`vm.runInThisContext`相似,但是是一個預編譯的`Script`對象的方法。`script.runInThisContext`運行腳本被編譯完畢的代碼,然后返回結果。運行中的代碼不能訪問本地作用域,但是可以訪問當前的全局對象。
一個使用`script.runInThisContext`來編譯一次代碼,然后運行多次的例子:
~~~
var vm = require('vm');
global.globalVar = 0;
var script = new vm.Script('globalVar += 1', { filename: 'myfile.vm' });
for (var i = 0; i < 1000; ++i) {
script.runInThisContext();
}
console.log(globalVar);
// 1000
~~~
`options`可以有以下屬性:
-
displayErrors: 是否在拋出異常前向`stderr`打印任何的錯誤,并且造成錯誤的行會被高亮。只會應用于運行中代碼的執行錯誤;創建一個有語法錯誤的`Script`實例是不可能的,因為構造函數會拋出異常。
-
timeout: 在關閉之前,允許代碼執行的時間(毫秒)。如果超時,一個錯誤被會拋出。
#### script.runInContext(contextifiedSandbox[, options])
與`vm.runInContext`相似,但是是一個預編譯的`Script`對象的方法。`script.runInContext`運行腳本被編譯完畢的代碼,然后返回結果。運行中的代碼不能訪問本地作用域。
`script.runInContext`的選項和`script.runInThisContext`相同。
例子:編譯一段 自增一個全局對象并且創建一個全局對象 的代碼,然后執行多次,這些全局對象包含在沙箱中。
~~~
var util = require('util');
var vm = require('vm');
var sandbox = {
animal: 'cat',
count: 2
};
var context = new vm.createContext(sandbox);
var script = new vm.Script('count += 1; name = "kitty"');
for (var i = 0; i < 10; ++i) {
script.runInContext(context);
}
console.log(util.inspect(sandbox));
// { animal: 'cat', count: 12, name: 'kitty' }
~~~
注意,運行不受信任的代碼是一個十分棘手的工作,需要十分小心。`script.runInContext`是十分有用的,但是為了安全的運行不受信任的代碼,還是將它們放在另一個單獨的進程中為好。
#### script.runInNewContext([sandbox][, options])
與`vm.runInNewContext`相似,但是是一個預編譯的`Script`對象的方法。如果傳遞了`sandbox`,`script.runInNewContext`將上下文化`sandbox`,如果沒有就創建一個新的已上下文化的沙箱,然后將沙箱作為全局對象運行代碼并返回結果。運行中的代碼不能訪問本地作用域。
`script.runInNewContext`的選項和`script.runInThisContext`相同。
例子:編譯一段 設置一個全局對象 的代碼,然后在不同的上下文中多次執行它。這些全局對象包含在沙箱中。
~~~
var util = require('util');
var vm = require('vm');
var sandboxes = [{}, {}, {}];
var script = new vm.Script('globalVar = "set"');
sandboxes.forEach(function (sandbox) {
script.runInNewContext(sandbox);
});
console.log(util.inspect(sandboxes));
// [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
~~~
注意,運行不受信任的代碼是一個十分棘手的工作,需要十分小心。`script.runInNewContext`是十分有用的,但是為了安全的運行不受信任的代碼,還是將它們放在另一個單獨的進程中為好。