I am trying on some code here,
var cat={
col:"Red",
getCol:function(){
document.writeln(this.col);
}
}
function getCol(){
document.writeln(cat.col);
}
$(function(){
$("#button1").click(cat.getCol);
$("#button2").click(getCol);
})
But I got undefined for button1, "Red" for button2. Can someone tell me why?
And if I change it into $("#button1").click(cat.getCol());, I got the "Red" I need...
First of all
$("#button1").click(cat.getCol);
gives you undefined because the body of cat.getCol uses this which ain't cat when this thing runs. I would suggest using Function.prototype.bind here, or several of the other variants if you are worried about cross-browser compatibility. There are many published solutions to the problems of setting "methods" as event handlers and ensuring that this stays bound to the enclosing object.
Next
$("#button2").click(getCol);
works fine because getCol uses cat directly.
Finally
$("#button1").click(cat.getCol());
is terribly wrong. The expression cat.getCol() is a call which returns undefined. This is not a good value to set for a click handler. You just saw the document.write taking place, but not in response to a click.
ADDENDUM
Live demo using bind
Generally in JS, this refers to the owner of the function .. So, in both cases when that function is called, this would resolve to the (jQuery object of the)element that has been clicked.
In the first case, this is not 'cat', so col is not defined. Thus, it gives undefined.
In the second case, no this, so cat.col resolves to Red.
I think you need to do some reading about JS functions, this, anonymous functions .. http://yehudakatz.com/2011/08/11/understanding-javascript-function-invocation-and-this/ is a good place to start.
This on MDN - https://developer.mozilla.org/en-US/docs/JavaScript/Reference/Operators/this
Related
I have what looks like to me to be a simple variable assignment not working.
This code is in jQuery, for the context see here.
I'm calling:
$('#foo').on('someEvent', eventHandlerFn);
And I get this issue within the jQuery on function. Here's the starting point:
As you can see from the console below the code, selector is set the my eventHandlerFn and the fn variable is undefined. This is as expected.
On line 3509, the value of selector is assinged to fn. So, the value of fn should be same as the value of selector, no??
See below - selector is defined, as expected, but fn is still undefined. Why?
The end result is that my event handler is never registered.
The code runs well as shown in the following two screens (the issue is on how chrome sets the context to the console)
It looks like console has access to the variable at definition time (in this case the passed parameters) and not the live values as you run the code
Before the swap
After the swap
I'm not seeing any problem with this jsFiddle. Feel free to edit the jsFiddle to get it to look more like your code.
Can you try putting in console.log(fn); after line 3510 and rerunning? Maybe it's just a problem with the debugger?
This seems to be an issue with the debugger in Chrome - either a material problem or just a nuance of the debugger that I don't understand. fn does have a value toward the end of the call, but not where the breakpoint is.
I'm updating an existing website running on Expression Engine. So far, I've stayed away from any code I didn't write or couldn't understand. I recently must have altered some bit of code someplace (helpful, I know) and now a block of JS I didn't write is causing an error that seems to bypass the document.ready() event. The window.load() event however is still taking place.
In the Chrome DevTools Console, the error "Uncought TypeError: Cannot call method 'replace' of UNDEFINED" points to the definition of a function "fixedEncodeURIComponent" pasted below.
$("#MessageContainer.Counted").counter({
type: 'char',
goal: 250,
count: 'down'
}).change(function(){
var TEMP = fixedEncodeURIComponent($(this).val());
$("#Message").val(TEMP);
});
var TEMP = fixedEncodeURIComponent($("#MessageContainer.Test").val());
$("#Message").val(TEMP);
function fixedEncodeURIComponent (str) {
str=str.replace(/"/g, '');
return encodeURIComponent(str).replace(/[!'()*]/g, escape);
}
As I interpret the error, this function is being passed a variable that is not a string. I added an alert(str) to the function definition and the result was UNDEFINED as I expected. The first of several unknowns for me is which call to the function 'fixedEncodeURIComponent' is being passed a bad variable. I assume that it's the first call, but that's just a guess. It so happens that this first call contains a syntax I have never encountered before. I don't know how to interpret what happens when $(this) is passed as a function argument.
Any insights would be greatly appreciated. Also, if there's more information you need please let me know. The client's site is password protected but I can include any code you request.
Thank you.
I'm taking a guess that the }); on line 3 is exiting a document.ready context. If that's the case then your second call to fixedEncodeURIComponent may be getting called before the DOM is even loaded.
Start by wrapping
var TEMP = fixedEncodeURIComponent($("#MessageContainer.Test").val());
$("#Message").val(TEMP);
in a
$(function() {
// code
});
block. If that doesn't work, check that #MessageContainer.Test actually matches an element. Since this is code you inherited, the class name "Test" clues me in that the block in question might be a remnant of someone trying to debug an issue and maybe it should have been removed.
I suspect $("#MessageContainer.Test") since it looks like its supposed to be an ID selector instead of what it actually is when jQUery parses it(which is an ID selector combined with a class selector). $("MessageContainer\\.Test") allows you to select an element with ID MessageContainer.Test
OK, I looked a lot for this on the web but cannot find an answer.
I can expect CSS differences between browsers but there are JavaScript differences too?
So why this works in IE8:
window.print(); // works
but when I pass window.print to a function and call it, it don't work in IE8 (works in IE9):
function callIt(f){
f.call();
};
callIt(window.print);
Is it a known issue?
EDIT
OK it does not work means it will simply ignore it, no javascript error or anything.
Sorry it gives this error:
Object doesn't support this property or method
EDIT 2
I need to use call or apply since I need to pass the context. I am trying to create a class which I can pass functions and it can call it with the possibility of passing context or arguments. Do not tell me to use f() that is not an answer since it does not fix my problem. The question is on call and apply.
It seems window.* functions are separate types than user-created functions in IE < 9. Thus, they don't get any of the Function.prototype.*. You'll see that
typeof alert === 'object'
function a(){}
typeof a === 'function'
This would happen for any of the window.* functions. Only for IE < 9. WTG Miscrosoft.
However you can try
Function.prototype.call.call(window.print)
See if that works for you.
function callIt(f) {
if (f) f();
}
callIt(window.print);
Done, no?
Update
per the poster's request that I answer the question, not recommend a solution that works, here she goes:
If you view typeof(window.print) in IE, you'll see that it reports itself as type object. Type object has no apply or call method. In my opinion, your design is wrong for the task. HOWEVER, if what you want is a rabbit hole to follow, here's the top:
var p = window.print;
window.print = function() { p(); }
function callIt(f){
f.call();
}
callIt(window.print);
I have no idea what will happen in any other browser or how many procedural exceptions you'll have to make to account for it everywhere you'll need to.
You almost certainly should not be using .call() here. f() will call the method, while f.call() will call it with an unset this. Under es3 (but not es5 strict,) an undefined value for this will be coerced to window. I suspect that IE9 properly handles this, while IE8 does not, but that's just a guess based on behavior.
If print cares about the value of this, you should call it as window.print() in order for this to be set correctly. In that case, you may have to wrap it in an anonymous function so that print doesn't get "sliced off" of window. callIt(function() { window.print();});
Im a newbie programmer who got the function below from Stoyan Stefanovs object oriented JavaScript Book. He says that if you call next three times, it will output "a" and "b" and then "c". When I tried it in firebug console, it kept giving me "a", so that`s one question (a) i.e. is there something about firebug that would explain my result?
Next, I tried to run it in jsfiddle.net but it won`t output anything. http://jsfiddle.net/mjmitche/SkSMm/
Im sure Im doing something wrong, but what? Please explain if you can. Note, I did next(); and got A, and then I did next(); again and got 'a' and next(); again and got 'a'. In other words, the counter didnt change or didnt remember.
function setup(x) {
var i = 0;
return function () {
return x[i++];
};
}
var next = setup(['a','b','c']);
next();
Here is the jsfiddle link to show it works:
http://jsfiddle.net/ZnZTk/
JsFiddle is not like the console, it doesn't have a window where it will output return values. The result of the code is a web page, that is shown at the lower right.
You can use the alert method to show the values:
alert(next());
http://jsfiddle.net/SkSMm/4/
As you see, calling next three times will actually output the three values in the array. The setup function returns a delegate to the anonumous function that is created in the function. As that anonymous function uses variables outside itself, but which are local to the surrounding function, a closure is created for the function. The closure will contain the i and x variables. As the closure belongs to the delegate, it will survive from one function call to the next, and retain the values of it's variables.
You could do a similar thing just using global variables:
var x = ['a','b','c'];
var i = 0;
function next() {
return x[i++];
}
alert(next());
alert(next());
alert(next());
As the variables are declared outside the function, they will survive between the function calls.
The drawback of using global variables is that one script easily clashes with another if the variables are not given very unique names. If you use a closure, there is no risk of the variables of one script to conflict with variables of another script.
You did it wrong:
And jsfiddle: http://jsfiddle.net/ZHgW2/
Here's a neat demo that takes advantage of an imported say function and relies on a button:
http://jsfiddle.net/entropo/wxTqR/
This is a great way to test your scripts without relying on the log or alerts.
The say function is from jQuery in Action. Excerpt:
Within this function, we employ the services of a small utility function, say() C,
that we use to emit text messages to a dynamically created element on the page
that we’ll call the “console.” This function is declared within the imported support
script file (jqia2.support.js), and will save us the trouble of using annoying and disruptive alerts to indicate when things happen on our page. We’ll be using this handy function in many of the examples throughout the remainder of the book.
Hey I have this code right here:
http://pastie.org/534470
And on line 109 I get an error saying "TypeError: Result of expression 'this.allVarsDefined' [undefined] is not a function."
Scope in javascript is confusing to me. Can anybody see what my problem is? Also do you guys know of any articles that would help me learn about scope in javascript. This is my first time really using JS :)
This looks prototype-based. You probably need to set up your notification callback like this:
setTimeout(this.notify.bind(this), 5000, track);
so that the notify function is bound to the Scrobbler object and gets this set to the Scrobbler object instead of the event triggering the function when the timeout occurs.
If I'm wrong on you using prototype, you can probably achieve the same effect using
var that = this;
setTimeout( function() { that.notify(); }, 5000, track );
Try changing line 109 from
setTimeout(this.notify, 5000, track);
to
setTimeout(function(){this.notify()}, 5000, track);
What this will do is create "closure" (function(){this.notify()}) that includes the "this" variable in it, and "this" includes this.allVarsDefined, so you should stop getting that error.
I think the problem with your old code is that when you write "this.notify" you were just yanking the function out of the instance of the object and passing it to setTimeout, but you were not passing any information about the object itself. That would be okay if the notify function did not refer to "this", but since it does refer to "this", you need to use a closure.
You would benefit from reading more about Javascript closures. Here is a decent article. I also recommend the great book Java Script: The Definitive Guide 5th Edition by O'Reilly. It only costs like $50 but it is well-written and will help you immensely if you are trying to write a web-app in javascript.
If my solution does not work, then simplify your code down to the most basic thing that you think should work and does not work, and then post it here.