JavaScript Changes in MongoDB 2.4

Consider the following impacts of V8 JavaScript Engine inMongoDB 2.4:

Tip

Use the new interpreterVersion() method in themongo shell and the javascriptEnginefield in the output of db.serverBuildInfo() to determinewhich JavaScript engine a MongoDB binary uses.

Improved Concurrency

Previously, MongoDB operations that required the JavaScript interpreterhad to acquire a lock, and a single mongod could only run asingle JavaScript operation at a time. The switch to V8 improvesconcurrency by permitting multiple JavaScript operations to run at thesame time.

Modernized JavaScript Implementation (ES5)

The 5th edition of ECMAscript,abbreviated as ES5, adds many new language features, including:

With V8, MongoDB supports the ES5 implementation of Javascript with thefollowing exceptions.

Note

The following features do not work as expected on documentsreturned from MongoDB queries:

  • Object.seal() throws an exception on documents returned fromMongoDB queries.
  • Object.freeze() throws an exception on documents returned fromMongoDB queries.
  • Object.preventExtensions() incorrectly allows the addition ofnew properties on documents returned from MongoDB queries.
  • enumerable properties, when added to documents returned fromMongoDB queries, are not saved during write operations.

See SERVER-8216, SERVER-8223,SERVER-8215, and SERVER-8214 for more information.

For objects that have not been returned from MongoDB queries, thefeatures work as expected.

Removed Non-Standard SpiderMonkey Features

V8 does not support the following non-standardSpiderMonkey JavaScriptextensions, previously supported by MongoDB’s use of SpiderMonkey asits JavaScript engine.

E4X Extensions

V8 does not support the non-standardE4X extensions. E4Xprovides a native XMLobject to the JavaScript language and adds the syntax for embeddingliteral XML documents in JavaScript code.

You need to use alternative XML processing if you used any of thefollowing constructors/methods:

  • XML()
  • Namespace()
  • QName()
  • XMLList()
  • isXMLName()

Destructuring Assignment

V8 does not support the non-standard destructuring assignments.Destructuring assignment “extract[s] data from arrays or objects usinga syntax that mirrors the construction of array and object literals.” -Mozilla docs)

Example

The following destructuring assignment is invalid with V8 andthrows a SyntaxError:

  1. original = [4, 8, 15];
  2. var [b, ,c] = a; // <== destructuring assignment
  3. print(b) // 4
  4. print(c) // 15

Iterator(), StopIteration(), and Generators

V8 does not support Iterator(), StopIteration(), and generators.

InternalError()

V8 does not support InternalError(). Use Error() instead.

for each…in Construct

V8 does not support the use of for each…inconstruct. Use for (var x in y) constructinstead.

Example

The following for each (var x in y) construct is invalidwith V8:

  1. var o = { name: 'MongoDB', version: 2.4 };
  2.  
  3. for each (var value in o) {
  4. print(value);
  5. }

Instead, in version 2.4, you can use the for (var x in y)construct:

  1. var o = { name: 'MongoDB', version: 2.4 };
  2.  
  3. for (var prop in o) {
  4. var value = o[prop];
  5. print(value);
  6. }

You can also use the array instance method forEach() with theES5 method Object.keys():

  1. Object.keys(o).forEach(function (key) {
  2. var value = o[key];
  3. print(value);
  4. });

Array Comprehension

V8 does not support Array comprehensions.

Use other methods such as the Array instance methods map(),filter(), or forEach().

Example

With V8, the following array comprehension is invalid:

  1. var a = { w: 1, x: 2, y: 3, z: 4 }
  2.  
  3. var arr = [i * i for each (i in a) if (i > 2)]
  4. printjson(arr)

Instead, you can implement using the Array instance methodforEach() and the ES5 method Object.keys() :

  1. var a = { w: 1, x: 2, y: 3, z: 4 }
  2.  
  3. var arr = [];
  4. Object.keys(a).forEach(function (key) {
  5. var val = a[key];
  6. if (val > 2) arr.push(val * val);
  7. })
  8. printjson(arr)

