doc: remove "above" and "below" references
[platform/upstream/nodejs.git] / doc / api / vm.markdown
index b454c73..39940ce 100644 (file)
 # Executing JavaScript
 
-    Stability: 2 - Unstable. See Caveats, below.
+    Stability: 2 - Stable
 
 <!--name=vm-->
 
 You can access this module with:
 
-    var vm = require('vm');
+    const vm = require('vm');
 
-JavaScript code can be compiled and run immediately or compiled, saved, and run later.
+JavaScript code can be compiled and run immediately or compiled, saved, and run
+later.
 
-## Caveats
+## Class: Script
 
-The `vm` module has many known issues and edge cases. If you run into
-issues or unexpected behavior, please consult [the open issues on
-GitHub](https://github.com/joyent/node/search?q=vm+state%3Aopen&type=Issues).
-Some of the biggest problems are described below.
+A class for holding precompiled scripts, and running them in specific sandboxes.
 
-### Sandboxes
+### new vm.Script(code, options)
 
-The `sandbox` argument to `vm.runInNewContext` and `vm.createContext`,
-along with the `initSandbox` argument to `vm.createContext`, do not
-behave as one might normally expect and their behavior varies
-between different versions of Node.
+Creating a new `Script` compiles `code` but does not run it. Instead, the
+created `vm.Script` object represents this compiled code. This script can be run
+later many times using methods below. The returned script is not bound to any
+global object. It is bound before each run, just for that run.
 
-The key issue to be aware of is that V8 provides no way to directly
-control the global object used within a context. As a result, while
-properties of your `sandbox` object will be available in the context,
-any properties from the `prototype`s of the `sandbox` may not be
-available. Furthermore, the `this` expression within the global scope
-of the context evaluates to the empty object (`{}`) instead of to
-your sandbox.
+The options when creating a script are:
 
-Your sandbox's properties are also not shared directly with the script.
-Instead, the properties of the sandbox are copied into the context at
-the beginning of execution, and then after execution, the properties
-are copied back out in an attempt to propagate any changes.
+- `filename`: allows you to control the filename that shows up in any stack
+  traces produced from this script.
+- `lineOffset`: allows you to add an offset to the line number that is
+  displayed in stack traces
+- `columnOffset`: allows you to add an offset to the column number that is
+  displayed in stack traces
+- `displayErrors`: whether or not to print any errors to stderr, with the
+  line of code that caused them highlighted, before throwing an exception.
+  Applies only to syntax errors compiling the code; errors while running the
+  code are controlled by the options to the script's methods.
+- `timeout`: a number of milliseconds to execute `code` before terminating
+  execution. If execution is terminated, an [`Error`][] will be thrown.
 
-### Globals
+### script.runInContext(contextifiedSandbox[, options])
 
-Properties of the global object, like `Array` and `String`, have
-different values inside of a context. This means that common
-expressions like `[] instanceof Array` or
-`Object.getPrototypeOf([]) === Array.prototype` may not produce
-expected results when used inside of scripts evaluated via the `vm` module.
+Similar to [`vm.runInContext()`][] but a method of a precompiled `Script`
+object. `script.runInContext()` runs `script`'s compiled code in
+`contextifiedSandbox` and returns the result. Running code does not have access
+to local scope.
 
-Some of these problems have known workarounds listed in the issues for
-`vm` on GitHub. for example, `Array.isArray` works around
-the example problem with `Array`.
+`script.runInContext()` takes the same options as
+[`script.runInThisContext()`][].
 
-## vm.runInThisContext(code, [filename])
+Example: compile code that increments a global variable and sets one, then
+execute the code multiple times. These globals are contained in the sandbox.
 
-`vm.runInThisContext()` compiles `code`, runs it and returns the result. Running
-code does not have access to local scope. `filename` is optional, it's used only
-in stack traces.
+    const util = require('util');
+    const vm = require('vm');
 
-Example of using `vm.runInThisContext` and `eval` to run the same code:
+    var sandbox = {
+      animal: 'cat',
+      count: 2
+    };
 
-    var localVar = 123,
-        usingscript, evaled,
-        vm = require('vm');
+    var context = new vm.createContext(sandbox);
+    var script = new vm.Script('count += 1; name = "kitty"');
 
-    usingscript = vm.runInThisContext('localVar = 1;',
-      'myfile.vm');
-    console.log('localVar: ' + localVar + ', usingscript: ' +
-      usingscript);
-    evaled = eval('localVar = 1;');
-    console.log('localVar: ' + localVar + ', evaled: ' +
-      evaled);
+    for (var i = 0; i < 10; ++i) {
+      script.runInContext(context);
+    }
 
-    // localVar: 123, usingscript: 1
-    // localVar: 1, evaled: 1
+    console.log(util.inspect(sandbox));
 
-`vm.runInThisContext` does not have access to the local scope, so `localVar` is unchanged.
-`eval` does have access to the local scope, so `localVar` is changed.
+    // { animal: 'cat', count: 12, name: 'kitty' }
 
-In case of syntax error in `code`, `vm.runInThisContext` emits the syntax error to stderr
-and throws an exception.
+Note that running untrusted code is a tricky business requiring great care.
+`script.runInContext()` is quite useful, but safely running untrusted code
+requires a separate process.
 
+### script.runInNewContext([sandbox][, options])
 
-## vm.runInNewContext(code, [sandbox], [filename])
+Similar to [`vm.runInNewContext()`][] but a method of a precompiled `Script`
+object. `script.runInNewContext()` contextifies `sandbox` if passed or creates a
+new contextified sandbox if it's omitted, and then runs `script`'s compiled code
+with the sandbox as the global object and returns the result. Running code does
+not have access to local scope.
 
-`vm.runInNewContext` compiles `code`, then runs it in `sandbox` and returns the
-result. Running code does not have access to local scope. The object `sandbox`
-will be used as the global object for `code`.
-`sandbox` and `filename` are optional, `filename` is only used in stack traces.
+`script.runInNewContext()` takes the same options as
+[`script.runInThisContext()`][].
 
-Example: compile and execute code that increments a global variable and sets a new one.
-These globals are contained in the sandbox.
+Example: compile code that sets a global variable, then execute the code
+multiple times in different contexts. These globals are set on and contained in
+the sandboxes.
 
-    var util = require('util'),
-        vm = require('vm'),
-        sandbox = {
-          animal: 'cat',
-          count: 2
-        };
+    const util = require('util');
+    const vm = require('vm');
 
-    vm.runInNewContext('count += 1; name = "kitty"', sandbox, 'myfile.vm');
-    console.log(util.inspect(sandbox));
+    const sandboxes = [{}, {}, {}];
 
-    // { animal: 'cat', count: 3, name: 'kitty' }
+    const script = new vm.Script('globalVar = "set"');
 
-Note that running untrusted code is a tricky business requiring great care.  To prevent accidental
-global variable leakage, `vm.runInNewContext` is quite useful, but safely running untrusted code
-requires a separate process.
+    sandboxes.forEach((sandbox) => {
+      script.runInNewContext(sandbox);
+    });
 
-In case of syntax error in `code`, `vm.runInNewContext` emits the syntax error to stderr
-and throws an exception.
+    console.log(util.inspect(sandboxes));
 
-## vm.runInContext(code, context, [filename])
+    // [{ globalVar: 'set' }, { globalVar: 'set' }, { globalVar: 'set' }]
 
-`vm.runInContext` compiles `code`, then runs it in `context` and returns the
-result. A (V8) context comprises a global object, together with a set of
-built-in objects and functions. Running code does not have access to local scope
-and the global object held within `context` will be used as the global object
-for `code`.
-`filename` is optional, it's used only in stack traces.
+Note that running untrusted code is a tricky business requiring great care.
+`script.runInNewContext()` is quite useful, but safely running untrusted code
+requires a separate process.
 
-Example: compile and execute code in a existing context.
+### script.runInThisContext([options])
 
-    var util = require('util'),
-        vm = require('vm'),
-        initSandbox = {
-          animal: 'cat',
-          count: 2
-        },
-        context = vm.createContext(initSandbox);
+Similar to [`vm.runInThisContext()`]() but a method of a precompiled `Script`
+object. `script.runInThisContext()` runs `script`'s compiled code and returns
+the result. Running code does not have access to local scope, but does have
+access to the current `global` object.
 
-    vm.runInContext('count += 1; name = "CATT"', context, 'myfile.vm');
-    console.log(util.inspect(context));
+Example of using `script.runInThisContext()` to compile code once and run it
+multiple times:
 
-    // { animal: 'cat', count: 3, name: 'CATT' }
+    const vm = require('vm');
 
-Note that `createContext` will perform a shallow clone of the supplied sandbox object in order to
-initialize the global object of the freshly constructed context.
+    global.globalVar = 0;
 
-Note that running untrusted code is a tricky business requiring great care.  To prevent accidental
-global variable leakage, `vm.runInContext` is quite useful, but safely running untrusted code
-requires a separate process.
+    const script = new vm.Script('globalVar += 1', { filename: 'myfile.vm' });
 
-In case of syntax error in `code`, `vm.runInContext` emits the syntax error to stderr
-and throws an exception.
+    for (var i = 0; i < 1000; ++i) {
+      script.runInThisContext();
+    }
 
-## vm.createContext([initSandbox])
+    console.log(globalVar);
 
-`vm.createContext` creates a new context which is suitable for use as the 2nd argument of a subsequent
-call to `vm.runInContext`. A (V8) context comprises a global object together with a set of
-build-in objects and functions. The optional argument `initSandbox` will be shallow-copied
-to seed the initial contents of the global object used by the context.
+    // 1000
 
-## vm.createScript(code, [filename])
+The options for running a script are:
 
-`createScript` compiles `code` but does not run it. Instead, it returns a
-`vm.Script` object representing this compiled code. This script can be run
-later many times using methods below. The returned script is not bound to any
-global object. It is bound before each run, just for that run. `filename` is
-optional, it's only used in stack traces.
+- `filename`: allows you to control the filename that shows up in any stack
+  traces produced.
+- `lineOffset`: allows you to add an offset to the line number that is
+  displayed in stack traces
+- `columnOffset`: allows you to add an offset to the column number that is
+  displayed in stack traces
+- `displayErrors`: whether or not to print any errors to stderr, with the
+  line of code that caused them highlighted, before throwing an exception.
+  Applies only to runtime errors executing the code; it is impossible to create
+  a `Script` instance with syntax errors, as the constructor will throw.
+- `timeout`: a number of milliseconds to execute the script before terminating
+  execution. If execution is terminated, an [`Error`][] will be thrown.
 
-In case of syntax error in `code`, `createScript` prints the syntax error to stderr
-and throws an exception.
+## vm.createContext([sandbox])
 
+If given a `sandbox` object, will "contextify" that sandbox so that it can be
+used in calls to [`vm.runInContext()`][] or [`script.runInContext()`][]. Inside
+scripts run as such, `sandbox` will be the global object, retaining all its
+existing properties but also having the built-in objects and functions any
+standard [global object][] has. Outside of scripts run by the vm module,
+`sandbox` will be unchanged.
 
-## Class: Script
+If not given a sandbox object, returns a new, empty contextified sandbox object
+you can use.
 
-A class for running scripts.  Returned by vm.createScript.
+This function is useful for creating a sandbox that can be used to run multiple
+scripts, e.g. if you were emulating a web browser it could be used to create a
+single sandbox representing a window's global object, then run all `<script>`
+tags together inside that sandbox.
 
-### script.runInThisContext()
+## vm.isContext(sandbox)
 
-Similar to `vm.runInThisContext` but a method of a precompiled `Script` object.
-`script.runInThisContext` runs the code of `script` and returns the result.
-Running code does not have access to local scope, but does have access to the `global` object
-(v8: in actual context).
+Returns whether or not a sandbox object has been contextified by calling
+[`vm.createContext()`][] on it.
 
-Example of using `script.runInThisContext` to compile code once and run it multiple times:
+## vm.runInContext(code, contextifiedSandbox[, options])
 
-    var vm = require('vm');
+`vm.runInContext()` compiles `code`, then runs it in `contextifiedSandbox` and
+returns the result. Running code does not have access to local scope. The
+`contextifiedSandbox` object must have been previously contextified via
+[`vm.createContext()`][]; it will be used as the global object for `code`.
 
-    globalVar = 0;
+`vm.runInContext()` takes the same options as [`vm.runInThisContext()`][].
 
-    var script = vm.createScript('globalVar += 1', 'myfile.vm');
+Example: compile and execute different scripts in a single existing context.
 
-    for (var i = 0; i < 1000 ; i += 1) {
-      script.runInThisContext();
+    const util = require('util');
+    const vm = require('vm');
+
+    const sandbox = { globalVar: 1 };
+    vm.createContext(sandbox);
+
+    for (var i = 0; i < 10; ++i) {
+        vm.runInContext('globalVar *= 2;', sandbox);
     }
+    console.log(util.inspect(sandbox));
 
-    console.log(globalVar);
+    // { globalVar: 1024 }
 
-    // 1000
+Note that running untrusted code is a tricky business requiring great care.
+`vm.runInContext()` is quite useful, but safely running untrusted code requires
+a separate process.
 
+## vm.runInDebugContext(code)
 
-### script.runInNewContext([sandbox])
+`vm.runInDebugContext()` compiles and executes `code` inside the V8 debug
+context. The primary use case is to get access to the V8 debug object:
 
-Similar to `vm.runInNewContext` a method of a precompiled `Script` object.
-`script.runInNewContext` runs the code of `script` with `sandbox` as the global object and returns the result.
-Running code does not have access to local scope. `sandbox` is optional.
+    const Debug = vm.runInDebugContext('Debug');
+    Debug.scripts().forEach(function(script) { console.log(script.name); });
 
-Example: compile code that increments a global variable and sets one, then execute this code multiple times.
-These globals are contained in the sandbox.
+Note that the debug context and object are intrinsically tied to V8's debugger
+implementation and may change (or even get removed) without prior warning.
 
-    var util = require('util'),
-        vm = require('vm'),
-        sandbox = {
-          animal: 'cat',
-          count: 2
-        };
+The debug object can also be exposed with the `--expose_debug_as=` switch.
 
-    var script = vm.createScript('count += 1; name = "kitty"', 'myfile.vm');
+## vm.runInNewContext(code[, sandbox][, options])
 
-    for (var i = 0; i < 10 ; i += 1) {
-      script.runInNewContext(sandbox);
-    }
+`vm.runInNewContext()` compiles `code`, contextifies `sandbox` if passed or
+creates a new contextified sandbox if it's omitted, and then runs the code with
+the sandbox as the global object and returns the result.
+
+`vm.runInNewContext()` takes the same options as [`vm.runInThisContext()`][].
 
+Example: compile and execute code that increments a global variable and sets a
+new one. These globals are contained in the sandbox.
+
+    const util = require('util');
+    const vm = require('vm');
+
+    const sandbox = {
+      animal: 'cat',
+      count: 2
+    };
+
+    vm.runInNewContext('count += 1; name = "kitty"', sandbox);
     console.log(util.inspect(sandbox));
 
-    // { animal: 'cat', count: 12, name: 'kitty' }
+    // { animal: 'cat', count: 3, name: 'kitty' }
 
-Note that running untrusted code is a tricky business requiring great care.  To prevent accidental
-global variable leakage, `script.runInNewContext` is quite useful, but safely running untrusted code
-requires a separate process.
+Note that running untrusted code is a tricky business requiring great care.
+`vm.runInNewContext()` is quite useful, but safely running untrusted code requires
+a separate process.
+
+## vm.runInThisContext(code[, options])
+
+`vm.runInThisContext()` compiles `code`, runs it and returns the result. Running
+code does not have access to local scope, but does have access to the current
+`global` object.
+
+Example of using `vm.runInThisContext()` and [`eval()`][] to run the same code:
+
+    const vm = require('vm');
+    var localVar = 'initial value';
+
+    const vmResult = vm.runInThisContext('localVar = "vm";');
+    console.log('vmResult: ', vmResult);
+    console.log('localVar: ', localVar);
+
+    const evalResult = eval('localVar = "eval";');
+    console.log('evalResult: ', evalResult);
+    console.log('localVar: ', localVar);
+
+    // vmResult: 'vm', localVar: 'initial value'
+    // evalResult: 'eval', localVar: 'eval'
+
+`vm.runInThisContext()` does not have access to the local scope, so `localVar`
+is unchanged. [`eval()`][] does have access to the local scope, so `localVar` is
+changed.
+
+In this way `vm.runInThisContext()` is much like an [indirect `eval()` call][],
+e.g. `(0,eval)('code')`. However, it also has the following additional options:
+
+- `filename`: allows you to control the filename that shows up in any stack
+  traces produced.
+- `lineOffset`: allows you to add an offset to the line number that is
+  displayed in stack traces
+- `columnOffset`: allows you to add an offset to the column number that is
+  displayed in stack traces
+- `displayErrors`: whether or not to print any errors to stderr, with the
+  line of code that caused them highlighted, before throwing an exception.
+  Will capture both syntax errors from compiling `code` and runtime errors
+  thrown by executing the compiled code. Defaults to `true`.
+- `timeout`: a number of milliseconds to execute `code` before terminating
+  execution. If execution is terminated, an [`Error`][] will be thrown.
+
+[indirect `eval()` call]: https://es5.github.io/#x10.4.2
+[global object]: https://es5.github.io/#x15.1
+[`Error`]: errors.html#errors_class_error
+[`script.runInContext()`]: #vm_script_runincontext_contextifiedsandbox_options
+[`script.runInThisContext()`]: #vm_script_runinthiscontext_options
+[`vm.createContext()`]: #vm_vm_createcontext_sandbox
+[`vm.runInContext()`]: #vm_vm_runincontext_code_contextifiedsandbox_options
+[`vm.runInNewContext()`]: #vm_vm_runinnewcontext_code_sandbox_options
+[`vm.runInThisContext()`]: #vm_vm_runinthiscontext_code_options
+[`eval()`]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/eval