Why does this Javascript function not work if called twice? - javascript

The Jasmine (unit?) tests I'm running works for all test with my code below, but the last test calls Gigasecond.date() twice, then validates the second one, which fails.
var Gigasecond = function(date) {
this.startDate = date;
};
Gigasecond.prototype.date = function() {
var x = this.startDate;
x.setSeconds(x.getSeconds() + 1000000000);
return x;
}
module.exports = Gigasecond;
I guess I don't know why this fails. When I log to the console I see the date gets incremented twice, but thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object? Is there any reference material for how this works? I looked around but couldn't find anything that applies to what's happening in this code.

You state that you
thought that x is its own separate variable that gets created/destroyed each time the function is called.. but it seems not. Is x just a reference to the actual .startDate field on the object?
That is correct. Dates are objects, and in JavaScript, objects are assigned to variables by reference, not copy. If you intend to work with a copy, you need to return a clone of the Date object with new Date(dateToBeCopied.getTime()) first.
In your code, if you want to work on a copy of the date, you need to replace the line
var x = this.startDate; //assignment by reference
with this line
var x = new Date(this.startDate.getTime()); //assignment by copy
The example code below demonstrates how this works. The Date Object dateA is assigned to the variable refA by reference and to the variable copyA by copy. When modifying refA, this affects dateA, whereas copyA is unaffected.
var dateA = new Date();
//assign a reference to dateA
var refA = dateA;
//assign a copy of dateA
var copyA = new Date(dateA.getTime());
//modify refA, increment with one year
refA.setFullYear(refA.getFullYear() + 1);
//variable refA points to dateA,
//both show the date incremented with one year
console.log('+1 year: ', dateA);
console.log('+1 year: ', refA);
//variable copyA returns an unmodified copy,
//not incremented
console.log('unmodified copy: ', copyA);

Related

javascript variable shows in console.log but not in browser output

I am trying to reuse the output of the year variable.
I will need to reuse the updated value [based on hashchange] in multiple functions later on.
It displays the correct value in the browser console, but it doesn't display in the browser.
<html>
<body>
<p></p>
1
2
</body>
<script>
location.hash = '#2019';
showHash();
var p = document.querySelector('p');
p.innerHTML = window.year;
function showHash() {
return year = location.hash;
}
window.onhashchange = showHash;
</script>
</html>
By assigning location.hash to year you are not modifying p.innerHTML. year and p.innerHTML are not referencing each other's value. When you initialised as follows:
p.innerHTML = window.year;
The value of year was copied so now you have two values which happen to be the same at that moment, but they are not linked so that if you would assign a new value to the one, it would also update the other. No, they are not references.
So in the event handler you should also assign the new hash to p.innerHTML, or better -- as the hash is text -- assign it to p.textContent:
var p = document.querySelector('p');
var year;
function showHash() {
// Assign both to textContent and year (they are independent)
p.textContent = year = location.hash;
// Maybe call some other functions which need to know about `year`
manage();
}
function manage() {
console.log(year);
// ... etc
}
window.onhashchange = showHash;
location.hash = '#2019'; // This triggers showHash, no need to call it explicitly
<p></p>
1
2

Javascript push keeps deleting first item

I have very strange problem. I am creating an array of date objects (mondays)
// array to hold week commencing dates
var mondays = [];
mondays.push(today);
var novi = new Date(today);
while(novi < endDate){
var next_monday = new Date(novi.setDate(novi.getDate() + 7));
day_index = next_monday.getDay();
if(day_index == 1){
mondays.push(next_monday);
}
// increment the date
novi = next_monday;
}
console.log(mondays);
UPDATE: Thanks for reply. I created new object at start and used that one.So again i am creating empty array, then adding one date to it before starting loop, then first item in loop doesnt get added, even tho it gets pushed. What am i doing wrong?
This is console.log that i am getting from above.
https://www.dropbox.com/s/04bckfcrwl7yvwd/Screenshot%202016-09-28%2018.29.25.png?dl=0
today.setDate(today.getDate() + 7)
You are modifying the date object you pushed into the array.
The first item isn't being deleted, it is being changed.
var next_monday = new Date(today.setDate(today.getDate() + 7));
Then you create a new date object from it.
Create the new date object first, then modify that.

SAPUI5 jQuery.sap.storage variable saving

