I have a problem understanding Javascript's engine technique called hoisting.
I've tried to create a var in the top of my file to quickly access and edit, but i want to use a variable that has yet to be declared.
First attempt:
var easy_to_edit_value = "some text " + a_yet_to_be_defined_var;
//imagine loads of code so its hard to find the correct funtion to edit the log
function my_function (a_yet_to_be_defined_var){
console.log(easy_to_edit_value);
}
my_function("more text");
This generates an error at line 1 since a_yet_to_be_defined_var is not defined.
After looking at this post: post-by-apsillers i tried again but this time declaring the var without value (so its known but undefined untill declared somewhere futheron)
var a_yet_to_be_defined_var; // now its known so this error is gone
var easy_to_edit_value = "some text " + a_yet_to_be_defined_var;
function my_function (a_yet_to_be_defined_var){
console.log(easy_to_edit_value);
}
my_function("more text");
//still undefined
//new attempt with a fresh var being set in the function before being called
var new_var;
var easy_to_edit_value = "some text " + new_var;
function my_function2 (a_yet_to_be_defined_var2){
new_var = a_yet_to_be_defined_var2;
console.log(easy_to_edit_value);
}
my_function2("more text");
//still undefined
But this outputs: some text undefined where i was expecting the some text more text since i filled the var before asking for it.
Please note these functions aren't ran using my_function("something") but are triggered by this: client.on('message', my_function);, i've seen arrow function solutions for related questions but i'm not sure how i would get that to work here.
Is it possible to make this work?
Instead of defining a value called easy_to_edit_value, change it to a function called easy_to_call_function that will return "some text " concatenated with the current value of new_var.
Once a (var or let) variable is assigned, it must be reassigned or reevaluated each time.
let new_var;
const easy_to_call_function = () => "some text " + new_var;
function my_function2(a_yet_to_be_defined_var2) {
new_var = a_yet_to_be_defined_var2;
console.log(easy_to_call_function()); // Call the function
}
my_function2("more text");
You need to re-declare the variable inside of the function:
var new_var;
var easy_to_edit_value = "some text " + new_var;
function my_function2(a_yet_to_be_defined_var2) {
new_var = a_yet_to_be_defined_var2;
easy_to_edit_value = "some text " + new_var;
console.log(easy_to_edit_value);
}
my_function2("more text");
If one variable is changed, other variable will not update according to the new value. That kind of programming requires a really high level compiler, which not many people are willing to make. The programmer must update variables on their own.
Related
I am getting an undefined when I try the post to twitter function. Should the quote_text variable be global and therefore accessible by the quoteTwitter function?
$(document).ready(function () {
loadJSON();
getQuote();
console.log(quote_text);
});
// Declare variables
var json_obj;
var num = 0;
var quote_text = "";
// Display a quote - this method is not perfect since the random number will repeat itself and it appears as if no new quote is delivered
function getQuote(callback) {
var html = "";
num = randNum();
quote_text = json_obj[num].quote;
html += "<strong> " + quote_text + " </strong>";
$("#quote").html(html);
$("#author").html(json_obj[num].author);
};
// Post the current quote on twitter
function quoteTwitter(quote_text){
var tweet = quote_text;
window.open('https://twitter.com/home?status=' +encodeURIComponent(tweet),"_blank");
}
Your function definition includes quote_text as a parameter, so inside the function it's trying to use that instead of the global variable with the same name. You're presumably not passing anything to the function when you call it, so it comes out as undefined.
You can fix this by changing this:
function quoteTwitter(quote_text){
to this:
function quoteTwitter(){
...but it'd probably be better in the long run to pass the correct value in as a parameter, if possible, instead of depending on global variables.
I can't figure out what's wrong with the following code and why would it work when I do it using the second way. Can anyone please help me understand this?
I have this following Javascript code:
var clsFunc = function(prefix) {
var id = 0;
return function() {
id = id + 1;
console.log(prefix + id);
}
}
First way (did not work):
If I try to call this function like this nothing happens
clsFunc('div')
Second way (worked)
var getId = {'div': clsFunc('div')}
getId.div()
Result:
div1
undefined
getId.div()
Result:
div2
The clsFunc function creates a function and returns it. So just doing
clsFunc('div');
...is pointless, because it creates a function and then just throws it away, because you didn't store it anywhere.
The second way stores the function that was created in an object property. That function has a reference to the context that created it (the call to clsFunc), even though that call has returned, which contains the id variable. When you call the function (getId.div()), it adds 1 to id and then outputs the prefix ("div") followed by the new value if id (1, then 2, then, 3, etc.).
You don't need an object for your second way, you could just use a variable:
var clsFunc = function(prefix) {
var id = 0;
return function() {
id = id + 1;
console.log(prefix + id);
}
};
var f = clsFunc('div');
f(); // "div1"
f(); // "div2"
(The undefineds you're seeing are just because you're running this in a JavaScript console that shows you the result of calling the function; since the function doesn't return anything, the result of calling it is undefined.)
I've built a simple html input so that users can input a zip code and then I have a variable in javascript set to that input. I can console.log this to prove the variable is set and that it is a string. I then try to run an ajax call and sub in the zip but it doesn't work. I can console.log the variable at any stage and see the variable has been updated, but somehow it's a hoisting issue or something where the ajax call value 'userInputZip' always reads to what I initially set. The ajax call works when 'userInputZip' is initially set to a valid zipoAny help is appreciated.
$(document).ready(function(){
});//end of document.ready
var inputDate = '2015-12-04T20:00:00';
var inputZipCode = '60618';
var userInputZip;
function runAjax(){
console.log(userInputZip);
$.ajax(getJambaseData);
}
// var dataArr = [];
var getJambaseData = {
type: 'get',
url:
'http://api.jambase.com/events?zipCode='+userInputZip+'&api_key=[inserted my key here]',
// 'http://api.jambase.com/events?zipCode='+userInputZip+'&api_key=[inserted my key here]',
success: function (data){
for (i=0; i< 10; i++){
if(data.Events[i].Date == inputDate){
var shortDate = data.Events[i].Date.substring(0,10);
var shortTime = data.Events[i].Date.substring(11,19);
// dataArr.push(data.Events[i].Date, data.Events[i].Artists[0].Name);
$("#divID").append('</p>' + 'date::: '+ shortDate + ' time:::' + shortTime + ' show::: ' + data.Events[i].Artists[0].Name + ' time::: ' + data.Events[i].Date + ' address::: ' + data.Events[i].Venue.Address + ' city::: ' + data.Events[i].Venue.City + '</p>');
}
}
},
error: function(){
console.log('failed');
},
}
function findShows(){
var userZip = document.getElementById("userInput");
userInputZip = userZip.value;
document.getElementById("divID").innerHTML = userInputZip;
runAjax();
}
////////////////////
You've mentioned
but somehow it's a hoisting issue or something where the ajax call value 'userInputZip' always reads to what I initially set
You define getJambaseData as a variable when the script is initially executed. You set the url value to url:
'http://api.jambase.com/events?zipCode='+userInputZip+'&api_key=[inserted my key here]'. What else did you expect to happen?
That's like saying var x = 10; and expecting it to magically change when you call a function.
What you have to do is move the whole var getJambaseData = {...} initialization into runAjax function and it should fix it. Or you could skip the variable initialization part and just pass the part inside {...} (including the curly braces obviously) inside the $.ajax call instead of variable. If you look at jQuery docs you'll see that in most examples and it's the usual syntax.
Not related to your question, but here are some friendly words of advice:
Don't use variable before you define it (reading top to bottom), it will save you a lot of headaches.
Another recommendation is don't use so much global variables, you could get the userInputZip inside findShows function and pass it to runAjax as function argument. If you'll develop applications in a way where you rely on global state a lot, you'll have a bad time very soon.
Well, i understand my question is a little bit strange and the answer seems obvious ("it's impossible !"), but, as JS is a very open language, i go on anyway :)
Let's say, we have the following code :
function dummy() {
}
var obj = new dummy();
var result = obj.aFunction('a','b');
Obviously, the JS interpretor says :
obj.aFunction is not a function
I understand his anger :) but is there a trick to bypass the interpretor (or something like that) or to create on-the-fly the aFunction function into the obj object before the interpretor evaluates all the stuff ?
I've red all about using dynamic function names and so on (using eval() and other tricks) but that don't solve my (weird) problem ...
Thanks in advance.
EDIT : Well, folks, thanks for your answers, but it's not my problematic.
In fact, i used to code in Java with AOP and what i want is :
Create a Valve (or something like this) that catches all the exceptions
Analyse the exception
if the exception corresponds to my 'no function' error, i create from scratch the function and execute it
I garbage this exception
if it's not the good exception i let it to continue its job
Unfortunatly, You cannot do that in JS. Using an ExceptionHandler is not sufficient because its API is too poor ...
But, Thanks to all ...
There are many ways to achieve this. Here is one:
function dummy() {
}
dummy.prototype.aFunction = function (a, b) {
alert(a + ', ' + b);
};
var obj = new dummy();
var result = obj.aFunction('a','b');
Here is a working example. Warning: it will pop up an alert box.
http://jsfiddle.net/X4F67/
Here is another, if you don't know the function name at runtime:
var name = 'aFunction';
function dummy() {
}
dummy.prototype[name] = function (a, b) {
alert(a + ', ' + b);
};
var obj = new dummy();
var result = obj[name]('a','b');
Fiddle: http://jsfiddle.net/X4F67/1/
Note that both of these affect the dummy prototype itself, so all instances of dummy would contain aFunction. If you instead want to work directly on the obj, you could use something like this:
...
var obj = new dummy();
obj[name] = function () { };
You can create a function on the fly, your code just has some issues.
First of all, setting:
var result = obj.aFunction('a','b');
Is making the browser think that obj.aFunction is an existing function that you are calling, you have to set the function.
obj.aFunction = function(a,b)
{
alert(a + ' ' + b);
}.bind(obj);
...then you could state:
var result = obj.aFunction;
If you were to say:
var result = obj.aFunction('a', 'b');
...after declaring obj.aFunction, it would be called at that line and alert right away.
Instead, you can do this:
window['result']('a', 'b');
As for declaring a function on the fly, such as writing out a function as a string and using eval() to evaluate the function and append it to a variable, I'm not sure why it doesnt work. This is what I tried:
obj.aFunction = eval("function(a,b){alert(a + ' ' + b);}.bind(obj)");
And I get:
Uncaught Syntax Error: Unexpected token (
Either way, hope that helps.
Sorry for the long winded title, but I think it summaries my problem
I have created a jsfiddle to cut down and create a simplified problem of my dilemma
http://jsfiddle.net/afw6k/3/
<input id="txtA"/>
<!-- after setupOnclick is executed my onlick for txtA should be onclick="someObj.log("Clicked!")"-->
<script>
function someObject(field){
this.field = field;
this.log = function(msg){
if(this.field.value != "") this.field.value += ", ";
this.field.value += msg
}
this.setupOnlick = function(){
field.onlick = function(){//So how do I pass this (as in someObject) to this?
this.log("Clicked!"); //As if I have written someObj.log("Clicked!");
}
}
}
var someObj = new someObject(document.getElementById("txtA"));
someObj.setupOnlick();
</script>
I'm not trying to simply write something to a textbox when clicked, but the above is a simplified version of what I am trying to accomplish here.
Passing this (the object) into an objects functions nested function
Or is there a far better way to accomplish this?
Save this in a variable:
this.setupOnlick = function(){
var theObj = this;
field.onlick = function(){//So how do I pass this (as in someObject) to this?
theObj.log("Clicked!"); //As if I have written someObj.log("Clicked!");
}
}
The value of this is just a value, so it can be copied to another variable. The variable "theObj" will remain in scope of the "click" handler when it runs.