JavaScript Sets lost reference but don't change size - javascript

I'm storing objects references inside my JavaScript Sets:
let set1 = new Set();
let obj = {};
Then if I use the has() method and the size property of the Set objects I get the next results:
console.log(set1.size) //it returns 1
console.log(set1.has(obj)) //it returns true
But, if I remove the reference of the object using the next code:
obj = null;
Then strange behaviour happens to me:
console.log(set1.size); //it returns 1 because they are Hard Sets.
console.log(set1.has(obj)); //it returns false
In the last line, why does it return false if the size is not changed? Then the reference is lost but the size is not changed.

In the last line, why does it return false if the size is not changed?
It returns size = 1 because it still holds one value (a reference to that object).
It returns false because it does not has a value that is equals to null.
But, if I remove the reference of the object using the next code:
You just overwrite a value of the variable. After that there is still one reference to the object left (inside the Set).
To remove an element from a Set you need to use Set.prototype.delete() method:
set1.delete(obj);
Presumably you need to do that while obj still holds a reference to the object.

When you override the value of obj:
obj = null;
You are only changing the value of obj, not of the Set entry, which still holds a reference to the object that was originally assigned to obj.
So the current state is:
obj: null
set1: [
{} // the object assigned to obj
]
So your line
console.log(set1.has(obj));
actually tests, if set1 contains null:
console.log(set1.has(null));
which is of course false (as it only contains the object).
To actually delete the object from the set, you can use:
set1.delete(obj);
You could also use a weakSet, if the reference in the set in only used as long as the reference to that object still exists somewhere else.

Related

javascript variable changing value after changes in original variable

I am having trouble maintaining the original value of a variable after making new changes to the original variable.
Code:
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_base = data
let ca_base = data.ca
let kwh_base = data.kwh
let pi_base = data.pi
(...)
data = Illumination.calculate_N(data)
data = Illumination.calculate_pi(data)
data = Illumination.calculate_kwh(data)
data = Illumination.calculate_ca(data)
let data_proposto = data
let ca_proposto = data.ca
let kwh_proposto = data.kwh
let pi_proposto = data.pi
-----------------------------------
EXAMPLE:
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
It was expected that the original variable (date) would have its values ​​changed, and this happens correctly, however, the variables data_base and data_proposto are not keeping their values
Both variables at the end of the calculation have the same values ​​as the variable date
The variables ca_proposto, ca_base, and the like store their values ​​correctly
Any idea?
The only interactions of the variables data_base and data_proposto were their creations with the data variable and their return of the function
OBS: If I use console.log () to view the value of the data_base variable before redoing the new calculations (Illumination.calculate_N (data)), the value of the variable appears correctly as it should, it is changed shortly after these calculations.
Because in both cases you are assigning not the object itself in the current state, but a reference to that object. What you need to do is to clone the object so the state is frozen at that point.
Simple Clone (Shallow Copy)
let data_base = Object.assign({}, data); //you get a clone of data
let data_proposto = Object.assign({}, data);
The limitation here is that it only does a shallow copy. See Deep Copy below for further explanation.
JSON Clone
This is a quick-and-dirty way to clone as it converts a JSON object to a string, and then back. i.e. you are no longer getting a reference, but a new object.
let data_base = JSON.parse(JSON.stringify(data));
let data_postero = JSON.parse(JSON.stringify(data));
But this won't work if your object is not JSON-safe.
Deep Copy
The least elegant method is probably safest. It deep copies the properties over into a new object. The key difference with Object.assign() is that it copies the values of nested properties, whereas Object.assign() copies the reference to nested objects.
So with Object.assign() any subsequent changes in your nested objects will affect all versions of your "clones". This won't happen if your clones only have property values of those nested objects at the time of cloning – these values are not affected by any changes to the nested objects.
const deepCopy = function(src) {
let target = {};
// using for/in on object also returns prototype properties
for (let prop in src) {
// .hasOwnProperty() filters out these prototype properties.
if (src.hasOwnProperty(prop)) {
target[prop] = src[prop]; //iteratively copies over values, not references
}
}
return target;
}
let data_base = deepCopy(data);
let data_postero = deepCopy(data);
#chatnoir Defined the problem very well, But I do not agree with his JSON serialization solution due to the below probleam:
You will lose any Javascript property that has no equivalent type in
JSON, like Function or Infinity. Any property that’s assigned to
undefined will be ignored by JSON.stringify, causing them to be missed
on the cloned object.
My suggestion to perform deep copy is to rely on a library that’s well
tested, very popular and carefully maintained: Lodash.
Lodash offers the very convenient clone and deepclone functions to perform shallow and deep cloning.
Lodash has this nice feature: you can import single functions separately in your project to reduce a lot the size of the dependency.
Please find the running sample code here: https://glitch.com/edit/#!/flavio-lodash-clone-shallow-deep?path=server.js:1:0
You are using the same variable data inside and outside functions.
ie; data is in the global scope.
static calculate_ai(data){
data.ai = data.areaTotal*data.au
return data
}
even though you are expecting the scope of the variable data inside the method calculate_ai to be limited to that method, it is not the case. data is in global scope and therefore, the value changes inside the method for the variable affects outside as well.
An effective solution is to use a different variable inside the method.
A variable is like an octopus tentacle, and not as a box (as it’s commonly described). In this analogy, the variable's name can be thought of as the name of a tentacle.
A variable (tentacle) holds on to a value in what’s called a binding. A binding is an association of a variable to a value: x = 1.
In JavaScript, if a variable b holds on to variable a, changing the value to which variable a holds onto, will change the value to which variable b holds onto, as b and a are referencing to the same value:
let a = {key: 1}
let b = a
console.log(`a: ${a.key}`) // -> 1
console.log(`b: ${b.key}`) // -> 1
a.key = 2
console.log(`a: ${a.key}`) // -> 2
console.log(`b: ${b.key}`) // -> 2
a = {key: 3} // This will point variable 'a' to a new object, while variable 'b' still points to the original object.
console.log(`a: ${a.key}`) // -> 3
console.log(`b: ${b.key}`) // -> 2

