Remove Globals from Nashorn - nashorn

Is there a way to remove access to globals in Nashorn short of
$ENV=undefined
?
I have done some searching, but I am unable to see anything other than how to use globals.
Also, is there a list of arguments/flags I can pass into the script engine? I am currently doing --no-java, but I cannot find a comprehensive list anywhere.
Any help is appreciated.

You can get a list of command-line options via jjs -help.
I don't know for sure about removing globals, but I doubt it. Nashorn uses a Global class that represents the ECMAScript global object, as described here.
The default context's ENGINE_SCOPE is a wrapped instance of ECMAScript "global" object - which is the "this" in top level script expressions. So, you can access ECMAScript top-level objects like "Object", "Math", "RegExp", "undefined" from this scope object. Nashorn Global scope object is represented by an internal implementation class called jdk.nashorn.internal.objects.Global.
That Global class has a bunch of the base ECMAScript plumbing baked into it in an immutable way, as without it javascript simply wouldn't work (no Object or Function prototypes, for instance). That page states that attempts to use an alternative object as the global will result in the engine placing your custom 'global' object into a new Global instance. Trying to run Javascript without that global plumbing simply wouldn't work.
Now if what you want to do is limit the Java classes available to a script, that's relatively straightforward (though not as straightforward as I wish it was).
ClassFilter filter = new ClassFilter() {
#Override
public boolean exposeToScripts(String name) {
// This would disable all Java classes
return false;
}
};
ScriptEngine engine = new NashornScriptEngineFactory().getScriptEngine(filter);
The main downside here is that the ClassFilter and getScriptEngine(ClassFilter) methods aren't part of the javax.scripting API, and you have to access the Nashorn-specific classes in the jdk.nashorn.api.scripting package directly.

Related

Inject a global variable into node context

Could i inject a global variable into node context, like "document" in html's script, which any javascript files could access this variable, and it isn't needed to import or require it?
//var document = require('document') // i don't need to require it by myself
document.findById('111')
To create a global in node.js, you assign to the global object.
// define global
global.myGlobal = 3;
// then use it anywhere
console.log(myGlobal);
Here's a good article on module-level variables and globals: Using global variables in node.js.
FYI, the node.js module architecture makes it so you do not need to use globals at all. You can simply require() in shared modules in order to share variables. If you're new to node.js, this may seem a bit odd and a bit inefficient, but you will get used to it and it is the preferred way to develop in node.js because it leads to modularity, testability and robust code.
Here's an interesting article on: Why global variables are bad.

Why is the usage of util.inherits() discouraged?

According to the Node.js documentation :
Note: usage of util.inherits() is discouraged. Please use the ES6 class and extends keywords to get language level inheritance support. Also note that the two styles are semantically incompatible.
https://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor
The reason why util.inherits is discouraged, is because changing the prototype of an object should be avoided, as most JavaScript engines look for optimisations assuming that the prototype will not change. When it does, this may lead to bad performance.
util.inherits relies on Object.setPrototypeOf to make this change, and the MDN documentation of that native method has this warning:
Warning: Changing the [[Prototype]] of an object is, by the nature of how modern JavaScript engines optimize property accesses, currently a very slow operation in every browser and JavaScript engine. In addition, the effects of altering inheritance are subtle and far-flung, and are not limited to the time spent in the Object.setPrototypeOf(...) statement, but may extend to any code that has access to any object whose [[Prototype]] has been altered.
Because this feature is a part of the language, it is still the burden on engine developers to implement that feature performantly (ideally). Until engine developers address this issue, if you are concerned about performance, you should avoid setting the [[Prototype]] of an object. Instead, create a new object with the desired [[Prototype]] using Object.create().
As the quote says, you should use the ES6 class and extends keywords to get language level inheritance support instead of utils.inherits and that's exactly the reason for which to use it is discouraged: there exist better alternatives that are part of the core language, that's all.
util.inherits comes from the time when those utils were not part of the language and it requires you a lot of boilerplate to define your own inheritance tools.
Nowadays the language offers a valid alternative and it doesn't make sense anymore to use the ones provided with the library itself. Of course, this is true as long as you use plan to use ES6 - otherwise ignore that note and continue to use utils.inherits.
To reply to your comment:
How is util.inherits() more complicated?
It's not a matter of being more or less complicated. To use a core language feature should be ever your preferred way over using a library specific alternative for obvious reasons.
util.inherits() got deprecated in the new version of node so need to use the ES6 class and extends keywords to get language level inheritance support instead of utils.inherits.
below example which I gave below helps you to understand more clearly :
"use strict";
class Person {
constructor(fName, lName) {
this.firstName = fName;
this.lastName = lName;
}
greet() {
console.log("in a class fn..", this.firstName, "+ ", this.lastName);
}
}
class PoliceMan extends Person {
constructor(burgler) {
super("basava", "sk");
this.burgler = burgler;
}
}
let policeObj = new PoliceMan();
policeObj.greet();
Output : in a class fn.. basava + sk
Here we can see Person class is inherited by PoliceMan class, so that PoliceMan obj can access the properties of Person class by calling super(); in a constructor
Hope this will work as util.inherits();
Happy Coding !!!

