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 <es...@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

Reply via email to