Call minified browser javascript in node - javascript

I have an enormous minified javascript file (with no browser specific calls) but several functions that I need to use. Is there a systematic way to convert such a file so that it is callable in node? The js is wrapped in a self executing anonymous function. The function ends with .call(this)

The very least you would need to do is export something from that file, so you could load it as a module and consume it from your other Node code.
exports.myThing = somethingFromMyFile;

As per your description, I am assuming that the file is of the format
(function () {
// file contents
this.someFunction = function() {
// function contents
}
}).call(this);
When executed in the browser window object gets passed as this and all the properties like someFunction are attached to window.
To use it as a module in node, you could bind the function to an empty object and export that object. For example,
var obj = {};
(function () {
// file contents
this.someFunction = function() {
// function contents
}
}).call(obj);
module.exports = obj;
Then use it like
var mymodule= require('./mymodule');
mymodule.someFunction();

Related

How to reference the calling Javascript module?

I am using what I understand to be the Javascript module pattern, and jQuery.
I have an app which has a public and an admin side. Each has its own JS file, though some functionality is shared so I have extracted it to a common file. Gulp combines the common + public files into a single file for use on the public side, and the common + admin files into a single file for use on the admin side.
The public JS file includes something like:
var PublicFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The HTML page where this code is needed fires it off like so:
<script>
PublicFoo.init();
</script>
The admin JS file includes something very similar, also defining a bar() function, and calling the same Common module function.
var AdminFoo = (function () {
var bar = function() {
// ..
};
var init = function() {
$button.on('click', Common.someCommonThing);
};
return {
init: init
};
})();
The common JS file (shared and combined with both public and admin JS) includes something like:
var Common = (function () {
var someCommonThing = function() {
// Do stuff.
// When done, I want to call bar() in the calling module.
// This does not work, throws 'Uncaught ReferenceError: bar is not defined'
bar();
};
return {
someCommonThing: someCommonThing,
// ...
};
})();
From the Common module, how can I reference a function in the calling module?
I know about .caller, but apparently that is non-standard and should not be used.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it, but that seems ugly:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing(PublicFoo)
});
};
// In Common
var someCommonThing = function(callingModule) {
// ...
callingModule.bar();
I could also of course extract the bar() call out and do it back in the calling module, but that doesn't seem so neat either:
// In PublicFoo
var init = function() {
$button.on('click', function() {
Common.someCommonThing();
bar();
});
};
// ... and the same thing in AdminFoo
I feel like this must be JS modules 101, a basic requirement, and yet I can't seem to find anything about it, though I may be searching using the wrong terminology. Or is the reason I can't find how to do this because it should not be done this way?
How can I reference the appropriate bar() from the Common module?
I know about .caller, but apparently that is non-standard and should not be used.
Also it doesn't work in your case, as the caller is the event handler and neither PublicFoo nor AdminFoo.
I could maybe somehow pass in the name of the calling module as a parameter to Common, and reference it
Yes, passing references to the thing that you want to be called is the way to go if you want someCommonThing to do different things after it has finished. Notice you really should only use such a callback when the thing is asynchronous, otherwise just returning and calling bar afterwards (like in your last snippet) is much easier.
How can I reference the appropriate bar() from the Common module?
If both bars might be loaded at once into the page, then there's no way around a parameter that references the callback.
However, that doesn't seem to be the case in your example - on one page, AdminFoo takes the role of Foo and on the other page PublicFoo takes the role of Foo.
So just reference only Foo.bar from Common! Let the respective pages fill it with the appropriate value, i.e.
var Foo = AdminFoo
on the admin page and
var Foo = PublicFoo
on the public page.
Passing functions to other functions is very common and perfectly idiomatic JavaScript, so you could do it like this:
// In PublicFoo
var bar = function() {
// ..
};
var init = function() {
$button.on('click', function() {
Common.someCommonThing(bar)
});
};
// In Common
var someCommonThing = function(bar) {
// ...
bar();
};

Is it possible to pass namespace as parameter in javascript function?

I have 3 .js files. The main Home.js and two other .js files, for instance Page1.js, Page2.js
Home.js:
var Home= {
Sample: function (pageId,data) {
pageId.MergePageData(data);
}
}
Page1.js:
var Page1 = {
MergePageData: function (data) {
// do something
}
}
Page2.js:
var Page2 = {
MergePageData: function (data) {
// do something
}
}
I tried calling like this by passing it as a string:
Home.Sample('Page1', 'data');
Home.Sample('Page2', 'data');
But I guess as it is being passed as a string am getting an error
"Object doesn't support property or method 'MergePageData' "
I need to differentiate the call between the two functions in two different js files. How to achieve that?
The pageId in your function is just a variable, and when you call it you specify the type of this variable, and as you pass "Page1", which is a String it is just a string without having anything to do with your real Page1 object. but there are some options that can help you out.
The Other point that you have to consider is, it doesn't matter you have 2 or 3 different js files. the important point is if all your javascript codes are injected to single html page, then you can have all your code in all the JavaScript files in single window context. So if you define something in a global scope which is window, you can have access to it all over your JavaScript code.
It seems your Page1 and Page2 are global objects, so you can do it like:
var Home= {
Sample: function (pageId,data) {
window[pageId].MergePageData(data);
}
}
but I guess data vriable is not a global, you have 2 options, first make it global or just store it in a storage like:
localStorage.setItem("data", JSON.stringify(data));
then change your Sample function like this:
var Home= {
Sample: function (pageId,data) {
window[pageId].MergePageData(JSON.parse(localStorage.getItem("data")));
}
}
Although you have to be very careful about the size of your data object, if it is a big object with a lot of properties and inner objects, you should reconsider and change your solution.
Basically you want to create your object Home inside an IIFE. That way you can pass in any library or object namespace throughout several files.
For your Home object, declare and run an anonymous function, assign your object directly to the the window object. This will be your "namespace" and accessible throughout your files by window.Home. Use this file to initialize your Page objects. As for now the DOM ready event is used from jQuery.
// #param ($): jquery library 1.10.2
(function ($) {
// 1. ECMA-262/5
'use strict';
// 2. PRIVATE CONFIGURATION
var cfg = {
// an object literal to store config
page2: {
page: 'page2',
data: 'data'
}
};
// 3. GLOBAL OBJECT NAMESPACE
window.Home = {
init: function(){
// initialize your other files
this.cache = {
page1: new Home.Sample();
page2: new Home.Sample(cfg.page2);
}
}
};
// 4. ONCE THE DOM IS READY
$(function () {
Home.init();
});
}(window.jQuery));
Then for your other files, a slightly different approach can be used.
// #param ($): jquery library 1.10.2
// #param (home): Home namespace
window.Home = (function ($, home) {
// 1. ECMA-262/5
'use strict';
// 2. CONFIGURATION
var cfg = {
page: 'page1'
data: 'data'
};
// 3. CONSTRUCTOR FUNCTION
home.Sample = function (options) {
this.settings = $.extend({}, cfg, options);
this.init();
};
// 4. PROTOTYPE OBJECT
home.Sample.prototype = {
init: function(){
this.cacheItems();
this.mergePageData(settings.data);
},
cacheItems: function(){
this.page = settings.page;
},
mergePageData: function (data) {
// do something with this.page and data
// consider caching data instead of passing it along
}
};
// 5. GLOBALIZE OBJECT
return home;
}(window.jQuery, window.Home || {}));
This approach is modular and better to maintain. Since the whole configuration is extracted from the logic you will find it easier to create different instances of an object. Simply by passing in options into your Sample object you can change the whole data/structure but keeping behavior as intended. You can fill in options from your server language and use the sizzle selector engine inside jQuery todo powerful DOM traversing and so on ...

Protect functions and var names on a javascript code

Im designing an API that requires my users to download a javascript file from my server and then load it on their pages. Inside this file there is a function call generic(), if my users include this js and for some reason they have a piece of js on their page where there is another function call generic() this will represent an issue. Im not a front end dev, I know that with php you can solve this creating a class and putting all your functions inside, so you can call them like $myclass->myfunction();, but how can i solve this on js? Is this even a good approach on js? (no jquery please.)
You will obviously always have to expose at least one identifier globally, but a common approach is to wrap everything in an immediately-invoked function expression:
var YourNamespace = (function () {
var privateData = 10; // Not accessible outside the IIFE
// Expose public properties (these functions can access the private data)
return {
someMethod: function () {
// Do stuff
},
anotherMethod: function () {
// More stuff
}
};
}());
This will expose a single identifier, YourNamespace, as an object with properties that can be used as methods. You can use it like this:
YourNamespace.someMethod();
Wrap your code inside a wrapper object/ or function.
var MyLibrary = {
global1: 123,
global2: 'abc',
doSomething: function(a){
// ...
},
somethingElse: function(b){}
};
If u are looking for Encapsulation in Javascript, then u are looking for Closures

Javascript: Wrapping entire script in a function call

I've came across a few times with this phenomena in JavaScript, where an entire script is wrapped in a function call, like this:
(function() {
// statements...
})();
Real world example, from glow.mozilla.com client-side code:
https://github.com/potch/glow/blob/master/media/glow.js
What is this coding style used for? What's the difference between with and without the wrapped function style and when should it be used?
Doing it like this ensures that none of the variables/function you define go into the global scope. All scripts you include in the page share the same global scope, so if you define two variables in two separate scripts with the same name, they actually refer to the same variable.
For example, suppose you have a.js and b.js, defined like so:
// a.js
var node = document.getElementById("something");
function frob() {
node.style.display = "none";
}
// b.js
var node = document.getElementById("something-else");
If you include b.js after a.js in your page, then when you call frob it's going to hide the "something-else" node instead of the "something" node like you would expect.
Instead, you can do something like:
// a.js
(function() {
var node = document.getElementById("something");
window.frob = function() {
node.style.display = "none";
}
})();
// b.js
(function() {
var node = document.getElementById("something-else");
})();
And the stuff inside b.js isn't going to interfere with what's in a.js.
Note that in reality I wouldn't add functions directly onto window, instead I would do something similar to what that glow.js script you linked to has: a single global variable that represents my scripts "namespace". In jQuery, for instance, that single global variable is $ (or jQuery).

Is it possible to destroy loaded JavaScript, including function & local variable?

I know. It is possible to dynamically load JavaScript and style sheet file into header of document. In the other hand, it is possible to remove script and style sheet tag from header of document. However, loaded JavaScript is still live in memory.
Is it possible to destroy loaded JavaScript from web browser memory? I think. It should be something like the following pseudo code.
// Scan all variables in loaded JavaScript file.
var loadedVariable = getLoadedVariable(JavaScriptFile);
for(var variable in loadedVariable)
{
variable = null;
}
// Do same thing with function.
Is it possible to create some JavaScript for doing like this?
Thanks,
PS. Now, you can use xLazyLoader and jQuery for dynamic loading content.
If the loaded script is assigned to a window property, for instance with the module pattern like so:
window.NiftyThing = (function() {
function doSomething() { ... }
return {
doSomething: doSomething
};
})();
or
window.NiftyThing = {
doSomething: function() { ... }
};
or
NiftyThing = {
doSomething: function() { ... }
};
Then you can delete the property that references it:
delete window.NiftyThing;
...which removes at least that one main reference to it; if there are other references to it, it may not get cleaned up.
If the var keyword has been used:
var NiftyThing = {
doSomething: function() { ... }
};
...then it's not a property and you can't use delete, so setting to undefined or null will break the reference:
NiftyThing = undefined;
You can hedge your bets:
NiftyThing = undefined;
try { delete NiftyThing; } catch (e) { }
In all cases, it's up to the JavaScript implementation to determine that there are no outstanding external references to the loaded script and clean up, but at least you're giving it the opportunity.
If, as Guffa says, the loaded script doesn't use the module pattern, then you need to apply these rules to all of its symbols. Which is yet another reason why the module pattern is a Good Thing(tm). ;-)
It might be possible to remove a Javascript file that has been loaded, but that doesn't undo what the code has done, i.e. the functions that was in the code are still defined.
You can remove a function definition by simply replacing it with something else:
myFunction = null;
This doesn't remove the identifier, but it's not a function any more.

Categories

Resources