I have a simple script which calls a function that is set in the function that the call is made...
But i get an "undefined function" error.
My script is:
function messages_document(messages){
messages = JSON.parse(messages);
function del_msg(id){
result = call_file('del.php',id);
if(result){
messages[id].length = 0;
}
}
var output = [];
output.push('<p align="center"><b><u>My Messages</u></b></p> <br/><br/>');
for(var id in messages){
output.push('Delete Message');
}
document.getElementById('main').innerHTML = (output.join(''));
}
I'm curious if i have misunderstood how scope works because i get:
del_msg is not defined
Any ideas why this is ?
You have a problem with the scope in that "del_msg" is defined: You need that function to be in the global scope, but you're creating it inside a function "messages_document" (that has its own scope).
Function statements are defined in the current scope, not globally. In this case, that means that del_msg exists only within the scope of messages_document. However, you invoke it via an onclick attribute: these attributes are evaluated globally. Since del_msg doesn't exist globally, it doesn't work.
You have two options. One is to make del_msg global, by defining it outside any other functions. However, this pollutes the global namespace, generally a bad thing. Better would be to apply it to your a element within the scope. This is going to require building the elements via DOM methods, rather than by HTML
var para = document.createElement('p'),
id,
link;
para.innerHTML = '<b><u>My Messages</u></b></p> <br/><br/>';
para.align = 'center';
for(id in messages){
link = document.createElement('a');
link.href = '';
link.onclick = del_msg;
link.innerHTML = "Delete message";
para.appendChild(link );
}
document.getElementById('main').appendChild(para);
Try declaring it like
var del_msg = function(id)...
Sorry confused. you are using the function on the window scope do declare it out of the other function.
The function is called with the onclick global scope.
What you have to understand here is that you are creating html code, but the onclick will be called when user click and not when you vreate the html.
Related
This is most likely a very simple one.
I have created a game in canvas and js. However I stumbled upon a problem. As I can access the variables and code inside the chrome console, I can change f.ex. the player score to whatever I'd like. This is not very good.
Is there some way I can make the file and variables non accessible through the console for players to use?
Thanks!
You can put the whole script into an IIFE so that any variables declared will be scoped to the just-invoked function, rather than be on the top level and accessible anywhere. For example:
(function() {
var playerName = 'bob';
var turnCount = 1;
// do stuff with playerName and turnCount,
// they won't be accessible or changeable from the outside
// you can declare functions and such here as well
// which will also only be accessible from the inside
})();
Like this, referencing playerName from the console will fail.
you can use a proxy.
javascript proxy
or you can make an IIFE and expose only the required functions such as:
var App = (function() {
var test = '';
var init = function() {
App.test = 'test';
};
return {
init: init
};
})();
or define your properties as not writable with Object.defineProperty()
I wonder if somebody could please help me understand something that seems odd with JS?
The below code works. The function inlineEditEvent.init() is called, and then t.copy() is called correctly (where var t = this;).
However, if I was to replace that with this.copy(), I get the error this.copy is not a function.
What's the difference here? Why does the below work, but not the way as described in the last paragraph? Thanks.
jQuery(function($){
$(document).ready(function(){inlineEditEvent.init();});
inlineEditEvent = {
init : function(){
var t = this;
/** Copy the row on click */
$('#the-list').on('click', '.row-actions a.single-copy', function(){
return t.copy();
});
}, // init
copy : function(){
// Do stuff here
}
} // inlineEditEvent
});
You're setting t as a context variable of this (of your init function). Once inside your click handler, this is now referring to the click handler, no longer the init function. Therefore, this.copy() is not a function.
this refers to this within the functions scope. That's why you need to set a self variable, so it's accessible within the scope of the function. Considering you're using jQuery, you could use $.proxy:
$.proxy(function(){
return this.copy();
},this)
t.copy(); appears in a different function to var t = this;. The value of this changes inside each function.
When you say var t= this; it refers to what this meant in that context. Later on when you are trying to refer to this, it is referring to a.single-copy instead since that is the new context it is in.
I am trying to write some javascript functions for a web application.
Following the advice from here: How do I declare a namespace in JavaScript?
I am trying to make the code unobtrusive by wrapping everything in named functions, however I am running into difficulty accessing properties in the parent function when inside a child anonymous function.
For example:
var title_picker = new function(){
// This property should be public
this.callback=function(){};
var ok=function(){
var title = $('input#title').val();
callback(title) // <---
}
...
When inside the "ok" function, what is the best way to reference the "callback" property?
With the code as written, no there isn't.
You can access variables from the scope of the parent, unless they are overwritten in the narrower scope.
this is always overwritten.
You can copy this to another variable that remains in scope though:
var title_picker = new function(){
var self = this; // Copy this to a variable that stays in scope
// This property should be public
this.callback = function(){};
var ok=function(){
var title = $('input#title').val();
self.callback(title) // self is still in scope
}
...
Perhaps something like this:
var title_picker = new function(){
// This property should be public
this.callback=function(){};
var that = this;
var ok=function(){
var title = $('input#title').val();
that.callback(title) // <---
}
...
Though there are many frameworks that do this kind of thing for you (yui, dojo, prototype...)
This is a very old problem, but I cannot seem to get my head around the other solutions presented here.
I have an object
function ObjA() {
var a = 1;
this.methodA = function() {
alert(a);
}
}
which is instantiated like
var myObjA = new ObjA();
Later on, I assign my methodA as a handler function in an external Javascript Framework, which invokes it using the apply(...) method.
When the external framework executes my methodA, this belongs to the framework function invoking my method.
Since I cannot change how my method is called, how do I regain access to the private variable a?
My research tells me, that closures might be what I'm looking for.
You already have a closure. When methodA is called the access to a will work fine.
Object properties are a different thing to scopes. You're using scopes to implement something that behaves a bit like ‘private members’ in other languages, but a is a local variable in the parent scope, and not a member of myObjA (private or otherwise). Having a function like methodA retain access to the variables in its parent scope is what a ‘closure’ means.
Which scopes you can access is fixed: you can always access variables in your parent scopes however you're called back, and you can't call a function with different scopes to those it had when it was defined.
Since a is not a property of this, it doesn't matter that this is not preserved when calling you back. If you do need to get the correct this then yes, you will need some more work, either using another closure over myObjA itself:
onclick= function() { myObjA.methodA(); };
or using Function#bind:
onclick= myObjA.methodA.bind(myObjA);
yes, you're right. Instead of a method reference
var myObjA = new ObjA();
libraryCallback = myObjA.methodA
pass a closure
libraryCallback = function() { myObjA.methodA() }
If you are using jQuery javascript framework, easiest way is to use proxy:
$('a').click($.proxy(myObjA, 'methodA'));
I'd do this:
function ObjA() {
this.a = 1;
this.methodA = function() {
alert(this.a);
}
}
function bindMethod(f, o) {
return function(){
return f.apply(o, arguments);
}
}
var myObjA = new ObjA();
myObjA.methodA = bindMethod(myObjA.methodA, myObjA);
...
Where bindMethod binds the methodA method to always be a method of myObjA while still passing on any arguments which function() {myObjA.methodA()} doesn't do.
I have a class:
function RustEditor() {
this.init = function() {
var saveButton = this.container.find("button.saveButton");
saveButton.click(function(){this.save();});
};
...
When I click the button, it complains that this.save is not a function. This is because "this" does not refer to the instance of RustEditor here, but to the button. What variable can I use inside that callback closure to point to the instance of RustEditor? I could use rust.editor (it's name in the global scope) but that's smelly code.
Common practice is to enclose the this value like so:
function RustEditor() {
this.init = function() {
var self = this;
var saveButton = this.container.find("button.saveButton");
saveButton.click(function(){self.save();});
};
Update with suggestion from tvanfosson:
this gets rebound when the event handler is invoked and thus you need to capture the reference to the class at the time the object is created with a variable that will retain that reference in the closure.
Within RustEditor() you could first copy a reference to the button and use that.