Function changes the value of parameter unexpectedly - javascript

I wrote a function calcNewtonPath with 4 parameters as below. However when i call it, the function changes the value of parameter matA unexpectedly and i can't understand why.
function calcNewtonPath(matA,matB,m,n){
let temp = matA.slice() //i tried this to prevent the unexpected change but it didn't work
for(let i=0;i<m;i++){
temp[i].push(-matB[i])
}
return matrix.solve(temp,m,n)
}
The function solve also changes the value of temp too! But it's a bit complicated so i think i will not put the code here.
Can anyone help me about this?

UPDATED:
.slice() will just do a shallow copy.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/slice
That means for example:
const a = [[1,2,3]]
const b = slice.a();
b[0][1] = 4;
a array will also be changed.
a will be [[1,4,3]] as well as b;
One easy solution would be to make a deep copy of an array:
const deepCopy = JSON.parse(JSON.stringify(array));

Related

Why can I only call this function once?

I am trying to build switches that create an array and have this so far:
const [playgroundFilters, setPlaygroundFilters] = useState([initialF]);
const updateItem = (whichvalue, newvalue) => {
let g = playgroundFilters[0];
g[whichvalue] = newvalue;
setPlaygroundFilters(g, ...playgroundFilters.slice());
console.log(playgroundFilters);
};
When I call up updateItem onPress it works once and every subsequent time I get an error "undefined is not an object evaluating g"
Is there an easy way to fix this?
setPlaygroundFilters expects an array so you would need to call it like that
setPlaygroundFilters([g, ...playgroundFilters.slice()]);
instead of
setPlaygroundFilters(g, ...playgroundFilters.slice());
I'm not sure you actually wants to use .slice() like that here, since it just returns the same (cloned) array.

When assigning the result of an addition to a variable, calculator doesn't work. Why?

I'm experimenting with my very basic Javascript and I found a nice Tutorial on how to make a very basic calculator in JS.
I tried following along with the video but I didn't want to just "copy-paste" what he was writing so I stopped and tried to do what I thought was the logic code...WRONG!
Here the problem
Why this doesn't work?
function addNum() {
let first = document.querySelector('.first').value;
let second = document.querySelector('.second').value;
let result = document.querySelector('.resultt').value;
return result = first + second
}
I tried to assign the input related to the result to a variable but it doesn't work.
But when I do this: (as it was done in the tutorial)
function addNum() {
let first = parseInt(document.querySelector('.first').value);
let second = parseInt(document.querySelector('.second').value);
document.querySelector('.resultt').value=first + second;
}
So without assigning the result to a variable, it works.
Why?
When you do
let result = document.querySelector('.resultt').value;
you're copying the value from the value property to the result variable. There's no ongoing link between them after that, they each just contain the same string. That means later, when you do result = first + second, all you're doing is updating result; that has no effect at all on value.
So you have to assign back to value as you do in your second code block.

Is it good practice to override function parameter value?

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`;
}

Storing a pointer in javascript

Is it possible to keep an object reference without using an holder object in javascript?
Currently when an object gets overridden I sometimes lose the reference to the "current" object state illustrated in the snippet below;
Is there a way to put a "pointer" in an array or not?
EDIT
To the questions asked:
What I have in the objects I have are references to form fields. Some of these are text fields, some of them are textareas, some of them checkboxes.
I wish to keep a map next to the direct referene of what type they are.
basicaly it would be
obj {
this.text1 = createTextField();
this.text1.datepicker();
this.text2 = createTextField();
this.area1 = createArea();
this.check = createCheck();
this.datefields = [this.text1];
this.checkboxes = [this.check];
}
So I can use the datefields/checkboxes array as a checkpoint to validate against which type a field is/should behave.
Currently I use
function datefields() { return [this.text1]; };
But I'd like to know if there's a better way to do this than to intantiate a new array when I need to check it.
I know there is a way with observers to mimic pointer behaviour, and i've fiddled with those and have some good results with that, i'm just curious if there are other ways i'm not aware of.
function myObject() {
this.myvalue = null;
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue = "hello";
}
var x = new myObject();
var elem = document.getElementById('results');
function log(message) {
elem.appendChild(document.createTextNode(message));
elem.appendChild(document.createElement('br'));
}
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
log("calling alter");
x.alter();
log("x.myvalue = "+x.myvalue);
log("x.arr[0] = "+x.arr[0]);
<div id="results"></div>
Simple answer: Only objects (including all subtypes) are passed by reference in JS. All other simple values are copied.
For a bit more detail I would recommend reading You Don't Know JS: Types & Grammer but specifically the section Value vs Reference in Chapter 2:
In JavaScript, there are no pointers, and references work a bit differently. You cannot have a reference from one JS variable to another variable. That's just not possible.
Quoting further on:
Simple values (aka scalar primitives) are always assigned/passed by value-copy: null, undefined, string, number, boolean, and ES6's symbol.
Compound values -- objects (including arrays, and all boxed object wrappers -- see Chapter 3) and functions -- always create a copy of the reference on assignment or passing.
There are plenty of examples included to show these points. I would highly recommend reading through to get a better understanding of how values/references work in JS.
There is no pointers in Javascript, though you could cheat a little using a wrapper object. Here is a minimal implementation of such an object:
var Wrapper = function (value) {
this.value = value;
};
Wrapper.prototype.valueOf = function () {
return this.value;
};
Then you may use it in place of the original value:
function myObject() {
this.myvalue = new Wrapper(null); // wrapper
this.arr = [this.myvalue];
}
myObject.prototype.alter = function() {
this.myvalue.value = "hello"; // notice the ".value"
}
The rest of your code needs no tweaks.

Changing an array without chaining the reference

Maybe I’m going about this all the wrong way, if so, please let me know!
Anyways, say I have an Array representing some nice data.
var orignal = ['a', 'b'];
var copy = orignal;
orignal.push('c');
console.log(original === copy); // true
I kind of like this functionality where the to objects still are the same. Of course if I would set original = ['c'] that would not be the case anymore. Is there any pattern to let me do more things on the array without breaking the link?
Assignment is the one thing that will break the link, because it is an operation on the reference, not the array. It makes the variable refer somewhere else. Anything else you do will be visible through both original and copy:
copy.length = 5; // visible through original
copy[3] = 4; // visible through original
copy.pop(); // visible through original
If you think you want assignment to preserve the link, you should probably instead be doing some similar but distinct operation, such as filling an array with the contents of another.
Incidentally, it's probably a bad idea to call the variable copy, since it's not a copy. It's the original, just like original is.
You should do inheritance :
function inherits(base, extension)
{
for ( var property in base )
{
try
{
extension[property] = base[property];
}
catch( warning ){}
}
}
and then :
var original = ['a', 'b'];
var copy=[]; inherits(original,copy) //NOT : var copy = orignal;
original.push('c');
console.log(original === copy); // false
DEMO : http://jsfiddle.net/abdennour/e64vB/1/

Categories