How to define a global js function in Kotlin? - javascript

Every function and variable that I create in KotlinJs project gets into a module. But I need to define some functions in global scope.
I use p5js library (pure js). It allows user to define event handling functions in global scope. I'm trying to use KotlinJS in this project. But I don't know how to create global functions to handle p5js's events. All my Kotlin functions are inside of the module. And to call my Kotlin code I need to specif the full name mymodule.draw()
Currently I have to make an additional layer of pure JS code with global funcs that translate execution to kotlin functions which looks like this:
function setup() {
mymodule.setup();
}
function draw() {
mymodule.draw();
}
The problem with this approach is a lot of boilerplate and repetitive code.

In case this will be useful for somebody I will leave another workaround here:
import kotlin.browser.window
fun main() {
window.asDynamic()["setup"] = ::setup
window.asDynamic()["draw"] = ::draw
}
fun setup() {}
fun draw() {}
What it actually does, it creates functions in kotlin module as usual and then assigns them to window object, which makes it global.
This solution is still not ideal, cause it needs a manual assignment for every function. At least it does it right in Kotlin project, no need to maintain a separate pure js file.
Maybe it is possible to create an annotation and leverage kotlin reflection(no idea how it's supported in KotlinJS).
Although this solution works for me, I would like to have some out of the box solution like they do for #JsNonModule external functions.

Adding on top of #Sergey's Answer, one can also use this work around when dealing with libs like p5.js
fun main() {
window.asDynamic().setup = {
// your setup code here
}
window.asDynamic().draw = {
// your draw code here
}
}
This approach minimizes the definition and the declaration of the two functions (looking at you C Language). Thanks

Unfortunately there is no way to define global function in Kotlin/JS. It is possible to use Plain module type where you have global symbols in module object which is defined in global scope.
// module M
fun foo() {}
which is accessible via M.foo

Related

Using 'export' keyword solely for importing into Unit Tests

I'm using Meteor and am writing unit tests for a Collection. I've got Helper methods for the collection in addition to just regular JS functions.
I.e.
Collection.helpers({
helperFn: function () {
return 'foo';
}
});
//And in the same file
function bar() {
return "bar";
}
Then in my tests file I have something like
import { Collection } from '../collections'
//Use Factory or Stub to create test Document
//This then works just fine and I can assert, etc..
testDoc.helperFn
My question is with wanting to test just the regular 'bar' JS function. This isn't a big deal using ES6 classes because then I can just export the whole class and call any function with an instance of it. But with Meteor I'm finding the only way I can access the function is by using the 'export' keyword.
So in my Collection file
export function bar ({ return bar; });
And now in my test file I'd do something like
import { bar } from '../collection'
I'd rather not add an export statement for every time I test a new function. Is there any way around this or is it not a big deal?
I do think that the export/import is the way to go, but to answer the first part of your question: yes, you can fall back to the original scoping of meteor and put these functions in the global scope of meteor as follows:
do not put your files in the imports/ folder, but into another folder in your project, e.g., server/.
defined the functions as:
bar = function() { /* function body */ }
These variables are interpreted by meteor as being global to the project, and hence do not need to be imported before use.
That said, there was a reason meteor introduced the imports/ folder and corresponding export/import paradigm in version 1.3. It avoids polluting the global scope and makes it much easier to see where things are defined.

Accessing variables and methods from another file

In this case, How do I access the variable and method declared in a file from another file?
File one
jQuery(function(t) {
var myVar = 'myValue',
e = function(t) {
console.log('myLog');
}
});
File two
jQuery(function($){
// ????
});
You don't. It has nothing to do with files (JavaScript largely doesn't care about files unless they're ES2015+ modules), it has to do with the fact that both myVar and e are entirely private to the anonymous function you're passing into jQuery in the first code block. Even other code outside that function in the same file would be unable to access them.
You'd have to change the first file to make that information accessible outside that function. You could do that by making them globals (blech), or by having a single global you use for all of your things like this with an object with properties for these things (slightly less "blech" :-) ), or by using something like Webpack and true modules.
It really depends on how you setup your scripts. For instance:
<script src="fileOne.js"></script>
<script src="fileTwo.js"></script>
Then you will be able to do the following:
File One:
- Declare variable x
File Two:
- Access variable x
I recommend taking a look at this, it'll help with understanding variable scope (however this doesn't cover ES6's let): https://www.w3schools.com/js/js_scope.asp

The way to use custom method everywhere without requiring the module everywhere

I am using Node.js. I defined a custom method to the String obj like this:
if (!String.prototype.myMethod) {
String.prototype.myMethod= function () {
//do something
return this;
};
}
I found that myMethod maybe used in many different files, so that I have to require the file where this piece of code in. Is there any way that does the many 'requires' ?
Don't do that.
Node is intentionally designed in a module pattern, where each module gets it's own scope to run in and without polluting the global variables. This very intentional and very important.
https://nodejs.org/api/modules.html#modules_the_module_wrapper

jQuery namespace declaration and modular approach

I have confusion on how to proceed with my project.
I am developing an enterprise app in which lots of modules are to be written.
Most of module will be using lots of jQuery plugins to create complex grids, draw graphs for different purposes which means modules will be appending divs, tables etc a lot to DOM.
I want to preserver namespace since this will be large app.
For that I came across prototype method and self-executing anonymous function.
self-executing anonymous function seems to be recommended a lot.
My questions are
Are self executing functions reusable ?I mean these are immediately executed so lets say a module draws a complex grid for a given JSON file. So will I be able to use same self-executing anonymous function for 3 different JSON files just like a jQuery plugin ?
when there will be lots of modules written , they will all self execute on start-up. Will it effect Ram/Processor usage? Shouldn't it be way that modules should be called when needed ? what significance will self execution do ?
My Project Scope:
Kindly help me understand this self executing thing in my project scope, which is My project Holds a main namespace say "Myapp" and and its modules like Myapp.moduleA, Myapp.moduleB.MyApp will trigger its modules on click etc.
What is best way to go for me ?
Self-Executing Anonymous Func
(function( skillet, $, undefined ) {
//Private Property
var isHot = true;
//Public Property
skillet.somevar = "Bacon Strips";
//Public Method
skillet.draw = function() {
//Draw a grid
};
//Private Method
function _grid( ) {
//
}
}
}( window.skillet = window.skillet || {}, jQuery ));
You cannot reuse a self executing function, it just executes immediately and that's it.
If you need to execute it multiple times, you should just declare a function.
A possible approach is this:
var MYNAMESPACE.Object = (function(){
// private methods
var somemethod = function(){};
// public methods
return {
somepublicmethod: function(){}
};
})();
Now you can call it like this:
MYNAMESPACE.Object.somepublicmethod();
As for executing upon startup. Provided you only create methods and don't DO anything immediately inside your declaration, it won't affect performance too much unless you have a really big amount of modules. If that's the case, you should probably look into the asynchronous module loader pattern (AMD). RequireJS is a good example of that: http://requirejs.org
I wrote an article about JS namespaces which could be interesting for you:
http://www.kenneth-truyers.net/2013/04/27/javascript-namespaces-and-modules/

