I can't reconcile the following with any of the JavaScript documentation I've read. Can somebody please shed some light?
The following snippet is taken from file panelUI.js in the Mozilla repository.
const PanelUI = {
/** Panel events that we listen for. **/
get kEvents() ["popupshowing", "popupshown", "popuphiding", "popuphidden"],
// more properties...
_addEventListeners: function() {
for (let event of this.kEvents) {
this.panel.addEventListener(event, this);
}
// more code...
},
// more properties...
Everything I've read about JS defines a getter as essentially a function (or "a method that gets the value of a specific property" and "The get syntax binds an object property to a function that will be called when that property is looked up"), so I'm a bit baffled to see an array literal where I would expect to find the body of function kEvents().
What does it mean in JS to have a function name followed by an array literal (in general or as part of a get definition)?
How would you write code that is functionally equivalent to the above, but does not use this somehow odd syntax?
I assume this is a consequence of SpiderMonkey's non-standard and deprecated support for expression closures.
this isn't valid JavaScript in any way... unless Firefox is allowing it as an alternative syntax for some reason.
but if you tried to run this or similar code in a browser like chrome, or even trying to compile it using Babel and ES6, it fails.
How would you write code that is functionally equivalent to the above, but does not use this somehow odd syntax?
An "equivalent" syntax appears to be to wrap the data in curly braces and return it:
get kEvents() {
return ["popupshowing", "popupshown", "popuphiding", "popuphidden"];
},
I would guess that the example code returns the same array instance every time, whereas my code is going to generate a new array every time it's called.
I imagine that the listed line is a non-standard syntax that mozilla has implemented but that is not associated with any current spec. Oftentimes with these sorts of features the browser development community pushes a browser to implement a new feature to see if it's worthwhile for standardization. It could have been a proposed syntax that was later dropped as well
That all said, this is speculative, as I've never seen a standard with that syntax in it.
Related
I use VS Code for JavaScript.
Definitions within a file work sometimes, but not others. Does anyone know why they fail?
In this example, VS Code finds the definition for edit easily. There is no occurrence of the word 'something' anywhere else in this file. Completely unique. So, why can't VS Code find its definition?
If I knew why, maybe I could change my code to work around it.
VS Code also can't find any references to these 'lost' properties. Which is very frustrating for tracking down where a function is called etc.
You should use this.
const edit = {
something: 5,
test() {
this.something;
},
};
You must not use an arrow function for test field, or this would point elsewhere but not the edit object.
EDIT: In TypeScript 4.3.5, the latest version of TS at the time of writing, TS is able to detect self-references in object literals, and both edit.something and this.something would work. For the case of working with JavaScript, upgrading VS Code should do the trick.
A TS playground link for reference.
There is a length limit. IntelliSense will define type :any if an object description is too long.
There is no way around this at all. The :any type will overwrite imported type definitions (e.g., a .d.ts file).
Two solutions:
Don't write long object declarations in your code.
Don't use VS Code or IntelliSense.
As for specifics:
The behavior is unpredictable.
If a type definition does not generate, reducing the object description length will not cause it to generate
Reducing an object description length to below the limit and re-launching VS Code will cause it to re-generate.
The length limit is unpredictable.
A function definition is 'longer' than a string, even if they have the same character count.
A nested ('deep') object declaration is longer than a shallow ('flat') object declaration, even if they have the same character count.
In short: IntelliSense breaks irreparably if you try to write long object declarations in a JS file.
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:
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
So the question is simply, if it's safe (wise) to declare method called "delete" in JavaScript. Example:
var request = {
delete : function (url) {
// Some code...
}
}
request.delete('http://page.dev/users/1');
I've tested this in Firefox and it's functional, but just wondering if it could cause problems in some other browsers; or in general if is it a good practice.
According to the language specification:
Identifier Names are tokens that are interpreted according to the grammar given in the “Identifiers” section of chapter 5 of the Unicode standard, with some small modifications. An Identifier is an IdentifierName that is not a ReservedWord (see 7.6.1).
This means you cannot use delete as a variable or function name, but you can use it as an object property name. This was not the case in the previous version of the specification, which is why most other answers are recommending you avoid using reserved words entirely. However, in ES5-compliant implementations, there should be no problem.
You'll never have an issue if you use this['style'], but with this.style, you should avoid reserved words, which does includes delete. According to the spec, it's actually OK to use reserved words as property names, but I would avoid it anyway because there are some bad implementations around (also it just has a generally bad feel to use reserved words, whatever the context).
No it's not a good idea because delete is a keyword. In the newest versions, they restricted the places where it will cause problems but there still are some.
One way of avoiding any kind of problem would be to use:
var request = {
"delete" : function (url) {
// Some code...
}
}
request["delete"]('http://page.dev/users/1');
But that's probably a bit less optimized and it's kind of ugly. I'd go with another name such as "remove".
delete is in the JavaScript reserved words list, use at your own peril.
delete object.property
delete object['property']
I'd use different keyword as other suggested - you can use synonyms like remove or purge - you get the idea.
But more important - make sure you're doing server-side validation for legibility of the call. Otherwise anybody could construct a delete call using "http://page.dev/users/1"
You should note that even using the bracket syntax for accessing properties isn't safe on all browsers.
Internet Explorer 7 and 8 will crash anyway.
Say I have this function:
function test(){
return a + b + 1;
}
How can I dynamically figure out that it will require globals a and b to be able to run? E.g. something like get_dependencies(test) returns ['a', 'b']
There's no built-in way to do that in standard JavaScript, if you're trying to do it with JavaScript itself.
On nearly all (but not all) JavaScript engines, you can get a form of the source of a function from the function object's toString function, e.g.:
var testSource = test.toString();
...and then of course you could parse that. This is non-standard behavior (the result of calling toString on a function is not defined in the specification), but it's widely-supported. You'd still have to do the parsing to find the symbols.
For the parsing, you have a couple of options. You could try to separate the parser portion of JSLint out of the rest of it, or alternately the terribly-named UglifyJS compressor has a full JavaScript parser which is already separate from the compressor part (see parse-js.js; apparently there's a tiny bit of NodeJS-specific stuff you might want to remove).
You can use a Javascript 'lint' tool that will test your code for common mistakes or oddities.
Some can be found online:
http://www.jslint.com/
http://www.javascriptlint.com/online_lint.php (can also be downloaded)
In your case, you might want to isolate individual functions via a regular expression for example, and submit them to such a tool.