quicksort algorithm javascript [duplicate]

Why the two scripts behave differently? I want the to use the first script, but in the second drawData() call it changes data; it's weird and not what I want to happen. The second script does not have this problem. Why is it like that, and how can I fix the first script?
First script does not change data:
var data = ["right"];
function drawData(arrs, type) {
if (type == "percentage") {
arrs[0] = "omg";
}
console.log(data[0]); // Changed!?
}
drawData(data);
drawData(data, "percentage");
Second script:
var data = "right";
function drawData(arrs, type) {
if (type == "percentage") {
arrs = "omg";
}
console.log(data); // OK, not changed.
}
drawData(data);
drawData(data, "percentage");
This is the difference between assignment to a local variable and mutation of the given object.
In both pieces of code arrs is a local variable, distinct from data. But the elements and other properties of arrs are exactly the same as those of data. Making changes to those property values (which is commonly called mutation of the object/array) will be visible whether you access them via arrs or via data. And this is exactly what the first script does.
The second script however, does not change a property value of arrs, but assigns an entirely new value to arrs, so that now it does not share any properties any more with data. This is even more apparent, because both data and arrs are primitive values which cannot mutate like explained in the previous paragraph. But even if they were objects or arrays, and you would do the following assignment:
arrs = [1234];
It would not affect data. data would only be affected if you would assign to a property/index of arrs without assigning to arrs directly.
First variant modifies object passed as parameter to function (which happens to be array) - so this change is seen outside function. Second variant assigns new value to function parameter (which happens to be reference to array) but does not change array itself.

Function identity in javascript

