Differences Between SuiteScript 2.0 and SuiteScript 2.1

SuiteScript 2.1 uses a different runtime engine than SuiteScript 2.0, also supports ECMAScript language features that are not supported in SuiteScript 2.0. This causes some capabilities in SuiteScript 2.0 scripts to function differently when the script is executed using SuiteScript 2.1.

The following sections describe important differences between SuiteScript 2.0 and SuiteScript 2.1:

Reserved Words as Identifiers

In the ECMAScript specification, reserved words are identifiers that have special meaning. For example, the var reserved word indicates a variable declaration. You cannot use reserved words as variable names, labels, or function names in JavaScript/ECMAScript. Because SuiteScript 2.1 supports a later edition of the ECMAScript specification (ECMAScript 2019) than SuiteScript 2.0 (ECMAScript 5.1), the list of reserved words is different. SuiteScript 2.1 is stricter about not including reserved words in scripts.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You use extends in one of the following ways in a script:

                      myObj({extends: 'test'});
function myFunction(extends) {}
function extends() {}
var extends = 1; 

                    

The script executes and does not generate an error. The extends identifier is not a reserved word in ECMAScript 5.1.

The script generates a syntax error. The extends identifier is a reserved word in ECMAScript 2019.

To avoid this issue, do not use any reserved words from any edition of ECMAScript (including those planned for future editions using ES.Next). For more information, see SuiteScript Reserved Words.

Error Object Properties

SuiteScript supports the Error object, which is provided by ECMAScript, to represent errors that can occur in scripts. You can call JSON.stringify(obj) on an Error object to obtain a string representation of the error. If you pass an argument to the constructor when you create the Error object, the string representation in SuiteScript 2.0 includes this argument as the value of the message property. The string representation in SuiteScript 2.1 does not include the message property.

This difference is because of how JSON.stringify(obj) handles enumerable and non-enumerable properties. In SuiteScript 2.0, the output of JSON.stringify(obj) includes the content of both enumerable and non-enumerable properties. In SuiteScript 2.1, the output of JSON.stringify(obj) includes only the content of enumerable properties and does not include the content of non-enumerable properties, as per the ECMAScript specification.

When you pass an argument to the Error object constructor, a non-enumerable message property is defined. If you change the value of this property after the Error object is created, the property remains non-enumerable. So, when an Error object is created in this way, the message property is not included in the JSON.stringify(obj) output in SuiteScript 2.1 scripts.

By contrast, when you do not pass an argument to the Error object constructor, the message property is not defined. If you try to set the value of this property after the Error object is created, a new message property is defined. Properties that are defined in this way are always enumerable. So, when an Error object is created in this way, the message property is included in the JSON.stringify(obj) output in SuiteScript 2.1 scripts.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You use the following code to create an Error object with no argument in a script:

                      var myFirstError = new Error();
myFirstError.message = 'A message';

var firstErrorJson = JSON.stringify(myFirstError); 

                    

The firstErrorJson variable contains the following output:

                      {
    'message' : 'A message'
} 

                    

The firstErrorJson variable contains the following output:

                      {
    'message' : 'A message'
} 

                    

You use the following code to create an Error object with an argument in a script:

                      var mySecondError = new Error('');
mySecondError.message = 'A message';

var secondErrorJson = JSON.stringify(mySecondError); 

                    

The secondErrorJson variable contains the following output:

                      {
    'message' : 'A message'
} 

                    

The secondErrorJson variable contains the following output:

                      {} 

                    

To avoid this issue, use only enumerable properties for objects. For error messages, create Error objects with no arguments. For more information, see JSON.stringify(obj) and Enumerability and ownership of properties.

Invalid JSON Parsing

SuiteScript can parse JSON strings that you use in your scripts. When invalid JSON is encountered, a syntax error is generated. The type and format of the generated error message is different in SuiteScript 2.1 than in SuiteScript 2.0. Also, including trailing commas in JSON strings is accepted in SuiteScript 2.0 but generates an error in SuiteScript 2.1.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You try to parse the following JSON string in a script:

                      var obj = 'b';
JSON.parse(obj); 

                    

The following error is generated:

org.mozilla.javascript.EcmaError: SyntaxError: Unexpected token: b

The following (or similar) error is generated:

SyntaxError: Invalid JSON: <json>:1:0 Expected json literal but found b

You try to parse the following JSON string in a script:

                      JSON.parse('{"mykey" : 1, }'); 

                    

