Consider we have the following JS code:
async function helloAsync(){
return "Hello";
}
function hello(){
return "Hello";
}
In Java, you can load this code into a GraalVM context object using:
context.eval("js", mappingTemplate);
Giving us two members that we can evaluate using:
Value bindings = context.getBindings("js");
final Value executionResult1 = bindings.getMember("hello")
.execute();
final Value executionResult2 = bindings.getMember("helloAsync")
.execute();
As a result, the executionResult2 would be a promise that can be completed within Java. My question is how I can reliably tell that executionResult2 is in fact a promise, and not just a string like executionResult1. Currently, a naive and unreliable approach could be:
if (executionResult.toString().startsWith("Promise") &&
executionResult.hasMember("then") && executionResult.hasMember("catch"))
What are more reliable/elegant ways of recognizing a promise returned from JS?
Can you try to inspect the content via this value.getMetaObject().
The doc say:
Returns the metaobject that is associated with this value or null if
no metaobject is available. The metaobject represents a description of
the object, reveals it's kind and it's features. Some information that
a metaobject might define includes the base object's type, interface,
class, methods, attributes, etc.
Could be useful for your case.
Yes, value.getMetaObject() is the way to go: it returns the JS constructor associated with the value instance, which should be Promise in your case.
Related
I'm learning how one can achieve OOP patterns in JavaScript. I'd like to know, which one is a correct way to assign a DOM element to a object literal member in pure JavaScript and what are the differences between those examples.
I am doing this so that I could reuse that DOM element in object literal functions and if I change any id, name or class names, I only have to update in one place.
MyObject = {
// Version 1
member: document.getElementByName('elementName'),
// Version 2
member2: function() {
return document.getElementByName('elementName');
},
// Version 3
member3: function() {
document.getElementByName('elementName');
}
};
MyObject2 = {
// Is this member in a different namespace
member: document.getElementByName('element2Name'),
};
// Is this member in a different namespace
member: document.getElementByName('element2Name'),
MyObject2.member and MyObject1.member are different. Javascript doesn't natively support namespace like in other languages but the same can be achieved using the Object literals.
Regarding the 3 different versions for the member assignment, the deciding factor is what kind of access do you need for your variable and how you want to consume that.
// Version 1
member: document.getElementsByName('elementName'),
This assigns the member property the result of the method getElementsByName, The result is a NodeList Collection. To access the property member you need to write it like MyObject.member.
// Version 2
member2: function() {
return document.getElementByName('elementName');
},
The member2 is a function, whereas member wasn't a function and hence how the invocation is done is different. In this case you can get the same result as the version1 by calling MyObject.member2().
// Version 3
member3: function() {
document.getElementByName('elementName');
}
Version 3 doesn't return anything and is useless if you need to consume the result. Basically, this version never stores the result of the function call document.getElementByName('elementName'); and hence the return value is undefined. Like member2, member3 is also a function. But, invoking the function MyObject.member3() returns undefined.
Which version to choose
version 3 is useless as it doesn't return anything.
I do not have enough information of your application to suggest you best match. Based on limited information available, I would prefer version 2 because of the following reasons
Since the value of the result which is defined by document.getElementByName('elementName'); changes and is dependent on DOM. So, i will go ahead with the member2 or version2. i generally prefer function whenever it's not simple and involve some computation. Also, the result of the function call gives the caller information that the result of function call can change. Properties are good when you can define simple data attribute.
Note: A property's value can be a function, in which case the property is known as a method.
Often, we are presented with an array (IEnumerable) property that specific values need to be extracted. in c# we can do something similar to:
public AssetModel PromoImage {
get
{
return Assets.FirstOrDefault(x => x.AssetTypeCd == "promoimage");
}
private set { }
}
Is there a way to easily to this within Angular 2?
Lodash provides similar functionality to LINQ for JavaScript programs (and then some), though not deferred execution -- LINQ queries are deferred until they are enumerated, while lodash (usually) performs the query immediately and returns an array/object of results. (Though in this case LINQ wouldn't even defer it since FirstOrDefault returns a scalar and not a queryable/enumerable.)
In your case, you would do something like this:
let obj = {
get promoImage() {
return _.find(assets, a => a.assetTypeCd === 'promoimage');
},
// ...
};
Then accessing obj.promoImage will execute the function to obtain the attribute's value.
(Here I assume this is where we are creating the new object, and assets is the assets list in the lexical scope of the constructor function. You can change it to reference this if you are storing data on the object itself and not in constructor upvalues.)
Notes:
Lodash does not depend on Angular at all.
ES6 provides a find() method on the Array prototype, so this feature will be built-in to browsers once ES6 is adopted. Sadly, IE is (as usual) the outlier without any support for it. However, Lodash is still a very useful library to have in your toolkit, and note that Lodash's find() works on objects too, not just arrays.
For example I loaded a script on some website, and I would like to know if JSON.parse/stringify wasn't monkey patched.
I noticed that if I use toString on the function in Chrome/FF, JSON.stringify.toString, then I get back:
function stringify() {
[native code]
}
My question is do you think this is a good way to verify if a function was monkey patched? Also would love to hear of any other approaches to this problem.
One could easily fake JSON.stringify.toString
JSON.stringify = function() {}
JSON.stringify.toString = function() {return 'ha-ha'}
console.log(JSON.stringify); //ha-ha
A little more robust way would be to use Function.prototype.toString
Function.prototype.toString.call(JSON.stringify)
But really bad monkeypatcher could patch Function.prototype.toString as well :)
Yes, this is the only practical way to check whether or not a native function had been overridden or not.
const isNative = fn => !!fn.toString().match(/\[native code\]/)
console.log(isNative(JSON.stringify));
A more robust solution could use Function.prototype.toString() instead of direct call of fn.toString(), but both are monkeypatchable as well. The joys of JavaScript :)
The spec ( http://www.ecma-international.org/ecma-262/7.0/index.html#sec-function.prototype.tostring ) does not specify the exact string returned for a builtin function :
19.2.3.5 Function.prototype.toString
When the toString method is called on an object func, the following
steps are taken:
If func is a Bound Function exotic object, then Return an
implementation-dependent String source code representation of func.
The representation must conform to the rules below. It is
implementation dependent whether the representation includes bound
function information or information about the target function. If
Type(func) is Object and is either a built-in function object or has
an [[ECMAScriptCode]] internal slot, then Return an
implementation-dependent String source code representation of func.
The representation must conform to the rules below. Throw a TypeError
exception. toString Representation Requirements:
The string representation must have the syntax of a
FunctionDeclaration, FunctionExpression, GeneratorDeclaration,
GeneratorExpression, ClassDeclaration, ClassExpression, ArrowFunction,
MethodDefinition, or GeneratorMethod depending upon the actual
characteristics of the object. The use and placement of white space,
line terminators, and semicolons within the representation String is
implementation-dependent. If the object was defined using ECMAScript
code and the returned string representation is not in the form of a
MethodDefinition or GeneratorMethod then the representation must be
such that if the string is evaluated, using eval in a lexical context
that is equivalent to the lexical context used to create the original
object, it will result in a new functionally equivalent object. In
that case the returned source code must not mention freely any
variables that were not mentioned freely by the original function's
source code, even if these “extra” names were originally in scope. If
the implementation cannot produce a source code string that meets
these criteria then it must return a string for which eval will throw
a SyntaxError exception.
So checking for [Native Code] may or may not work depending on the interpreter. Furthermore, an implementation could well implement builtin functions as normal javascript code.
So in answer to your question, you cannot determine, is a Javascript specified way whether a builtin function has been monkey-patched.
That said it appears that Chrome and Firefox both return the [Native Code] string subject to verification on other implementations that may be a pragmatic solution.
I just wanted to add that, after ES6, all solutions that involve checking "[native code]" are even less reliable because of ES6 proxy traps.
// Example monkey-patching the Fetch API using an ES6 proxy trap
window.fetch = new Proxy(window.fetch, {
apply(fetch, that, args) {
const result = fetch.apply(that, args);
result.then((response) => {
console.log("Intercepted!", args, response);
});
return result;
}
});
// True
console.log(window.fetch.toString().includes("[native code]"));
// True
console.log(Function.prototype.toString.call(window.fetch).includes("[native code]"));
For more info, check this answer.
I tried to develop some of the ideas from other replies into a working script - here it is:
https://gist.github.com/mindplay-dk/767a5313b0052d6daf2b135fdecd775f
Paste it into the Chrome (or Edge) console and press ENTER - it'll print out a list of any constructors and class-methods not matching their native counterparts. (It does this by comparing against the native APIs in an iframe - which it creates via document.createElement, so, technically, it's possible to fool it by overriding that method, if you were intending to do so deliberately; this isn't a security tool.)
Note that this currently gives false positives for window.location, window.fetch and window.length - this appears to be because these properties aren't correctly reflected by their native browser implementations? If you know how to fix it, please post a comment.
Here is example output from a site that was incorrectly loading some IE11 polyfills into Chrome:
Is it acceptable to add an attribute or value to a JavaScript function?
Example:
var f = 1;
function foo (param) {
f++;
}
var fooFunc = foo;
fooFunc.dummy = f;
console.log('fooFunc: ' + fooFunc);
console.log('fooFunc.dummy: ' + fooFunc.dummy);
The above example creates a function (foo), then assigns it to a new variable (fooFunc) and then adds a dummy attribute to fooFunc.
When run, this example prints the text of the function first, and then it prints the expected value (1 in this case). When printing the function, it doesn't show any indication of the dummy value:
fooFunc: function foo(param) {
f++;
}
fooFunc.dummy: 1
JsFiddle here - open the browser's JavaScript console to see the log messages: http://jsfiddle.net/nwinkler/BwvLf/
Why does this work? And where is the dummy attribute stored, and why isn't it printed when I log the function?
Lastly, even if this works, is it a good idea (or an acceptable practice) to use this? I don't want to start an open ended discussion on this, but rather see if there's documented uses of this, or people discouraging this in JavaScript coding guidelines.
Everything except primitives ( null, undefined, number, string, boolean ) in JavaScript are objects. So functions are basically objects.
Objects in JavaScript can have properties and methods, hence functions too.
all functions inherit from Function.prototype and has certain properties ( name, length ) and methods ( .call, .apply ) coming through this chain.
It is sometimes very useful to keep properties attached to the function itself, like cache information, number of invocations etc. There is nothing wrong out in using it this way.
More details : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function
Let's have a look at ECMAScript documentation (Which is the standard JavaScript is based on). Here's the 3rd. version of it:
http://www.ecma-international.org/publications/files/ECMA-ST-ARCH/ECMA-262,%203rd%20edition,%20December%201999.pdf
Go to chapter 15, Native ECMAScript Objects.
15.3 > Function objects.
There's a lot of interesting information there concerning your question, but the first thing worth noticing is that function is an object.
As an object, it has attributes (predefined and that you can assign yourself).
For example, try:
console.log('fooFunc.name: ' + fooFunc.name);
It should display "foo" in your case.
Since it's documented quite well, you can use it as a standard way, though it is not so well-spread and may seem a bit unusual.
Hope this helps.
It is normal object behavior, whether "acceptable" or not.
By using the function keyword you are actually calling the native predefined Function() constructor. Like any object constructor it returns an object after building it. Like any object, the returned object can have properties, including other functions as method properties.
var adder = function(a, b){return a+b};
adder.subtracter = function(a, b){return a-b};
console.log(adder(1,2)); // 3
console.log(adder.subtracter(1,2)); // -1
TIP: if you want to see the adder object and its subtracter method, switch to DOM view from Console view after running the above code in console and then search for "adder". You'll see the object there, and then you can collapse to see what it's made from, including a subtracter object.
Of course, a function object is a special native object, which makes it possible to make calls like this: adder() and actually run some code. The fact that a function object is harder to inspect for custom attached properties, combined with its native special object treats (read built-in restrictive behavior), should give you a hint that, while it's possible, attaching custom properties is not the intended nor a good use of a function object.
Consider the code:
Example 1
var Executors = java.util.concurrent.Executors;
var executor = Executors.newCachedThreadPool();
var fork = function (callable) {
// Clarify Runnable versus Callable overloaded methods
executor['submit(java.util.concurrent.Callable)'](callable);
};
fork(function(){ ... }); //ok
This works.
But this does not work:
Example 2
var Executors = java.util.concurrent.Executors;
var executor = Executors.newCachedThreadPool();
var fork = executor['submit(java.util.concurrent.Callable)'];
fork(function(){ ... }); //fails, NullPointerException
I assume, it is because fork here is not a JS Function instance, it is actually an instance of jdk.internal.dynalink.beans.SimpleDynamicMethod
I tried to use fork.apply(executor,function() { ... }); but natrually, SimpleDynamicMethod has no apply.
Why is it, actually, that Example 2 does not work, while Example 1 does?
Is it simply a perk of Nashorn? It there a better way to define fork() function than in Example 1?
Update
In example 2,
print(typeof fork); reports function
print(fork) reports [jdk.internal.dynalink.beans.SimpleDynamicMethod Future java.util.concurrent.AbstractExecutorService.submit(Callable)]
and exception is (with line 13 reading fork(function() {)
Exception in thread "main" java.lang.NullPointerException
at jdk.nashorn.internal.scripts.Script$\^eval\_._L5(<eval>:13)
at jdk.nashorn.internal.scripts.Script$\^eval\_.runScript(<eval>:5)
at jdk.nashorn.internal.runtime.ScriptFunctionData.invoke(ScriptFunctionData.java:527)
Unfortunately, currently you can't use bind, apply, and call with POJO methods. I'd like to add that as a future enhancement. The best you can currently do in your above example is:
executor['submit(Callable)'](function() { ... })
Note that while in general indexed access to a property (using the [] operator) is less efficient than property name access (using the . operator), Nashorn recognizes indexed access with a string literal and treats it just as efficiently as a property name access, so you don't suffer a slowdown here, just a bit of visual noise. In the case above, it will actually end up getting linked to the executor's virtual method directly.
Speaking of visual noise, you don't have to fully qualify java.util.concurrent.Callable. When the non-qualified name of the parameter type is sufficient to disambiguate the overloads (which is pretty much always), you can just use the non-qualified name, regardless of what package it is in (works for your own classes too).
The problem is that you are missing the receiver 'executor' from the call. In general, 'fetching' Java functions is only practical with static Java functions. For example:
jjs> var abs = java.lang.Math.abs;
jjs> abs(-10);
10
In your example, we could have bound fork to executor and make it equivalently static. This support is currently not present. We should probably have support for adding the receiver as the first argument if 'fetched' from a class. Will file an enhancement request for a future release.
Alex,
In example 1, var fork is a function that returns array executor. In example 2, var fork is an array. That is why you cant use () and apply.
Does fork[0](function(){...}) work for you ?
Thanks