There is something wrong with my code, but I can't find what it is. The first time I call registerStartDateValidation, the value of the startDateValidation variable in the defineKeyword closure is of course the same than what was affected outside the closure. But the second time, the variable is reaffected with another value, but the value of startDateValidation in the defineKeyword is still equal to the value of the first time we call registerStartDateValidation. Does the closure cache the variable?
Tv4.prototype.registerStartDateValidation = function (attributes) {
var helper = this;
var dateNames = Object.keys(attributes);
var startDateName = dateNames[0];
var startDateString = attributes[startDateName];
var endDateName = dateNames[1];
var endDateString = attributes[endDateName];
var startDateValidation = helper.startDateValidation(startDateString, startDateName, endDateString, endDateName);
console.log(startDateValidation)//First time equal "true", second time equal "false"
tv4.defineKeyword('startDate', function (data, value) {
if (value === 'startDate') {
console.log(startDateValidation)//First time equal "true", second time still equal "true"
return startDateValidation
}
});
};
Note that there is nothing making an ajax request, that could mess up the order the functions are called.
Short answer: no, a closure won't cache the variable, so there is something else going on in your code. Reducing the problem to a simple complete example that demonstrates the problem will usually make it obvious where the problem is coming from, or at least help other people figure it out.
However, since it looks like you're referring to is this project, it may be possible to figure out what's going on. Tv4.defineKeyword() appends new functions to a list if it is called multiple times for the same keyword. Since you're calling tv4.defineKeyword (note the lower-case 't') and not helper.defineKeyword or this.defineKeyword, it looks like each call to registerStartDateValidation will affect the same instance, so you are almost certainly adding a validation function when you meant to replace it.
Related
In JavaScript consider I am trying to append a new value and return it.
I have below example regarding overriding parameter value
The below function receives a string value as param and overriding the param with new value and returning it.
function test(value) {
value = value + "hi";
return value;
}
console.log(test("Hello"));
The below function receives a string value as param. I would like to append a new value and return it. So I assigned value to a local variable and then appended strong to a new variable and returning it.
function test(value) {
let temp = value;
temp = value + "hi";
return temp;
}
console.log(test("Hello"));
I am calling it and passing value
test(“Hello”);
Which one is recommended from above?
It's purely a matter of style. Some people think you should leave parameter values alone, others think it's fine to change them.¹
From a practical perspective, it doesn't cause any harm. That is, there is no hidden side-effect to doing so. In particular, since JavaScript is purely pass-by-value, reassigning the parameter can't have any effect on whatever argument was used to fill in that parameter:
function test(value) {
value = value + "hi";
return value;
}
let a = "let's say ";
let b = test(a);
console.log(b); // "let's say hi"
console.log(a === b); // false, `a` was not modified
Your version with temp can be simpler, though:
function test(value) {
let temp = value + "hi";
return temp;
}
(or even
function test(value) {
return value + "hi";
}
but I figure it's highly simplified for the question.)
¹ (I happen to be in the latter camp, but that's neither here nor there.)
Yes, this is not at all wrong and is often done by many programmers across many languages. It is a common practice.
You can use it in cases where you want to use the parameter value inside the function but after making certain modifications to it.
For example, I might want to add two numbers using a function add(a, b) where a and b can be strings or integers or floats.
But just to be sure about it, I can define the add function in the following way:
function add(a,b) {
a = parseFloat(a);
b = parseFloat(b);
return a + b;
}
and this is perfectly fine. This way I can be always sure that there will be no exceptions thrown or in case parameters were passed as strings, it doesn't returns 12 (if I said add(1,2)) when really it should have been 3.
By making parameter overriding a common practice and incorporating it into your coding style, you spare the browser from creating or defining new variables just to modify those variable values. This might not mean much in small applications, but in large scale heavy applications, it might make a noticeable difference especially on low end devices.
The short answer is: it's only a matter of style.
However, this isn't always right. When passing objects, they will be passed by reference, meaning that every change you'll make to the parameter will affect the original object:
const obj = {originalValue: true};
function modifyObject(input) {
input.originalValue = false; // The change happens here
return input; // So it will take place regardless of this line
}
console.log('before:', obj);
modifyObject(obj); // See? we don't even retrieve the return value
console.log('after:', obj);
If we were talking about Java, then creating a new variable would be good practice. As there is something called the Garbage Collector that collects unused variables, etc. and discards them. So keeping a link to the original variable wouldn't allow the collector to discard the variable. (I read this somewhere, but some people said to me it doesn't really work this way, so read more about this online if you want)
In JavaScript, however, it doesn't really matter. It depends on you. Your style. It also depends on the situation as it can be useful sometimes. But really it doesn't really matter. Do as you like.
If you want to simplify it you can do as #T.JCrowder said:
function test(value){
return value+ “hi”;
}
That's about it.
Using ES6 Template literals
function test(value){
return `${value} hi`;
}
Good Day,
I am working on a pet project using NodeJS and Electron. It is basically a simple text editor at the moment. However I am running into an issue when trying to pass the value of a text-area to a function prior to saving to file.
Specifically when I call a function in another module, the value of the contents becomes 'undefined'. I suspect I am passing it incorrectly, or that it is being over-written between when I make the call and when the call executes, since strings are supposed to be passed by reference.
The code for the Renderer(index.html) is like this :
let otherModule = require('./js/otherModule.js');
let $ = require('jquery');
$('#btn_Save').on('click',() => {
// get the fileName, if empty propmt user with save dialog,
//log it to console for debugging
var contents = $('#txt_Content').val();
console.log('with:',contents.substring(0,9),'...');
var finalContents = contents; // (create a copy?)
if(//someConditionMet//)
{
var otherVar = $('#txt_Other').val();
console.log('Use:',otherVar.substring(0,9),'...');
finalContents = otherModule.someFunc(contents, otherVar);
}
//do something with final contents.
})// end of On-click
I have used console.log() to extensively evaluate the function and can confirm that up to the call to otherModule, the contents are correct, and match those in the textArea.It is once we are in the 'otherModule' that things go awry.
The code for the otherModule is like this:
const someFunc = function(contents, otherVar)
{
console.log('DoThings with:',contents.substring(0,9),'...');
// print shows the value to be undefined...
// do more things
console.log('Did stuff with otherVar:',otherVar.substring(0,9),'...');
// prints just fine as as expected.
// do more things
return someString;
}
module.exports = {
someFunc: someFunc
}
As mentioned in the comment, the very first line of the function logs the contents of the console, which displays the substring as 'undefined'.
Thank you for your time and your consideration!
// Extra context//
I have done some searching but beyond learning that strings are passed by reference and are immutable, I have not seen an answer to a question like this. There has been some discussion of closure issues, but usually in the context of events and callbacks, which I do not believe is the context here.
// Extra Information//
I have since found a solution to get my parameters to pass correctly. I have posted the answer below. I did two things:
1. Changed the function definition from 'const' to 'let'
2. Changed the order of the params, and removed the space following the comma.
If you get the value inside the if you should be fine.
if(//someConditionMet//)
{
var contents = $('#txt_Content').val(); //New line
var otherVar = $('#txt_Other').val();
console.log('Use:',otherVar.substring(0,9),'...');
finalContents = otherModule.someFunc(contents, otherVar);
}
I have found a solution to this problem. I am not certain why it makes a difference but I changed two things in 'otherModule'.
1. I changes the function from 'const' to 'let'
2. I changed the order of the parameters, removing the space after the comma
The new function header looks like:
let someFunc = function(otherVar,contents) {...}
I also updated the call to match the new order ( given):
finalContents = otherModule.someFunc(otherVar,contents);
I hope this helps someone in the future!
Here's a function I have written to add words to local storage using Javascript. In case you're wondering, this is my attempt at building a search history functionality for a simple dictionary lookup site.
function add2local(entry){
var l = localStorage.length;
if(l==0){
var lu = [entry];
localStorage.setItem("w", JSON.stringify(lu));
}
else {
var lu = JSON.parse(localStorage.getItem("w")); alert(lu);
lu.push(entry); alert(lu);
}}
My understanding is the this function would keep appending its argument to local storage every time it's called. So, the first time I call it, I send it the word pirate. This gets added to the array and subsequently to the local storage as expected. The first alert() (the alert() functions are solely being used for testing) confirms this. The second time, I call it with the word vampire. Now, going by the function's logic, vampire should be appended to the array and thus the second alert() should output "pirate, vampire." And so it does.
But the third time around, say, I call the function with the word foo. This time around, it should output "pirate, vampire, foo" but instead shows "pirate, foo". Every subsequent call simply replaces the second word with the new word instead of appending it. What might I be doing wrong here? Am I misunderstanding how push() works?
The if condition and logic is incorrect; it is irrelevant how many items localStorage has, but it is very important to re-save the modified array.
In any case, I suspect an impl. might look as so:
function add2local(entry){
// load entries - if there are none, we simulate an empty array to load
var lu = JSON.parse(localStorage.getItem("w") || "[]");
// add new entry
lu.push(entry);
// write back - so change is not lost between function calls
localStorage.setItem("w", JSON.stringify(lu));
// return all local entries saved - for use from the caller
return lu;
}
Why check the storage length? You don't care. Fetch the key and if it's null then default to empty array.
function add2local (entry) {
var key = "w"
var value = localStorage.getItem(key)
if (value) {
value = JSON.parse(value)
} else {
value = []
}
value.push(entry)
localStorage.setItem(key, JSON.stringify(value))
}
Is it possible to find the name of an anonymous function?
e.g. trying to find a way to alert either anonyFu or findMe in this code http://jsfiddle.net/L5F5N/1/
function namedFu(){
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var anonyFu = function() {
alert(arguments.callee);
alert(arguments.callee.name);
alert(arguments.callee.caller);
alert(arguments.caller);
alert(arguments.name);
}
var findMe= function(){
namedFu();
anonyFu();
}
findMe();
This is for some internal testing, so it doesn't need to be cross-browser. In fact, I'd be happy even if I had to install a plugin.
You can identify any property of a function from inside it, programmatically, even an unnamed anonymous function, by using arguments.callee. So you can identify the function with this simple trick:
Whenever you're making a function, assign it some property that you can use to identify it later.
For example, always make a property called id:
var fubar = function() {
this.id = "fubar";
//the stuff the function normally does, here
console.log(arguments.callee.id);
}
arguments.callee is the function, itself, so any property of that function can be accessed like id above, even one you assign yourself.
Callee is officially deprecated, but still works in almost all browsers, and there are certain circumstances in which there is still no substitute. You just can't use it in "strict mode".
You can alternatively, of course, name the anonymous function, like:
var fubar = function foobar() {
//the stuff the function normally does, here
console.log(arguments.callee.name);
}
But that's less elegant, obviously, since you can't (in this case) name it fubar in both spots; I had to make the actual name foobar.
If all of your functions have comments describing them, you can even grab that, like this:
var fubar = function() {
/*
fubar is effed up beyond all recognition
this returns some value or other that is described here
*/
//the stuff the function normally does, here
console.log(arguments.callee.toString().substr(0, 128);
}
Note that you can also use argument.callee.caller to access the function that called the current function. This lets you access the name (or properties, like id or the comment in the text) of the function from outside of it.
The reason you would do this is that you want to find out what called the function in question. This is a likely reason for you to be wanting to find this info programmatically, in the first place.
So if one of the fubar() examples above called this following function:
var kludge = function() {
console.log(arguments.callee.caller.id); // return "fubar" with the first version above
console.log(arguments.callee.caller.name); // return "foobar" in the second version above
console.log(arguments.callee.caller.toString().substr(0, 128);
/* that last one would return the first 128 characters in the third example,
which would happen to include the name in the comment.
Obviously, this is to be used only in a desperate case,
as it doesn't give you a concise value you can count on using)
*/
}
Doubt it's possible the way you've got it. For starters, if you added a line
var referenceFu = anonyFu;
which of those names would you expect to be able to log? They're both just references.
However – assuming you have the ability to change the code – this is valid javascript:
var anonyFu = function notActuallyAnonymous() {
console.log(arguments.callee.name);
}
which would log "notActuallyAnonymous". So you could just add names to all the anonymous functions you're interested in checking, without breaking your code.
Not sure that's helpful, but it's all I got.
I will add that if you know in which object that function is then you can add code - to that object or generally to objects prototype - that will get a key name basing on value.
Object.prototype.getKeyByValue = function( value ) {
for( var prop in this ) {
if( this.hasOwnProperty( prop ) ) {
if( this[ prop ] === value )
return prop;
}
}
}
And then you can use
THAT.getKeyByValue(arguments.callee.caller);
Used this approach once for debugging with performance testing involved in project where most of functions are in one object.
Didn't want to name all functions nor double names in code by any other mean, needed to calculate time of each function running - so did this plus pushing times on stack on function start and popping on end.
Why? To add very little code to each function and same for each of them to make measurements and calls list on console. It's temporary ofc.
THAT._TT = [];
THAT._TS = function () {
THAT._TT.push(performance.now());
}
THAT._TE = function () {
var tt = performance.now() - THAT._TT.pop();
var txt = THAT.getKeyByValue(arguments.callee.caller);
console.log('['+tt+'] -> '+txt);
};
THAT.some_function = function (x,y,z) {
THAT._TS();
// ... normal function job
THAT._TE();
}
THAT.some_other_function = function (a,b,c) {
THAT._TS();
// ... normal function job
THAT._TE();
}
Not very useful but maybe it will help someone with similar problem in similar circumstances.
arguments.callee it's deprecated, as MDN states:
You should avoid using arguments.callee() and just give every function
(expression) a name.
In other words:
[1,2,3].forEach(function foo() {
// you can call `foo` here for recursion
})
If what you want is to have a name for an anonymous function assigned to a variable, let's say you're debugging your code and you want to track the name of this function, then you can just name it twice, this is a common pattern:
var foo = function foo() { ... }
Except the evaling case specified in the MDN docs, I can't think of any other case where you'd want to use arguments.callee.
No. By definition, an anonymous function has no name. Yet, if you wanted to ask for function expressions: Yes, you can name them.
And no, it is not possible to get the name of a variable (which references the function) during runtime.
Below is my code fragment:
<div onclick = "myClick('value 1')">
button 1
</div>
<div onclick = "myClick('value 2')">
button 2
</div>
Basically when I for each click on a different div, a different value will be passed to the JavaScript function.
My Question is how can I keep track of the value passed in the previous click?
For example, I click "button 1", and "value 1" will be passed to the function. Later, I click on "button 2", I want to be able to know whether I have clicked "button 1" before and get "value 1".
Just add it to a variable in your script:
var lastClicked;
var myClick = function(value) {
lastClicked = value;
};
You can define somekind of variable, like var lastUsed;
add additional line to your function:
var lastUsed = null;
function myClick(value){
prevClicked = lastUsed; //get the last saved value
...
lastUsed = value; //update the saved value to the new value
...
}
And here you go
You need a variable. Variables are like little boxes in which you can store values. In this case, we can store the value that was last passed to the function myClick.
In Javascript, you can define a variable like this:
var lastClickedValue;
You can "put" a value into that variable. Let's say you want to put your name in there. You would do this:
lastClickedValue = 'sams5817';
Now here's the tricky bit. Variables have "scope". You might want to think about it as their "life-time". When a variable reaches the end of its scope, you cannot read or write to it anymore. It's as if it's never been. Functions define a scope. So any variable you define in a function will disappear at the end of the function. For example:
function myClick(value)
{
var lastClickedValue;
alert('lastClickedValue is = ' + value);
lastClickedValue = value;
}
That looks almost right, doesn't it? We declared a variable, display its last value, and update it with the new value.
However, since the lastClickedValue was declared in the function myClick, once we've reached the end of that function, it's gone. So the next time we call myClick, lastClickedValue will be create all over again. It will be empty. We call that an "uninitialized" variable.
So what's the problem? We're trying to remember a value even after the end of myClick. But we declared lastClickedValue inside myClick, so it stops existing at the end of myClick.
The solution is to make sure that lastClickedValue continues to exist after myClick is done.
So we must delcare lastClickedValue in a different scope. Luckily, there's a larger scope called the "global scope". It exists from the moment your page loads, and until the user moves on to another webpage. So let's do it this way:
var lastClickedValue;
function myClick(value)
{
alert('lastClickedValue is = ' + value);
lastClickedValue = value;
}
It's a very small difference. We moved the declaration of the variable lastClickedValue to be outside the function myClick. Since it's outside, it will keep existing after myClick is done. Which means that each time we call myClick, then lastClickedValue will still be there.
This will let you know what the last value passed to myClick was.
Finally, I'd like to advise you to look for some kind of Javascript tutorials. I wish I knew of some good ones to recommend, but I'm certain you can find a few on the Internet. If you try to write programs before understanding what you're doing, you'll find yourself producing work that is less than what you're capable of. Good luck!
I suppose you need something like this
var clickedButtons = [];
function myClick(value){
...
clickedButtons.push(value);
...
}
I am surprised that no one else mentioned this, but since functions are first class objects in JavaScript, you can also assign attributes and methods to functions. So in order to remember a value between function calls you can do something like I have with this function here:
function toggleHelpDialog() {
if (typeof toggleHelpDialog.status === 'undefined')
toggleHelpDialog.status = true;
else
toggleHelpDialog.status = !toggleHelpDialog.status;
var layer = this.getLayer();
if (toggleHelpDialog.status) layer.add(helpDialog);
else helpDialog.remove();
layer.draw();
}
Here I have added an attribute named 'status' to the toggleHelpDialog function. This value is associated with the function itself and has the same scope as the toggleHelpDialog function. Values stored in the status attribute will persist over multiple calls to the function. Careful though, as it can be accessed by other code and inadvertently changed.
we can leverage javascript static variables
One interesting aspect of the nature of functions as objects is that you can create static
variables. A static variable is a variable in a function‘s local scope whose value persists across
function invocations. Creating a static variable in JavaScript is achieved by adding an instance
property to the function in question. For example, consider the code here that defines a function
doSum that adds two numbers and keeps a running sum:
function doSum(x,y){
if (typeof doSum.static==='undefined'){
doSum.static = x+y;
}else{
doSum.static += x+y;
}
if (doSum.static >= 100){doSum.static = 0;doSum.static += x+y;}
return doSum.static;
}
alert(doSum(5,15))
alert(doSum(10,10))
alert(doSum(10,30))
alert(doSum(20,30))