The script executes successfully.

The following (or similar) error is generated:

SyntaxError: Invalid JSON: <json>:1:0 Expected json literal but found ,

To avoid this issue, make sure you use the JSON format that is compatible with the ECMAScript specification. For more information, see JSON object.

Strict Mode

ECMAScript 5 introduced strict mode. If a SuiteScript 2.0 script assigns a value to a variable without first declaring the variable using the var or const keyword, the script continues executing and no error is thrown. If a SuiteScript 2.1 script assigns a value to a variable without using the var , let, or const keyword, an error is thrown. For more information about strict mode, see Strict Mode.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You place a portion of your script (or your entire script) into strict mode and assign a value to an undeclared variable:

                      'use strict';
x = 122;
log.debug('x = ', x); 

                    

Script execution completes without throwing an error.

The following error is generated:

ReferenceError: x is not defined

Reassignment of const Variables

JavaScript const variables create a read-only reference to a value. When a const variable is assigned a value, the variable identifier cannot be used again (reassigned). In SuiteScript 2.0, no error is thrown when you reassign a const variable. In SuiteScript 2.1, a TypeError is thrown.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You set a value for a const variable and then try to assign it a new value:

                      const recordId = 1;
recordId = 2;
log.debug("recordId", recordId); 

                    

The script completes execution successfully, however the value of recordId is not changed by the recordId = 2; line. The log statement will write: recordId 1.

The execution stops at the recordId = 2; line, and the following error is generated:

TypeError: Assignment to constant variable

Behavior of for...each...in Statement

The for...each...in statement was deprecated as part of ECMA-357 (4x) specifications and should no longer be used. In SuiteScript2.0, the for...each...in statement is accepted. In SuiteScript 2.1, a SyntaxError is thrown if you try to use the for...each...in statement in your script. For more information about the deprecation of for...each...in, see for..each..in.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You use a for...each...in statement to process values in an object:

                      var obj = {fileType: "csv", encoding: "UTF-8", isOnline: "false"};
for each(var value in obj) {
    log.debug("value = " , value);
} 

                    

The for...each...in statement is accepted and allows you to process the values in the object.

The following error is generated:

SyntaxError: SyntaxError: <eval>:3:4 Expected ( but found each for each ( var value in obj) {

Formats for Converting Dates to Local Date Strings

JavaScript supports several date formats and ways to create a date. After you create a date, you can convert it to a local date string. In SuiteScript 2.0, the default format for the converted date string is the long format. In SuiteScript 2.1, the default format for the converted date string is the short format.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You create a date and log two different formats for that date:

                      var event = new Date(Date.UTC(2012, 12, 21, 12));
log.debug("date1 = ", event.toLocalDateString();
log.debug("date2 = ", event.toLocalDateString('de-De', { year: 'numeric', month: 'long', day: 'numeric' })); 

                    

The default format is the long format, and additional properties passed are ignored.

The output is:

  • date1 = December 21, 2012

  • date2 = December 21, 2012

The default format is the short format, and additional properties passed are ignored.

The output is:

  • date1 = 2012–12–21

  • date2 = 2012–12–21

Conditional Catch Blocks

In JavaScript, a try-catch statement can include an optional if statement within the catch block, however it is not ECMAScript specification compliant. In SuiteScript 2.0, a script that includes a conditional catch statement executes without error. In SuiteScript 2.1, a SyntaxError is thrown for any script that includes a conditional catch statement.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You create a try-catch statement with an if statement in the catch block:

                      try {
// do something here
} catch (e if e instanceof TypeError) { // Don't use
    log.debug("error = " , e);
} 

                    

The script completes execution without throwing an error.

The following error is generated:

SyntaxError: SyntaxError: <eval>:2:11 Expected ) but found if } catch (e if e instanceof TypeError) { // Don’t use

The toSource Method

In JavaScript, the toSource method is used to return a string representing the source code of the object. However, this feature is obsolete and should not be used. In SuiteScript 2.0, a script that includes the toSource method for an object executes without error. In SuiteScript 2.1, an error is thrown for any script that includes the toSource method for an object. For more information about the toSource method, see toSource.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You try to log a transactions source:

                      function Transaction(name) {
    this.name = name;
}
var obj = new Transaction("myTrans");
log.debug("Transaction = ", Transaction.toSource());
log.debug("Transaction Obj = ", obj.toSource()); 

                    

The script completes execution without throwing an error.

An error is thrown indicating toSource is not a valid function.

Set Decimal Number with Trailing Zeros

When you set a decimal number value in JavaScript, behavior depends on the format of the numerical value. In SuiteScript 2.0, if there are trailing zeros in a decimal value you set, the value is set as a double precision floating point number (double). In SuiteScript 2.1, if there are trailing zeros in a decimal value you set, the value is set as an integer value. Note that in both SuiteScript 2.0 and SuiteScript 2.1, a value is always set as a double value if there are no trailing zeros in the decimal value you specify.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You set a decimal value with trailing zeros:

                      record.setValue('memo', 616.00) 

                    

record.setValue() saves a number as a double number: 616.0.

record.setValue() saves a number with trailing zeros as an Integer: 616.

You set a decimal value with no trailing zeros:

                      record.setValue('memo', 616.01) 

                    

record.setValue() saves a number as a double number: 616.01.

record.setValue() saves a number as a double number: 616.01.

String Differences for RESTlet Post Method

In SuiteScript 2.0, a JSON.stringify() call is added internally to whatever is passed in the post() method of a RESTlet. This affects the value passed. In SuiteScript 2.1, a JSON.stringify() call is not added to the post() method for a RESTlet.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You return JSON.stringify in a post function:

                      // the following is included in a 2.x RESTlet
...
function post() {
    return JSON.stringify("flower");
} 

                    

Returns "\"flower\"" and a string length of 12.

If you specify "flower" in the return statement, "flower" is returned with a string length of 8.

Returns "flower" and a string length of 8.

If you specify "flower" in the return statement, flower is returned with a string length of 6.

                      let xmlRequest = new XMLHttpRequest();
var url = "/app/site/hosting/restlet.nl?script=RESTLET_SCRIPT_ID&deploy=RESTLET_DEPLOYMENT_ID";

xmlRequest.onreadystatechange = () => {
    if (xmlRequest.readyState === 4) {
        if (xmlRequest.status === 200) {
            log.debug("xmlRequest.responseText=" + xmlRequest.responseText);
            log.debug("xmlRequest.responseText.length=" + xmlRequest.responseText.length);
        } else {
            log.debug("xmlRequest.status=" + xmlRequest.responseText);
        }
    }
};

xmlRequest.open("POST", url, true /* async */);
xmlRequest.setRequestHeader("Content-Type", "application/json");
xmlRequest.send(JSON.stringify({})); // log statements appear after request is sent 

                    

The log statements are:

xmlRequest.responseText="\"ok\""

xmlRequest.responseText.length=8

The log statements are:

xmlRequest.responseText="ok"

xmlRequest.responseText.length=4

RESTlet Return Type Difference

SuiteScript 2.1 changes the way that RESTlet responses are formatted for certain content types. When the Content-Type in the RESTlet header does not match the type that the RESTlet is returning, the results returned may not be what you are expecting.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

You set the Content-Type in a RESTlet header to application/json. For example, see the following sample RESTlet script and sample code for calling the RESTlet.

                      /**
 /**
 * @NApiVersion 2.x
 * @NScriptType restlet
 */
define([], function() {
        function get() {
                var x = {name:"jane", age:20};
                return JSON.stringify(x);
        }
        return {
                get: get
        }
}); 

                    
                      var host = window.location.host;
var url = 'https://' + host + '/app/site/hosting/restlet.nl?script=customscript296&deploy=customdeploy1';
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
       alert(typeof xhttp.response);
 alert(typeof JSON.parse(xhttp.response));
    }
};
xhttp.open("GET", url, true);
xhttp.setRequestHeader('Content-Type', 'application/json');
xhttp.send(); 

                    

The response is automatically converted to a string and that string is returned instead of an object.

In the example scenario, the alert output is a string, SS2.0 gives string; but in SS2.1 it comes as object.

The return type for JSON will be an object.

In the example scenario, the alert output is an object.

parseInt Difference

The parseInt function operates differently in SuiteScript 2.1 than it did in SuiteScript 2.0, for certain calls to parseInt. To avoid encountering incorrect results because of this difference, follow best practices when using the parstInt function, which can be found at: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt.

Scenario

SuiteScript 2.0 Behavior

SuiteScript 2.1 Behavior

Parse a string value representing a number.

                      require([],function() { 
    var x = parseInt('08');
    log.debug('x', x); 
}); 

                    

There is no value assigned to x.

The return value for x is 8.

Related Topics

General Notices