Namespace import in node.js

I've got some function that allows to merge namespace, very similar to import when the module contains lot's of function (I expose an API with dozens of combinators)
It generates lots of var f = target.f; for every item from the export
function getNamespace(name, exports){
var output='';
for(var item in exports){
output += 'var ' + item + ' = '+name+ '.'+item + ';';
}
return output;
}
and usage:
var paco = require('./paco.js');
eval(paco.getNamespace('paco', paco));
// instead of paco.between(paco.start(),paco.content(),paco.end())
between(start(), content(), end())
Question:
I there a way to 'hide' the eval into the some function ? I don't want neither to mutate global namespace nor to call vm.runInThisContext, just need to add some local variables into the calling context after call function similar to require.
I mean I need something like
import('./paco');
// this should work like this
// var paco = require('./paco.js');
// var between = paco.between;
but without mutation of global and without eval in the calling scope.
tl;dr: No.
In order to understand why this is impossible, it's important to understand what Node is doing behind the scenes.
Let's say we define a function in test.js:
function foo() {
var msg = 'Hello world';
console.log(msg);
}
In traditional browser JavaScript, simply putting that function declaration in a file and pulling the file in with a <script> tag would cause foo to be declared in the global scope.
Node does things differently when you require() a file.
First, it determines exactly which file should be loaded based on a somewhat complex set of rules.
Assuming that the file is JS text (not a compiled C++ addon), Node's module loader calls fs.readFileSync to get the contents of the file.
The source text is wrapped in an anonymous function. test.js will end up actually looking like this:
(function (exports, require, module, __filename, __dirname) {
function foo() {
var msg = 'Hello world';
console.log(msg);
}
});
This should look familiar to anyone who has ever wrapped their own code in an anonymous function expression to keep variables from leaking into global scope in a browser. It should also start making sense how "magic" variables in Node work.
The module loader evals1 the source text from step 3 and then invokes the resulting anonymous function, passing in a fresh exports object. (See Module#_compile.)
1 - Really vm.runInThisContext, which is like eval except it does not have access to the caller's scope
After the anonymous wrapper function returns, the value of module.exports is cached internally and then returned by require. (Subsequent calls to require() return the cached value.)
As we can see, Node implements "modules" by simply wrapping a file's source code in an anonymous function. Thus, it is impossible to "import" functions into a module because JavaScript does not provide direct access to the execution context of a function – that is, the collection of a function's local variables.
In other words, there is no way for us to loop over the local variables of a function, nor is there a way for us to create local variables with arbitrary names like we can with properties of an object.
For example, with objects we can do things like:
var obj = { key: 'value' };
for (var k in obj) ...
obj[propertyNameDeterminedAtRuntime] = someValue;
But there is no object representing the local variables of a function, which would be necessary for us to copy the properties of an object (like the exports of a module) into the local scope of a function.
What you've done is generate code inside the current scope using eval. The generated code declares local variables using the var keyword, which is then injected into the scope where eval was called from.
There is no way to move the eval call out of your module because doing so would cause the injected code to be inserted into a different scope. Remember that JavaScript has static scope, so you're only able to access the scopes lexically containing your function.
The other workaround is to use with, but you should avoid with.
with (require('./paco.js')) {
between(start(), content(), end())
}
with should not be used for two reasons:
It absolutely kills performance because V8 cannot perform name lookup optimizations.
It is deprecated, and is forbidden in strict mode.
To be honest, I'd recommend that rather than doing something tricky with eval, do your future maintainers a favor and just follow the standard practice of assigning a module's exports to a local variable.
If you're typing it that often, make it a single-character name (or use a better editor).
According to this answer Global variables for node.js standard modules? there is global object the same as in browser there is window. So you can add key to that object
function getNamespace(exports) {
for(var item in exports){
global[item] = exports[item];
}
}
and use it as:
paco.getNamespace(paco);
no need for eval at all.
No. It's not possible to modify the local scope from an external module. Reason being, when eval is called in the external module, its context will be the external module, not the scope requiring the module.
In addition, vm.runInThisContext does not have access to the local scope, so that wont help you either.

Categories

Resources