So I want to call a function Local.getThis onload with this code:
class Local {
getThis() {
let that;
if (localStorage.getItem('that') === null) {
that = [];
console.log(that);
localStorage.setItem('that', that);
} else {
that=JSON.parse(localStorage.getItem('that'));
console.log(that);
}
}
// DOM Load Event
document.addEventListener('DOMContentLoaded', Local.getThis)
But nothing is happening, no error nothing. But when I change "getThis" to STATIC it works (Output: []). Does it need to be STATIC ??
P.S.
After setting that = []; I get an error
'Uncaught SyntaxError: Unexpected end of JSON input
at JSON.parse (<anonymous>)
at HTMLDocument.getThis'
on the next reload but that is probably a whole other problem I guess.
EDIT:
For the record the error was related to localStorage.setItem('that', that);, it should be ofcourse localStorage.setItem('that', JSON.stringify(that));
part 1: this is a reserved word in JavaScript, change parameter's name.
part 2: Local is a class, so to access a function directly from it that function must be static. Otherwise an instance needs to be initiated first. and the function can then be used from that instance.
But nothing is happening, no error nothing. But when I change
"getThis" to STATIC it works (Output: []). Does it need to be STATIC
??
To call your method as Local.getThis need to be static.
Otherwise you need to create an instance of Local.
var local = new Local();
document.addEventListener('DOMContentLoaded', function() {
local.getThis();
})
You should create an instance of Local class first to have this
const local = new Local();
document.addEventListener('DOMContentLoaded', local.getThis.bind(local))
//or
document.addEventListener('DOMContentLoaded', function() {
local.getThis();
})
Update
Also you cannot use variable name this as it is reserved word.
If you don't need a context (this) you can create a method as a static method:
class Local{}
Local.getThis = function() {
// code without this
}
so then you can use as you've written:
document.addEventListener('DOMContentLoaded', local.getThis);
Related
I have javascript file called screener.js
function ScreenerPage() {
function onScreenListChange() {
do stuff
};
}
from the index.html file I include the javascript file like this:
<script type="text/javascript" src="./js/screener.js"></script>
Then later in the head section of index.html I instantiate the screenerPage object like this:
<script type="text/javascript">
$(document).ready(function () {
screenerPage = new ScreenerPage();
}
</script>
Then down in the body section there is a select with onchange event that calls
<select id="screenList" onchange="screenerPage.onScreenListChange()">
but the browser shows error:
Uncaught TypeError: screenerPage.onScreenListChange is not a function
What am I doing wrong?
The way javascript works is it has objects and the way of which they are created matter!
Here is the way i've found that works for this kind of thing
screener.js
var ScreenerPage = function() {
this.onScreenListChange = function() {
//do stuff
console.log("test")
}
}
Later on
var a = new ScreenerPage();
a.onScreenListChange();
if you have any questions on how it works feel free to try to message me!
The reason it does not work is that you're having a scope issue.
The function ScreenerPage is defined in the global scope, meaning it is accessible anywhere. Now inside that function you define a local function called onScreenListChange.
You are able to do that, but that function only exists within the scope of the function you defined it in.
When I look at your function, I think you want to use classes. A class is a single name that can have multiple variables / methods to do a specific task.
class ScreenerPage {
constructor(text){
this.onScreenListChange(text) // Call this "method" on object creation.
}
onScreenListChange(text) {
console.log(text ? text : 'do stuff');
};
}
var a = new ScreenerPage('hi'); // now watch your console log.
a.onScreenListChange();
I know (or I think I know) how scopes in JavaScript work so I suppose it can be impossible BUT: is there a way to get to the block (function) scoped variables in a class instance?
class Test {
run() {
const running = true;
}
}
const test = new Test();
test.run();
console.log(?) -> here I would like to get info that `running` variable was created
I can't create another function inside Test class. I've just got the instance.
FYI: the problem I try to solve is broader and has to do with 3rd-party library.
Unless you change the function run you can't access the property within. If you're working with 3rd-party code it's hard but a possible solution would be to overwrite the method by extending the class (you need to go very sure that the 3rd party code doesn't change that much):
class ConcreteTest extends Test {
run() {
// option A
this.running = true
// option B
return true;
// or use both A and B
}
}
The run function would be overwritten so it depends if this is an appropriate or working solution.
Doesn't your library provide any API or workaround to solve your issue?
I know how scopes in JavaScript work so I suppose it can be impossible
Yes indeed. That's what block scope means: the variable is only available to code in that very block, i.e. between the { … } braces of the run method.
test.run();
console.log(?) // here I would like to get info that `running` variable was created
No, that's not possible. Notice the the running variable doesn't even exist any longer after the .run() call ended.
The only way to make the true value available to the outside is to change the run method, e.g. by making it an object property not a local variable.
var app = { running: true };
var Test = { run: function() { return app.running; } };
var testInstance = new Test();
var testRunMethod = testInstance.run; testRunMethod();
app.running can be globally accessed switch. the run method can be a property of the test object and therefore can be copied and reused.
I've a crazy problem. I'm instantiating an object from a class. Then I want to pass a function from this object to the setInterval function. The whole code block is executed with a keyDown event.
Here's the code:
function doKeyDown(e){
var instance = new Class(e.keyCode);
setInterval(instance.functionToBeExecuded(), 200);
}
The strange thing is that it's getting executed once and then starts to loop an error which states (firebug):
27
SyntaxError: missing ] after element list
[object HTMLAudioElement]
For the sake of completeness:
Class.prototype.functionToBeExecuded = function(){
var node = document.createElement("audio");
//the key is stored in the object (from the Class's constructor)
node.setAttribute("key", this.variable);
}
Does anyone see some fails?
Thanks in advance! =)
P.S.: This is not a duplicate cause I'm not facing the function, function() error. If I'm executing it with (instance.functionToBeExecuded, 200) it happens just nothing.
What I've found out so far is that the problem must be in the scope somehow. If I do it like this:
function doKeyDown(e){
var instance = new Class(e.keyCode);
setInterval(instance.functionToBeExecuded, 200);
}
Class.prototype.functionToBeExecuded = function(){
console.log(this);
var node = document.createElement("audio");
//the key is stored in the object (from the Class's constructor)
node.setAttribute("key", this.variable);
}
I'm getting a looping console output with "window". So the function is executed in the window's scope. But why? And how to work around?
Console output:
Window index.html
The workaround would be: wrap it using another function instead of calling method directly
function doKeyDown(e){
var instance = new Class(e.keyCode);
setInterval(function(){
instance.functionToBeExecuded()
}, 200);
}
This would give output many of these:
Class {functionToBeExecuded: function}
I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}
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.