Im building a webapp where i load the main page with its own javascript file in the index.html then the nav is calling all other pages in a div without a browser refresh using $.ajax and attaching specific script for each page in the div too with $.getScript.
Sometimes i needs to access a method declared in the main page javascript from within the div loaded javascript so what i generally do is attach the main method to document, exemple, instead of just:
let doThis = function(num){
// do your stuff
}
i do this
document.doThis = function(num){
// do your stuff
}
This way i can easily access it from any other javascript file loaded at different levels.
Thing is i feel its not a good practice, what would then be the good practice? or is it acceptable one?
If you are not using any bundler,then 'Revealing Module Pattern' can be used as a good practice here. This will allow the syntax to be more consistent and in this case, will make it easier to tell which of the functions can be accessed globally.
window.mainPageModule = (function () {
var privateVar = "abcd",
function privateFunction() {
//Do some private stuff here
}
function publicSetValue(value) {
privateVar = value;
}
function publicGetValue() {
return privateVar;
}
// Reveal desired functions to public
return {
doThis: publicSetValue,
getThis: publicGetValue
};
})();
Then, to access the public function anywhere globally
mainPageModule.doThis("1234")
Related
I have been learning about encapsulation in Javascript with the module pattern. I want to give access to specific js files. From what I understand, it is only possible to restrict access to everything and give access to everything, is this correct?
smiley.js
(function(exports){
function smiley(string){
return string + ' :)';
};
exports.smiley = smiley;
})(this);
play.js
smiley('Hello');
Given an HTML file that includes smiley.js and play.js.
<script src='smiley.js'></script>
<script src='play.js'></script>
Is it possible to have another js file that does not have access to smiley.js but is also included in the HTML file?
Is there only global (window) scope and private scope or can I specify a scope for different files?
If I understand your question correctly, I would say:
const Script1 = (function () {
// Encapsulate the logic.
const Logic = {
sayHi () {
alert('Script1 says hi!');
},
shutUp () {
alert('Shut up!');
}
};
// Public attributes.
return {
sayHi () {
Logic.sayHi();
}
}
})();
document.addEventListener('DOMContentLoaded', function () {
Script1.sayHi(); // Will successfully work.
// Script1.shutUp(); -> Will say "Script1.shutUp is not a function".
});
Basically the idea is simple. Inside the self-invoking function you declare an object, which will hold the functions and data fields. Then from the return statement of the self-invoking function you can make functions publicly available. This way you can keep the ones you want private - private, and the ones you want available - you can make available. The same applies for multiple JS scripts. Just each script declares it's own self-invoking function. Script1, Script2, etc...
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
Hi,
I have my main file in which I include my javascript file.
In my javascript file I have this
$(document).ready(function(){
//some functions here
});
I want all the functions just available to this page and I know you can kinda conceal them to outside world of javascript by doing something like
(function(){
$document.ready(function(){
//my functions
)};
}).init();
but I am not 100% sure how would it be called or whether its even the right way.
Anyone shedding light on this would be a great help!
In javascript everything declared inside a function is only available inside that function (except for when you declare a variable without the keyword var).
So everything inside the function that you pass to $().ready() is only available inside that function.
$(document).ready(function () {
//all code here is scoped inside this function, so it can't be accessed
// outside of this function
});
Like the first comment says you can't hide them from the user, if they really want to see it, they will see it.
You can clean them up in a way if you really wanted to, something like
var mySpace = {};
mySpace.init = function() {
// your init functions here
};
in doc ready you just call
mySpace.init();
I am not sure if this is what you wanted but it is the way I understood the question
(function(){
var secret1 = function(msg) {console.log("Secret Message:" + msg);}
$document.ready(function(){
secret1("this can only be called from within");
)};
})();
secret1("this will cause a script error");
It sounds like the thing you are looking for is a 'javascript obfuscator'. Here is an example one. It makes the code much harder to read and copy. But as others have said, you can't actually fully hide javascript.
The problem here is that JavaScript is intrinsically a client-side scripting language unless using a server-side javascript application such as node.js.
As long as JavaScript is being used in this way, the entirety of your code will be downloaded much like downloading a .txt file from a website. The only real difference is that the ".js" extension and its inclusion in html <script> tags or in an AJAX call will force the user's browser to render it as JavaScript.
If you want to make the script a little harder for the user to find, however, this is doable. I recommend having your website retrieve the script via AJAX and appending it to the DOM. You can do this with require.js or by using Kickstrap and making your script into an "app." The script won't appear as a link in the DOM and the user would really have to search for it. You can make it even more difficult (without compromising the integrity of your site) by minifying the script. This will make it run faster while inadvertently making it less human-readable on the front end.
In JavaScript there is only function scope (the exception argument in try-catch being an exception). ES5 will let you use let (no pun intended) to achieve block scope but it wont be usefull untill majority of UAs implement it.
So your functions are concealed from the outside world, if with outside you mean outside the dom ready event.
$( document ).ready( function () {
var myFunc = function () {};
} );
myFunc();// <- ReferenceError: myFunc is not defined
You can't really hide the functions, as it's in the source code of a file downloaded by the client, but you can make it so they can't access your functions from javascript.
(function() {
var doStuff = function() {
// Not Accessible
console.log('You can\'t reach me!');
}
return {
'init': function() {
// Accessible
doStuff();
}
}
})().init();
If you are talking about Access Modifiers like public, private etc. Then check out this article on how Javascript handles this. Here are the key components:
//constructor function (class)
function Maths(x, y) {
//public properties
this.x =x;
this.y = y;
//public methods
this.add = function () { _sum = x + y; return _sum; }
this.mod = function () { _mod = x % y; return _mod; }
//public method calls private method
this.show = function () {
this.add();
this.mod();
showResult();
}
//private variables
var _sum=0;
var _mod=0;
//private methods
function showResult() {
alert( "sum: " + _sum + ", mod: " + _mod );
}
}
//end function
//create instance
var plus = new Maths(3, 4);
plus.show();
//static method multiply, you can use it without instance of Maths
Maths.multiply = function (x,y) { return x * y; }
//call static method by constructor function (class) without instance of Maths
var result = Maths.multiply(5,7);
alert(result);
//output: 35
UPDATE: The back-end service was powered by an ASP.Net AJAX Web Service proxy.
1) The main page has two global objects, one for the back end connections (Svc) and another for handling the DOM (Main). It also dynamically loads documents into an iframe.
2) These iframes need to access services provided by Svc, and also supply a callback function.
3) The problem - passing a function created in the iframe to the parent frame, it's treated as an object not a function and cannot be invoked.
Can anyone provide a better solution than what I've got currently in the iframe:
var Main = parent.Main,
Svc = parent.Svc;
Svc.method(data, Main.createCallback(
function(response) {}
));
and in the parent frame:
Main.createCallback = function(func) {
return function() {
func.apply(func, arguments);
}
}
if you override the iFrame's function from the main, the main scope will then be used.
The inverse problem can be seen here, in your case, you just override the frame's function itself i.e:
document.getElementById('yourFrameID').contentWindow.targetFunctionInFrame = targetFunctionInMain;
Bonus: if you can modify the iFrame's code, I would suggest to:
In the frame:
make a placeholder function callbackParent() {}
add a call to this function into your iframe code, so that you just have to override the callbackParent from your main.
In the main:
make the function which should be invoked function doStuff() {}
override the function as described above document.getElementById('yourFrameID').contentWindow.callBackParent = doStuff;
I use iframes to modularize my app too.They are a kind of includes embedding all CSS, HTML and JS for a module.
My first attempts were by returning a function too, but then I found it quite hard for sharing scopes.
Now I make directly a reference to the main parent object in the iframe.
eg:
var Svc = parent.Svc, JSON = parent.JSON, $ = parent.$;
Svc.module1 = {
method1:function(arg){
...
},
...
}
The global var JSON and jQuery references are here to have them available inside the methods.
My guest is that Svc.method is making some checks to see if the callback has some criteria before calling it. This criteria might be that the callback function must created by the same framework (here it's ASP.Net). You have to find what that criteria is. if "Main.createCallback" works, it's because it's meeting that criteria.
Sorry but your all wrong... add this....
const event = new CustomEvent('MSGSent', { detail: "fff variable" });
Call it like this....use a global variable for detail... like an array []
window.dispatchEvent(event);
Now after the iframe loads add this code and you get an Object back in the main page....
iframe.onload = function() {
try {
iframe.contentWindow.addEventListener('MSGSent',function(e){
alert(e.detail);
});
} catch (error) {
}
};
The problem is ASP.Net AJAX Web Service proxies, which don't appear to support calling the web service from an iframe with an inline callback function.
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.