Groovy - Type Check Closure Code Before Execution

I have a Groovy script that lets the user define some dynamic properties and methods and later executes a user-defined closure. A script would look like this:
// init properties and methods dynamically at runtime
context.prop1 = "Some test value"
context.method1 = { String input ->
"exec " + input.toUpperCase()
}
// "this" is set to the context variable from above
run {
println method1( prop1 )
}
So in the beginning of the script, a context is initialized with user-defined properties (e.g. prop1) and methods (e.g. method1). The context is then used as this pointer in the run closure. I have achieved this by dynamically extending the meta class of the context and setting the context as delegate of the run closure (with DELEGATE_FIRST as resolves strategy).
Currently I am struggling at type checking. Before executing the run closure, I would like to check if method1 really expects prop1. I have looked into the DelegatesTo annotation, but that doesn't seem to work for dynamically extended objects. I have also played with the AST, but since my knowledge on that topic is limited, I haven't come up with a solution. If what I want to achieve is possible, any pointers in the right direction would be greatly appreciated.
You want to add a method to a context at runtime and then type check this before execution of that method.
Type checking is done at compile time. That is before anything of your program is executed. There is normally no chance this can ever check anything that will only happen at runtime, unless you have a way to statically declare it and give the compiler the power to do the check. But this means normally, you will have to do static compilation.
One way would be to use type checking extensions, but I think in your case that might be overkill. A more simple way would be to use extension modules. And the most simple way would be to use custom script base class.
But for any of these solution you will need static compilation to really have type checking, same for DelegatesTo (which is more used in combination with extension modules). For a type checked DSL a mix of type checking extensions and extension modules can work very well. But you will of course loose more dynamic features of the language and some simplicity.

What are the scopes and/or persistence of JavaScript Code Modules?

Experimenting with a bootstrapped extension, I'm trying to understand the scopes and/or persistence of jsm modules by setting a property, called baseUri, on a module object from bootstrap.js and reading it again from javascript in my options.xul (which is opened from the Add-ons Manager).
My current understanding is that JavaScript Code Modules are persisted, once loaded. However, when I try to access baseUri from options.xul, its value is undefined.
install.rdf:
<!-- just the relevant XML (this works as expected, by the way): -->
<em:optionsURL>chrome://test/content/options.xul</em:optionsURL>
/modules/Test.jsm:
var EXPORTED_SYMBOLS = [ 'Test' ];
Test = {
baseUri: undefined
}
/bootstrap.js:
// this is done in global scope,
// not inside install() or startup() for instance, if that matters
let test = Components.utils.import( 'file:///absolute/path/to/Test.jsm', {} ).Test;
test.baseUri = someBaseUriIExtracted;
/chrome/content/options.js (included in /chrome/content/options.xul):
let test = Components.utils.import( 'file:///absolute/path/to/Test.jsm', {} ).Test;
console.log( test.baseUri ); // undefined
So, I guess what I'm failing to fully understand is what the exact scopes are from which I should be able to access object properties from exported jsm symbols and/or how and when exactly these objects are persisted.
Does my problem have anything to do with sand-boxing, perhaps? Does Firefox consider options.xul, when opened from the Add-ons Manager, to be a different security scope than bootstrap.js, perhaps?
Can you shed a thorough light on the actual scopes of jsm modules and when and where I should be able to access persisted properties on jsm modules?
The documentation is pretty straightforward about what and how is shared
Each scope that imports a module receives a by-value copy of the
exported symbols in that module. Changes to the symbol's value will
not propagate to other scopes (though an object's properties will be
manipulated by reference).
I think the accompanying examples are clear.
Maybe you should use getters/setters.
From what I know:
Other jsm modules
Browser window
Content window
bootstrap addon scope

Global function in express.js?