Note

The new logic uses the Array instance method forEach() andnot the generic method Array.forEach(); V8 does notsupport Array generic methods. See Array Generic Methods formore information.

Multiple Catch Blocks

V8 does not support multiple catch blocks and will throw aSyntaxError.

Example

The following multiple catch blocks is invalid with V8 and willthrow "SyntaxError: Unexpected token if":

  1. try {
  2. something()
  3. } catch (err if err instanceof SomeError) {
  4. print('some error')
  5. } catch (err) {
  6. print('standard error')
  7. }

Conditional Function Definition

V8 will produce different outcomes than SpiderMonkey with conditionalfunction definitions.

Example

The following conditional function definition produces differentoutcomes in SpiderMonkey versus V8:

  1. function test () {
  2. if (false) {
  3. function go () {};
  4. }
  5. print(typeof go)
  6. }

With SpiderMonkey, the conditional function outputs undefined,whereas with V8, the conditional function outputs function.

If your code defines functions this way, it is highly recommendedthat you refactor the code. The following example refactors theconditional function definition to work in both SpiderMonkey and V8.

  1. function test () {
  2. var go;
  3. if (false) {
  4. go = function () {}
  5. }
  6. print(typeof go)
  7. }

The refactored code outputs undefined in both SpiderMonkey and V8.

Note

ECMAscript prohibits conditional function definitions. To force V8to throw an Error, enable strict mode.

  1. function test () {
  2. 'use strict';
  3.  
  4. if (false) {
  5. function go () {}
  6. }
  7. }

The JavaScript code throws the following syntax error:

  1. SyntaxError: In strict mode code, functions can only be declared at top level or immediately within another function.

String Generic Methods

V8 does not support String generics.String generics are a set of methods on the String class thatmirror instance methods.

Example

The following use of the generic methodString.toLowerCase() is invalid with V8:

  1. var name = 'MongoDB';
  2.  
  3. var lower = String.toLowerCase(name);

With V8, use the String instance method toLowerCase() availablethrough an instance of the String class instead:

  1. var name = 'MongoDB';
  2.  
  3. var lower = name.toLowerCase();
  4. print(name + ' becomes ' + lower);

With V8, use the String instance methods instead of followinggeneric methods:

String.charAt()String.quote()String.toLocaleLowerCase()
String.charCodeAt()String.replace()String.toLocaleUpperCase()
String.concat()String.search()String.toLowerCase()
String.endsWith()String.slice()String.toUpperCase()
String.indexOf()String.split()String.trim()
String.lastIndexOf()String.startsWith()String.trimLeft()
String.localeCompare()String.substr()String.trimRight()
String.match()String.substring()

Array Generic Methods

V8 does not support Array generic methods.Array generics are a set of methods on the Array class that mirrorinstance methods.

Example

The following use of the generic method Array.every() isinvalid with V8:

  1. var arr = [4, 8, 15, 16, 23, 42];
  2.  
  3. function isEven (val) {
  4. return 0 === val % 2;
  5. }
  6.  
  7. var allEven = Array.every(arr, isEven);
  8. print(allEven);

With V8, use the Array instance method every() available throughan instance of the Array class instead:

  1. var allEven = arr.every(isEven);
  2. print(allEven);

With V8, use the Array instance methods instead of the followinggeneric methods:

Array.concat()Array.lastIndexOf()Array.slice()
Array.every()Array.map()Array.some()
Array.filter()Array.pop()Array.sort()
Array.forEach()Array.push()Array.splice()
Array.indexOf()Array.reverse()Array.unshift()
Array.join()Array.shift()

Array Instance Method toSource()

V8 does not support the Array instance method toSource().Use the Array instance method toString() instead.

uneval()

V8 does not support the non-standard method uneval(). Use thestandardized JSON.stringify()method instead.