[graalvm-users] Javascript Questions

Christian Wirth christian.wirth at oracle.com
Tue Oct 5 02:22:02 PDT 2021


Hi Steve,

to your first question: the `Value value` you expect returned here is the result of the `var` statement in JavaScript. That statement, by definition, does not return anything (in ECMASCript semantics: it returns `NormalCompletion(Empty)` ). You would be able to access the value if you changed the code to `var w = 5; w;` as the second statement would return `w`’s value.

What you actually want to do is to access the global scope, where the variable (`w` in your case) is stored and available. For this, you can access the bindings of the global object (the variable `jBindings` thus represents the global object):

Context.eval("js", "var w = 5; ");
Value jsBindings = context.getBindings("js")
jsBindings.getMember("w").asInt() == 5;

See https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/Context.html as you might need additional methods of `Value`, like `isNumber` etc.

You could also return an object explicitly, and again use Value’s methods to access the content, e.g.

Value valueO = Context.eval("js", " var o = {foo:42, bar:'test'}; o;");
System.out.println(valueO.getMember("bar").asString());


For your second question, yes, the origin language an object is coming from is something you need to consider. With our Polyglot Interop protocol, you can access objects from different languages as if they were defined in your guest language (meaning: you can do things like `var x = window.w; windows.newVar = 42;` in JavaScript, when `window` actually is a host object defined in Java). However, while this is valid JavaScript syntax, the object’s origin language might reject some operations – you suspect correctly that Java won’t be able to create a `newVar` field if it was not already there in the first place. You will get a similar error message and behavior as if `window` was a frozen JavaScript object, where you can’t define new properties either. A similarly problematic case is that Java arrays can’t grow and thus you cannot access them out-of-bounds, as you can do in JavaScript by default.

To work around this, you can use a `org.graalvm.polyglot.proxy.ProxyObject` on the Java side. Instead of using a POJO to define `window`, you create a Proxy, which allows you to react to property to such cases (and e.g. store the new field in a Map) – see the getMember, hasMember and putMember methods in ProxyObject.

https://www.graalvm.org/truffle/javadoc/org/graalvm/polyglot/proxy/ProxyObject.html

In your nightmare case, you will just have to next those Proxies; you might also need ProxyArray and ProxyExecutable (for the lambda).

Best,
Christian



From: graalvm-users-bounces at oss.oracle.com <graalvm-users-bounces at oss.oracle.com> On Behalf Of Steve Brenneis
Sent: Montag, 4. Oktober 2021 05:49
To: graalvm-users at oss.oracle.com
Subject: [graalvm-users] Javascript Questions

Hello.

I have a project to analyze how scripts on web pages interact with the browser window and document objects. I can only analyze them. I can't modify them. Most things are fairly obvious, but I have come up against a couple of items that I can't find answers for anywhere. If there is documentation that I have missed, I would be eternally grateful if someone could point me in the right direction. The project will be written in Java.

Given this evaluation:

Value value = context.eval("js", "var w = 5;");

value will be of type undefined and value.hasMembers will return false;
Is there any way to bring the value of w back to Java?

This leads into the second question.

In a browser, the window object is actually a pseudonym for the global scope. Therefore

var w = 5;

can be functionally equivalent to

window.w = 5;

How does the javascript polyglot line things up between a weakly typed language like javascript and a strongly typed one like Java?

I can define a Window class in Java and give it a member variable w

class Window {
    public int w;
}

But then, because this is perfectly valid javascipt

window.w = 'hello';

w obviously can't be typed as an integer.

And how would I handle this case?

window.x = {
     number: 4,
    letter: '6',
    string: "hello",
    method: (() => a = b)
}

I could define x of type Object, but I would have no idea how to access the members. And obviously if I don't know what variables will be created beforehand, I can't declare them.

I have also run into nightmares like this

if (window.z === undefined) {
    window.z = [];
    window.z.a = { variableOne: "something", variableTwo: "something else"};
    window.z.push({variableThree: "another thing", variableFour: "yet another thing"});
}

There may be (I hope) a simple solution and I just haven't been able to find it. Any help is appreciated.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://oss.oracle.com/pipermail/graalvm-users/attachments/20211005/70d19224/attachment-0001.html 


More information about the GraalVM-Users mailing list