Reputation: 717
I've got some code like the following.
ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine engine = manager.getEngineByName("nashorn");
engine.eval("[1, 2, 3].includes(1)");
But that throws the following error
javax.script.ScriptException: TypeError: [1, 2, 3].includes is not a function in <eval> at line number 1
at jdk.nashorn.api.scripting.NashornScriptEngine.throwAsScriptException(NashornScriptEngine.java:470)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:454)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:406)
at jdk.nashorn.api.scripting.NashornScriptEngine.evalImpl(NashornScriptEngine.java:402)
at jdk.nashorn.api.scripting.NashornScriptEngine.eval(NashornScriptEngine.java:155)
at javax.script.AbstractScriptEngine.eval(AbstractScriptEngine.java:264)
I can do indexOf(1) instead and that seems to work, but is there a reason why I don't have access to includes with this parser?
Upvotes: 4
Views: 5485
Reputation: 732
Nashorn does not support includes() because it implemented an earlier version of the JavaScript spec before includes() was added. You can polyfill (aka shim) support for includes() into Nashorn using the reference on Mozilla's website.
The original question was for doing includes() on a JavaScript array. A previous answer was for JavaScript string, so not correct. Here is a snippet of JUnit test code that shows how to use polyfills for both arrays and strings.
// Copied from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes#Polyfill
public static final String NASHORN_POLYFILL_STRING_PROTOTYPE_INCLUDES = "if (!String.prototype.includes) { Object.defineProperty(String.prototype, 'includes', { value: function(search, start) { if (typeof start !== 'number') { start = 0 } if (start + search.length > this.length) { return false } else { return this.indexOf(search, start) !== -1 } } }) }";
// Copied from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Polyfill
public static final String NASHORN_POLYFILL_ARRAY_PROTOTYPE_INCLUDES = "if (!Array.prototype.includes) { Object.defineProperty(Array.prototype, 'includes', { value: function(valueToFind, fromIndex) { if (this == null) { throw new TypeError('\"this\" is null or not defined'); } var o = Object(this); var len = o.length >>> 0; if (len === 0) { return false; } var n = fromIndex | 0; var k = Math.max(n >= 0 ? n : len - Math.abs(n), 0); function sameValueZero(x, y) { return x === y || (typeof x === 'number' && typeof y === 'number' && isNaN(x) && isNaN(y)); } while (k < len) { if (sameValueZero(o[k], valueToFind)) { return true; } k++; } return false; } }); }";
@Test
public void testStringIncludesWithPolyfill() throws Exception {
runScript(NASHORN_POLYFILL_STRING_PROTOTYPE_INCLUDES, "'[1, 2, 3]'.includes(2)");
}
@Test(expected=javax.script.ScriptException.class)
public void testStringIncludesWithoutPolyfill() throws Exception {
runScript(null, "'[1, 2, 3]'.includes(2)");
}
@Test
public void testArrayIncludesWithPolyfill() throws Exception {
runScript(NASHORN_POLYFILL_ARRAY_PROTOTYPE_INCLUDES, "[1, 2, 3].includes(2)");
}
@Test(expected=javax.script.ScriptException.class)
public void testArrayIncludesWithoutPolyfill() throws Exception {
runScript(null, "[1, 2, 3].includes(2)");
}
private void runScript(final String polyfill, final String booleanExpression) throws ScriptException {
final ScriptEngineManager scriptEngineManager = new ScriptEngineManager();
final ScriptEngine scriptEngine = scriptEngineManager.getEngineByName("nashorn");
Assert.assertNotNull(scriptEngine);
if (null != polyfill) {
scriptEngine.eval(polyfill);
}
final Object booleanExpressionResult = scriptEngine.eval(booleanExpression); // returns Boolean object
Assert.assertNotNull(booleanExpressionResult);
Assert.assertEquals(booleanExpressionResult.getClass(), Boolean.class);
System.out.println(booleanExpression + " = " + booleanExpressionResult.toString());
}
Upvotes: 3
Reputation: 4405
String.prototype.includes is specified in ECMAScript 2015 ( ECMA-262 6th Edition). Nashorn engine implements ECMA-262 Edition 5.1). See also http://www.ecma-international.org/ecma-262/6.0/#sec-string.prototype.includes
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes has a polyfill for String.prototype.includes. I checked that the polyfill works with Nashorn engine.
Upvotes: 4