How can I define a global function in express.js, that without require I can call it
"How" is simple enough:
global.fnName = function(){ return "hi"; }; // Andreas Hultgren's answer
But you don't need the global prefix; the thing about the global object is ...
fnName = function(){ return "hi"; }; // i.e. don't do: var name = function(){ ... };
console.log(fnName()); // this prints "hi"
console.log(global.fnName()); // this also prints "hi" - it was assigned to global.
"Without require" is a separate consideration: if you don't use require there is no guarantee your "globals" will have been declared by the time you need them. It enforces loading order of dependencies, among other things.
"Why am I" and "Is it correct to" are now hidden questions you should consider. It is accepted in javascript that Global Variables ...
... should be reserved for objects that have system-wide relevance and they should be named to avoid ambiguity and minimize the risk of naming collisions - Angus Croll, Namespacing in Javascript
i.e. global truly is Global: it is used by every author of every plugin or library you pull in to your application, not just you. Naming collisions between global variables break your application. This applies equally in node.js.
Global variables are also thought of as a code smell. In the detail sections below here you will see you can quickly get into trouble by using global variables, and they should really be treated as something that pushes you towards dependency injection and/or namespaces and modules.
Node.js and express - global vars and functions
Here's a good rule: if you upload it to a web server, or share it with other people, don't use global variables.
global is permissible in tiny "Saturday afternoon" apps in node.js with express.js, but tend to cause problems later if they get adopted into production. Therefore:
Modules and exports is best practice.
Injection should also be used to reduce coupling between javascript files. But in all cases you will usually need require to ensure they exist by the time you need them:
You should really consider app.locals data, and/or middleware functions, for anything that is view data related.
// call this as a function with an input object to merge
// the new properties with any existing ones in app.locals
app.locals.({
sayHello: function() { return "hi"; }
});
// now you can also use this in a template, like a jade template
=sayHello()
If you are creating global vars/functions for configuration settings purposes the below comments about namespaces still apply, and there are conventions emerging such as config.json files (still using require) for settings that are globally accessed.
Global variables - simple case
It is simple enough to declare a global variable in javascript, and for a function the process is no different. Simply omit the var keyword which would normally force a local scope on the declaration:
// app.js
blah = "boo";
sayHello = function(string toWho) { return "hello " + toWho; }
getVersion = function() { return "0.0.0.1"; }
// routes/main.js
console.log(blah); // logs: "boo"
console.log(global.blah); // logs: "boo"
console.log(sayHello("World")); // logs: "hello World"
console.log(global.sayHello("World")); // logs: "hello World"
console.log(getVersion()); // logs: "0.0.0.1"
But what if two separate plugins in your project use a global getVersion function - how do you get the right version number? Also, how do you ensure that getVersion exists before you need it, or exists at all?
Why do we need require?
To quote the nodejitsu docs the built in require function ...
... is the easiest way to include modules that exist in separate files. The basic functionality of require is that it reads a javascript file, executes the file, and then proceeds to return the exports object
"So", you may ask, "require just makes sure that a module from another file is included? Why bother?" It's better than that: you can make a whole folder a module, making your code easier to organise and test test test, it will recognise various extensions for file modules, not just .js, and it will look in various folders as well. Of course, it caches as well.
So, now that require has found your module, it ensures the code inside it is executed, and puts the objects your created into a "namespace":
// module file ./myModule.js
exports.blah = "boo";
exports.sayHello = function(string toWho) { return "hello " + toWho; }
// routes/main.js
var demoModuleReference = require('./myModule.js');
console.log(demoModuleReference.blah); // logs: "boo"
console.log(demoModuleReference.sayHello("World")); // logs: "hello World"
In that sample, demoModuleReference is an object that looks like:
{
blah: "foo",
sayHello: [Function]
}
Why modules and not global variables (a.k.a namespacing and "Global is the new private")?
Seems complicated now? Surely global variables are easier? requires ensures the following:
It ensures ordered loading of dependencies
It prevents variable name conflicts within global through the exports object.
This application at mankz.com (chrome or firefox only) is fascinating. Depending on how you use your js code, you are very likely to have variable name conflicts within the global scope. Name conflicts come from everywhere. In a browser, for instance, they can come from extensions. node.js is slightly different, but it is becoming more and more extended by compatible plugins as time goes on (you can load jquery in right now, for example). As the versions go on frameworks will get added, and name collisions in global will become more likely. My last run of that app in chrome showed over 1200 global namespace variables.
Namespaces - why?
This global namespace pollution was publicised early on by Douglas Crockford through Eric Miraglia in the article "A JavaScript Module Pattern". In summary:
All objects that need to be used between js files are really global
So, create a namespace object that will be unique
Assign the return value an anonymous function
Add private methods and variables inside that function
Do something useful with the pattern
Example:
ANDYBROWNSONICSUITE.BoomBox.SoundModule = function () {
var privateField = "can't touch this";
return {
play: function() {
console.log(privateField);
}
}
}
Why is this good?
Now you have only increased the global namespace members in the world by one, but this member contains as many items as you like.
Your application is far less likely to clash with other namespaces
It's a pattern, other frameworks expect you to use it to interact with them properly. In that reference, jQuery is a browser plugin, but you can use it with node and therefore your app, so the library interactivity policy statement is a perfect example.
It's a pattern, if we all follow it we our programs are all more likely to get along
When you read the Crockford reference along with the Croll reference (Direct Assignment section) I mentioned at the start, you see why it looks this complicated rather than just doing: sound.play = function() { ... } - ease of maintenance, refactoring the namespace etc. being just one reason.
Summary
In summary:
Can I create globals? Yes, it's simple, omit the var keyword before the declaration.
Should I create globals? You should use the module pattern, which is implicitly supported by node, and by express
Why am I creating globals? If it's for configuration, use a config namespace (e.g. How to store Node.js deployment settings/configuration files?)
You can:
global.name = function(){};
But you really should avoid using globals, even if it's possible to use them.

Resources