In my application I have a function for a synchronisation in which I take two timestamps, at the start and the end, to get the time spent while synchronizing.
I want to save this variable into the local storage.
After that I need to compare the variable coming from the function with the variable from the function and get the average of them.
I know the storage is a key-value type, I still have problems getting this work. The function is posted below. Thanks for every possible help.
handleSyncPress: function() {
new Date().getTime();
var syncStart = Math.floor(Date.now() / 1000);
var that = this;
var fUpdateBindings = function() {
that.getView().getModel().refresh(true);
}
test.mp.Offline.sync(fUpdateBindings);
new Date().getTime();
var syncEnd = Math.floor(Date.now() / 1000);
var syncTime = syncEnd - syncStart;
this._oStorage = jQuery.sap.storage(jQuery.sap.storage.Type.local);
this._oMyData = this._oStorage.get(syncTime);
this._oStorage.put(syncTime, this._oMyData);
}
As you can see I'll started the initialisation of the storage already at least.
As I said in a comment in your other question, the storage is something like a dictionary that stores key-value-pairs.
The key is the identifier that you will use to access your value later.
The value can be anything: Numbers, Strings, Bools, Arrays, Objects, you name it.
Imo the best solution would be to store all your sync times in a single value (i. e. an array of sync times).
handleSyncPress: function() {
// get current timestamp
var syncStart = Date.now();
// do stuff
var fUpdateBindings = function() {
that.getView().getModel().refresh(true);
}
test.mp.Offline.sync(fUpdateBindings);
// get another timestamp
var syncEnd = Date.now();
// diff between the timestamps is the sync time (in milliseconds)
var syncTimeInMilliseconds = syncEnd - syncStart;
this._oStorage = jQuery.sap.storage(jQuery.sap.storage.Type.local);
// load value for the key "syncTimes"
var aSyncTimes = this._oStorage.get("syncTimes");
aSyncTimes = JSON.parse(aSyncTimes); // may not be needed
// if this is the first time you access the key, initialize the value
if (aSyncTimes === null) {
aSyncTimes = [];
}
// append your new sync time
aSyncTimes.push(syncTimeInMilliseconds);
// store your sync time array
aSyncTimes = JSON.stringify(aSyncTimes); // may not be needed
this._oStorage.put("syncTimes", aSyncTimes);
// hopefully you already know how to calculate the avg value from an array of integers
// if not: avg = sum / length
}
Edit: According to the API, only strings are supported as values. I tried other types, and they worked, but it might be safest to (de)serialize the data. I updated the code example.
The line
this._oMyData =this._oStorage.get(syncTime);
will return nothing in your case, right? This is because you did not store a value before this call. Furthermore, I guess you should use a String for key...
Using SAPUI5 for accessing the localStorage would work like this:
// get an instance of jQuery.sap.storage.Storage
var oStorage = jQuery.sap.storage(jQuery.sap.storage.Type.local);
//...
// Store
var syncTime = ...;
oStorage.put("syncTime", syncTime);
// Read
var syncTime = oStorage.get("syncTime");
However, I prefer to use native JavaScript APIs, i.e. see http://www.w3schools.com/html/html5_webstorage.asp:
// Store
var syncTime = ...;
localStorage.setItem("syncTime", syncTime);
// read
var syncTime = localStorage.getItem("syncTime");
The key should be string...

Date display with javascript

my instructions are to Include a function defined via a function
expression that displays the current date and time in an h2 at the top of the
page when the page is opened. Add an id=”dateDisplay” to the h2. Include
a self-invoking function that changes the color of the date text that was
printed by the first function.
Im a bit confused on how to accomplish this. I tried to do a function expression to display the date but i get nothing shown and no errors. I tried to do a body onload to call the function but that result in a console error of function not defined.
HTML
<div>
<h2 id="dateDisplay"></h2>
</div>
Javascript
var d = new Date();
var x = function dateDisplay(){
document.getElementById("dateDisplay").value = d;
}
I'm really confused by the instructions. What exactly am I suppose to do to get this in working order.
edited: I had an error with my link to my js file. The issue now is I get console error document.getElementById... is null weather i use innerHTML or value or .innerText
You need to call your function, and use .innerText and not .value. Note value is only for input elements.
var d = new Date();
var x = function dateDisplay(){
document.getElementById("dateDisplay").innerText = d;
}
x();
You can also use the .innerHTML method like so:
var d = new Date();
var x = function dateDisplay(){
document.getElementById("dateDisplay").innerHTML = d;
}
x();
You also forgot to call the function x
you must use this code :
Javascript:
var d = new Date();
var x = function dateDisplay(){
document.getElementById("dateDisplay").innerHTML = d;
}
x();
To "display data" in HTML, (in most cases) you will set the value of an innerHTML property.after this change you must call x() function .
and you hava to use this after dateDisplay element loaded.
call function directly more prefer than assign to variable function
var d = new Date();
dateDisplay();
function dateDisplay(){
document.getElementById("dateDisplay").innerHTML = d;
}

Javascript - create array between two date objects

Question
I am attempting to build an array between two JS objects. It appears that my objects are being created correctly, and in fact that the code below is running.
The unexpected behavior is that every object in my output array is transforming to match the last date that I looped through. i.e. if I loop, whatever my todate_dateobjis, I get an entire array of just that value.
I have to do some debugging wrt the actual start/end dates being correct, but I can handle that -- what I'm stymied by is the behavior described above.
I am very new to javascript. I imagine this is some issue with mutation? Any guidance would be appreciated.
I left the console logs in just because why take them out?
Code
function build_dateobjs_array(fromdate_dateobj, todate_dateobj) {
// return an array of dateojects from fromdate to todate
var current_date = fromdate_dateobj;
var return_array = []
while (current_date <= todate_dateobj) {
return_array[return_array.length] = current_date; // I have read that this is generally faster that arr.push()
var tomorrow = new Date(current_date.getTime() + 86400000);
console.log('tomorrow: ', tomorrow);
current_date.setTime(tomorrow);
console.log('current_date: ', current_date)
console.log("build_dateobjs_array : ", return_array);
};
return return_array;
};
Date objects are mutable. This line:
current_date.setTime(tomorrow);
...changes the state of the Date object that current_date refers to, which you never change.
So you're storing the same object repeatedly in return_array. Instead, make a copy of the Date:
return_array[return_array.length] = new Date(+current_date);
Also, it's probably best to change
var current_date = fromdate_dateobj;
to
var current_date = new Date(+fromdate_dateobj);
so you're not modifying the Date that was passed in.
Side note: There's no need for the round-trip to milliseconds, simply:
function build_dateobjs_array(fromdate_dateobj, todate_dateobj) {
// return an array of dateojects from fromdate to todate
var current_date = new Date(+fromdate_dateobj);
var return_array = [];
while (current_date <= todate_dateobj) {
return_array[return_array.length] = new Date(+current_date);
current_date.setDate(current_date.getDate() + 1);
};
return return_array;
}
(There's also no reason to put a ; at the end of a function declaration.)

Categories

Resources