The following is unintuitive behavior in javascript,
function function1 () {};
function function2 () {};
var class_a_functions = {function1:true, function2:true};
var contained = function1 in class_a_functions;//false
var equals = function1.name in class_a_functions;//true
Why does the in containment test fail even though I have inserted the functions, not their names, into the dictionary?
EDIT:
If it isn't obvious, I am aware that function1.name is "function1". This is why I asked why the test fails "even though I have inserted the functions, not their names".
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/in
// Arrays
var trees = new Array("redwood", "bay", "cedar", "oak", "maple");
0 in trees // returns true
3 in trees // returns true
6 in trees // returns false cause there's no 6th key in trees Array
"bay" in trees // returns false (you must specify the
// index number, not the value at that index)
"length" in trees // returns true (length is an Array property)
That's why it returns false
On the other case, class_a_functions[0] is the reference to the stored function in Array that's why equality returns true cause fn1() === fn1()
Now after your edited question the above seems like nonsense so I'll answer further:
var class_a_functions = {function1:true, function2:true};
Is now and object where function1 and function2 are simple Properties holding true as Value.
var contained = function1 in class_a_functions;//false
The above returns false cause there's no "function1" Function inside the Object reference class_a_functions
var equals = function1.name in class_a_functions;//true
The above... well, let's go back to MDN, says:
Summary:
The in operator returns true if the specified property
is in the specified object.
So you have a property of function1 Now let's see if is present in the Object class_a_functions ... Yes. So TRUE
I'm not sure why most of the answers are so trivial and don't really address the underlying issue motivating the question, which is that getting the memory address/object hash/object id in javascipt is "impossible", and therefore the equality testing by object reference is also "impossible".
How can I get the memory address of a JavaScript variable?
A solution for that containment problem is to monkey-patch an object to contain a unique property/string that can be used as a key.
The in is used to identify the key not the value.
The in operator tests if a property is in an object. function1 is not a property of the array, it's a member.
There should be
'function1' in class_a_functions;//true
This is because
In a dictionary
obj = {key:5}
this is equal to
obj = {"key":5} // so it will be stored as string
If you will see the docs it says prop is A string or numeric expression representing a property name or array index.

what does calling Object without using new do?

I've seen code that goes along the line of
Object( existingObject ).myMethod();
Is this different than calling existingObject.myMethod() directly? More generally, what does Object(x) do?
The Object constructor creates an object wrapper for the given value.
If the value is null or undefined, it will create and return an empty
object, otherwise, it will return an object of a type that corresponds
to the given value. If the value is an object already, it will return
the value.
In your case, since the value is an object already, it will just return the value existingObject. So, no, it is not really different from calling existingObject.myMethod directly.
Documentation

JavaScript Reference array insert

I am novice to JavaScript but I know JavaScript does calls by value when passing primitives and calls by reference when passing objects.
var a = [4,5];
var temp = a;
console.log(a); // [4,5] OK
console.log(temp); // [4,5] OK
temp = temp.push(6); // Insert one more element into temp array
console.log(a); // [4,5,6] why so??
Console.log(temp); // [4,5,6]
I know this is because of reference got change . What should I do to avoid deep copy ?
If I change temp don’t want to change original reference a, it should print [4,5].
If you want to copy it, you can use slice:
var temp = a.slice(0);
Edit: thanks to cuberto for pointing me out slice(0)
"I know JavaScript behavior is call by value in primitive value and
call by reference in case of object."
Not exactly. In Javascript everything is passed by value all the time. If you pass an object, you actually pass a reference to the object, and that reference is passed by value.
Example:
var o = { name: 'first' };
// pass object reference to a function
use(o);
function use(x) {
// change the reference
x = { name: 'second' };
}
alert(o.name); // shows "first"
As the reference is passed by value to the function, changing the reference inside the function doesn't change the variable that was used to send the reference.
In your code you have only one array:
var temp = a; // copy the reference from a to temp
You have two variables that reference the same array, so any changes that you do to the array using one variable to access it will be visible when you look at the array using the other variable.
To get two separate arrays you have to specifically create a copy of it:
var temp = a.slice(0);
Note: Copying an array makes a shallow copy. That means that if you for example have an array of objects that you copy, you will have two arrays, but they will still share the same set of objects.
As you know, primitive values are passed by value, everything else is passed by reference. Primitives are boolean, number and string (and maybe consider null and undefined here). Everything else is an object and passed by reference.

Categories