Attila Szegedi
szegedia at gmail.com
Mon Oct 17 05:44:50 UTC 2016
it’s a side effect of the fact that primitive strings values in Nashorn are instances of java.lang.String, and the fact that with Nashorn you can invoke methods on Java objects, therefore “startsWith” is a Java String method.
While Java methods also don’t inherit from Function.prototype (hence, you can’t call “call” on them as you have correctly observed), implementations of Function.prototype.call and .apply are actually coded so that they do work on them with a not terribly obvious, but correct invocation:
var sw = "".startsWith
Function.prototype.call.call(sw, "abc", "a")
should return true. Note that since the expression fn.call.call is totally unbound from the fn that produced it, you can use any “fn”; I usually use “Function” for some semblance of clarity:
Function.call.call(sw, "abc", "a")
Finally, .startsWith is only present on primitive String values (as they’re java.lang.String), not on JS String objects, that’s why you were getting results you didn’t expect from “typeof Object(string).startsWith”
HTH,
Attila.
> On 16 Oct 2016, at 13:42, Esben Andreasen <esben at esbena.dk> wrote:
>
> Hi
>
> I am not sure if this is a bug or feature of the Nashorn engine. But
> it looks like some String-prototype methods are missing, yet the
> methods are somehow present when used in the right way.
>
> Minimal example: calling `startsWith` by using `call`:
>
> ```
> 1 $ jjs -v
> 2 jjs> String.prototype.startsWith.call('abc', 'ab')
> 3 <shell>:1 TypeError: Cannot read property "call" from undefined
> ```
>
> Expected behavior:
>
> Not a type error, for multiple reasons:
>
> 1. Other JavaScript engines do not throw a type error.
> 2. The equivalent code `"abc".startsWith("ab")` does not throw a type error.
>
>
> Further investigation:
>
> ```
> 1 $ jjs -v
> 2 nashorn 1.8.0_101
> 3 jjs> "abc".startsWith('ab')
> 4 true
> 5 jjs> "abc".startsWith
> 6 [jdk.internal.dynalink.beans.OverloadedDynamicMethod
> boolean java.lang.String.startsWith(String,int)
> boolean java.lang.String.startsWith(String)
> ]
> 7 jjs> "abc".startsWith.call("abc", "ab")
> 8 <shell>:1 TypeError: "abc".startsWith.call is not a function
> 9 jjs> typeof String.prototype.startsWith
> 10 undefined
> 11 jjs> String.prototype.split.call("abc", "b")
> 12 a,c
> ```
>
> Interpretation:
>
> It looks like `startsWith` is not present on the String-prototype, yet
> it is present on the String-primitives. Other String-prototype methods
> (`split`) are however present.
>
> Further notes:
>
> This also applies to `String.prototype.endsWith`.
>
>
> Related bug/feature: primitive values are not wrapped properly:
>
> ```
> 1 $ jjs -v
> 2 jjs> typeof Object("abc").startsWith
> 3 undefined
> ```
>
> -
>
> Esben
More information about the nashorn-dev
mailing list