I have a basic question about using the .shift method. Below is my working code to convert a number to the sum of all digits. After converting to string and splitting to array, if the first value is the '-' sign I use .shift to remove this element, then make the next value negative. My question is, where does the '-' go? What happens to this value that I have not assigned to any variable?
Moving forward, should I be concerned about using this method if it will potentially leave values sort of 'floating' around in my code?
function sumDigits(num) {
var numArr = num.toString().split('');
if (numArr[0] === '-') {
numArr.shift();
numArr[0] *= -1;
}
var total = numArr.map(Number).reduce(function(a, b) {
return a + b;
});
return total;}
Thanks!
Since arrays in Javascript are mutable, each element in an array is a reference to a place in memory. When you create a new array or add an element to an array, Javascript implicitly allocates memory and then creates new references from the array to point to the newly allocated objects in memory.
In your situation, when you shift(), you're removing the reference to the memory that contains that element, and not the element itself.
So how does Javascript actually delete these items from memory? Garbage collection. One simple mechanism of garbage collection checks all of the objects in memory and counts the number of references to it. If the number of references is 0, then it indicates to the garbage collector that the object can be deleted from memory.
So when after you delete the reference to the first element in the array with shift(), the garbage collector later comes in and sees that the object that the first element in the array used to point to now has nothing that references it. Thus it is safe to garbage collect, and is therefore deallocated from memory.
All in all, you do not need to worry about memory leaks from using shift() thanks to Javascript's garbage collection mechanism.
Here is an interesting link about Javascript memory management, if you're curious to learn more.
Related
The WeakSet is supposed to store elements by weak reference. That is, if an object is not referenced by anything else, it should be cleaned from the WeakSet.
I have written the following test:
var weakset = new WeakSet(),
numbers = [1, 2, 3];
weakset.add(numbers);
weakset.add({name: "Charlie"});
console.log(weakset);
numbers = undefined;
console.log(weakset);
Even though my [1, 2, 3] array is not referenced by anything, it's not being removed from the WeakSet. The console prints:
WeakSet {[1, 2, 3], Object {name: "Charlie"}}
WeakSet {[1, 2, 3], Object {name: "Charlie"}}
Why is that?
Plus, I have one more question. What is the point of adding objects to WeakSets directly, like this:
weakset.add({name: "Charlie"});
Are those Traceur's glitches or am I missing something?
And finally, what is the practical use of WeakSet if we cannot even iterate through it nor get the current size?
it's not being removed from the WeakSet. Why is that?
Most likely because the garbage collector has not yet run. However, you say you are using Traceur, so it just might be that they're not properly supported. I wonder how the console can show the contents of a WeakSet anyway.
What is the point of adding objects to WeakSets directly?
There is absolutely no point of adding object literals to WeakSets.
What is the practical use of WeakSet if we cannot even iterate through it nor get the current size?
All you can get is one bit of information: Is the object (or generically, value) contained in the set?
This can be useful in situations where you want to "tag" objects without actually mutating them (setting a property on them). Lots of algorithms contain some sort of "if x was already seen" condition (a JSON.stringify cycle detection might be a good example), and when you work with user-provided values the use of a Set/WeakSet would be advisable. The advantage of a WeakSet here is that its contents can be garbage-collected while your algorithm is still running, so it helps to reduce memory consumption (or even prevents leaks) when you are dealing with lots of data that is lazily (possibly even asynchronously) produced.
This is a really hard question. To be completely honest I had no idea in the context of JavaScript so I asked in esdiscuss and got a convincing answer from Domenic.
WeakSets are useful for security and validation reasons. If you want to be able to isolate a piece of JavaScript. They allow you to tag an object to indicate it belongs to a special set of object.
Let's say I have a class ApiRequest:
class ApiRequest {
constructor() {
// bring object to a consistent state, use platform code you have no direct access to
}
makeRequest() {
// do work
}
}
Now, I'm writing a JavaScript platform - my platform allows you to run JavaScript to make calls - to make those calls you need a ApiRequest - I only want you to make ApiRequests with the objects I give you so you can't bypass any constraints I have in place.
However, at the moment nothing is stopping you from doing:
ApiRequest.prototype.makeRequest.call(null, args); // make request as function
Object.create(ApiRequest.prototype).makeRequest(); // no initialization
function Foo(){}; Foo.prototype = ApiRequest.prototype; new Foo().makeRequest(); // no super
And so on, note that you can't keep a normal list or array of ApiRequest objects since that would prevent them from being garbage collected. Other than a closure, anything can be achieved with public methods like Object.getOwnPropertyNames or Object.getOwnSymbols. So you one up me and do:
const requests = new WeakSet();
class ApiRequest {
constructor() {
requests.add(this);
}
makeRequest() {
if(!request.has(this)) throw new Error("Invalid access");
// do work
}
}
Now, no matter what I do - I must hold a valid ApiRequest object to call the makeRequest method on it. This is impossible without a WeakMap/WeakSet.
So in short - WeakMaps are useful for writing platforms in JavaScript. Normally this sort of validation is done on the C++ side but adding these features will enable moving and making things in JavaScript.
(Of course, everything a WeakSet does a WeakMap that maps values to true can also do, but that's true for any map/set construct)
(Like Bergi's answer suggests, there is never a reason to add an object literal directly to a WeakMap or a WeakSet)
By definition, WeakSet has only three key functionalities
Weakly link an object into the set
Remove a link to an object from the set
Check if an object has already been linked to the set
Sounds more pretty familiar?
In some application, developers may need to implement a quick way to iterate through a series of data which is polluted by lots and lots of redundancy but you want to pick only ones which have not been processed before (unique). WeakSet could help you. See an example below:
var processedBag = new WeakSet();
var nextObject = getNext();
while (nextObject !== null){
// Check if already processed this similar object?
if (!processedBag.has(nextObject)){
// If not, process it and memorize
process(nextObject);
processedBag.add(nextObject);
}
nextObject = getNext();
}
One of the best data structure for application above is Bloom filter which is very good for a massive data size. However, you can apply the use of WeakSet for this purpose as well.
A "weak" set or map is useful when you need to keep an arbitrary collection of things but you don't want their presence in the collection from preventing those things from being garbage-collected if memory gets tight. (If garbage collection does occur, the "reaped" objects will silently disappear from the collection, so you can actually tell if they're gone.)
They are excellent, for example, for use as a look-aside cache: "have I already retrieved this record, recently?" Each time you retrieve something, put it into the map, knowing that the JavaScript garbage collector will be the one responsible for "trimming the list" for you, and that it will automatically do so in response to prevailing memory conditions (which you can't reasonably anticipate).
The only drawback is that these types are not "enumerable." You can't iterate over a list of entries – probably because this would likely "touch" those entries and so defeat the purpose. But, that's a small price to pay (and you could, if need be, "code around it").
WeakSet is a simplification of WeakMap for where your value is always going to be boolean true. It allows you to tag JavaScript objects so to only do something with them once or to maintain their state in respect to a certain process. In theory as it doesn't need to hold a value it should use a little less memory and perform slightly faster than WeakMap.
var [touch, untouch] = (() => {
var seen = new WeakSet();
return [
value => seen.has(value)) || (seen.add(value), !1),
value => !seen.has(value) || (seen.delete(value), !1)
];
})();
function convert(object) {
if(touch(object)) return;
extend(object, yunoprototype); // Made up.
};
function unconvert(object) {
if(untouch(object)) return;
del_props(object, Object.keys(yunoprototype)); // Never do this IRL.
};
Your console was probably incorrectly showing the contents due to the fact that the garbage collection did not take place yet. Therefore since the object wasn't garbage collected it would show the object still in weakset.
If you really want to see if a weakset still has a reference to a certain object then use the WeakSet.prototype.has() method. This method, as the name implies returns a boolean indicating wether the object still exists in the weakset.
Example:
var weakset = new WeakSet(),
numbers = [1, 2, 3];
weakset.add(numbers);
weakset.add({name: "Charlie"});
console.log(weakset.has(numbers));
numbers = undefined;
console.log(weakset.has(numbers));
Let me answer the first part, and try to avoid confusing you further.
The garbage collection of dereferenced objects is not observable! It would be a paradox, because you need an object reference to check if it exists in a map. But don't trust me on this, trust Kyle Simpson:
https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/es6%20%26%20beyond/ch5.md#weakmaps
The problem with a lot of explanations I see here, is that they re-reference a variable to another object, or assign it a primitive value, and then check if the WeakMap contains that object or value as a key. Of course it doesn't! It never had that object/value as a key!
So the final piece to this puzzle: why does inspecting the WeakMap in a console still show all those objects there, even after you've removed all of your references to those objects? Because the console itself keeps persistent references to those Objects, for the purpose of being able to list all the keys in the WeakMap, because that is something that the WeakMap itself cannot do.
While I'm searching about use cases of Weakset I found these points:
"The WeakSet is weak, meaning references to objects in a WeakSet are held weakly.
If no other references to an object stored in the WeakSet exist, those objects can be garbage collected."
##################################
They are black boxes: we only get any data out of a WeakSet if we have both the WeakSet and a value.
##################################
Use Cases:
1 - to avoid bugs
2 - it can be very useful in general to avoid any object to be visited/setup twice
Refrence: https://esdiscuss.org/topic/actual-weakset-use-cases
3 - The contents of a WeakSet can be garbage collected.
4 - Possibility of lowering memory utilization.
Refrence: https://www.geeksforgeeks.org/what-is-the-use-of-a-weakset-object-in-javascript/
##################################
Example on Weakset: https://exploringjs.com/impatient-js/ch_weaksets.html
I Advice you to learn more about weak concept in JS: https://blog.logrocket.com/weakmap-weakset-understanding-javascript-weak-references/
If I have a large array I'm using all the time and continuously through-out the lifetime of the app, such as a user list. And yes I enjoy using arrays rather than objects for many reasons and can't use splice() because I have index references.
The usual quote for garbage collection:
Since Javascript is garbage collected, you don't need to delete
objects themselves - they will be removed when there is no way to
refer to them anymore.
Does this mean that when I delete an element in an array, since the array can be referred to at any time - the Garbage collector wont free up the deleted element? or does it mean because the object can't be referred to, it will free up memory? - And even if it is, wont my array get filled up with 'undefined' entries which presumably use up at least 1 or 2 bytes of memory? - does anyone know how much memory is used per undefined entry?
Example:
var userList = [];
var userNumber = 0;
userList[userNumber++] = {name:'john',score:200,friends:['abby','micky']};
userList[userNumber++] = {name:'jack',score:200,friends:['betty','billy']};
userList[userNumber++] = {name:'jimm',score:200,friends:['catty','ken']};
delete userList[1];
// will {name:'jack',score:200,friends[ n ]} size of memory be freed
// or a little less to internally reference 'undefined'?
When you delete an array property, its value becomes unreachable*, hence freeable by the garbage collector as soon as you delete them.
a = [0, 1, 2]
alert(1 in a); // true
delete a[1];
alert(1 in a); // false
* - assuming the array element is not otherwise reachable from a property of a reachable object or live local variable.
... - the Garbage collector wont free up the deleted element? or does it mean because the object can't be referred to, it will free up memory?
The garbage collector is never obliged to free any memory, but can reuse any memory previously used by the value of a deleted array property that is not otherwise referenced by any property or live local variable.
I basically need a dictionary of certain numbers to other values. I'll start with:
var o = /*??????*/
And then:
o[4] = foo;
o[8] = bar;
You'll notice that the indexes are far from sequential, though as keys they are definitely significant.
What are the disadvantages to using an array for this, or should I just be using numeric keys on an object?
Stick to 'plain' objects. Arrays imply sequential iteration, which will give people the wrong idea — you wouldn't want to shift, splice or push to this object, which is essentially a hash.
If the incidentally numeric keys do not represent an ordered sequence, you're just giving the wrong idea to anyone else (not to mention yourself) when they approach the code.
Javascript objects are sparse, and arrays are just specialized objects with an auto-maintained length property (which is actually one larger than the largest index, not the number of defined elements) and some additional methods. You are safe either way; use an array if you need it's extra features, and an object otherwise.
I have been wonder where a for loop or a for..in loop would be farther on an array.
I have tested this using jsperf.
My For Loop had 16,676,377 op/s
while the for..in only had 519,853 op/s
So why is:
var a = ["hi", "hi2", "bye", "bye2"];
for (var i in a) {
return a[i];
}
Slower compared to:
var a = ["hi", "hi2", "bye", "bye2"];
for (var i = 0; i < a.length; i++) {
return a[i];
}
The answer for your question is simple: for in loop was not created to deal with arrays and does additional things as well and should not be used.
The main purpose of the for-in statement is to iterate thought object's properties, not through the array. This statement will also go into the array prototype chain, iteration through inherited properties and I think you do not need this or even do not know about this.
Another funny thing that you even do not know in what order it will be iterated.
So the main thing to remember - do not use for in with arrays. Only with objects.
P.S as RobG correctly added:
A for loop will search for properties on the [[Prototype]] chain too if they aren't found on the array. E.g. a for loop over [0,,2] will search for 1 all the way to Object.prototype[[Prototype]]
There are a couple of things wrong here.
your return in the loop's body causes the loop to abort after the first iteration, your tests are useless
for..in loops over an object's properties, an array's elements are not its only properties! were you to add a property, such as a.foo = true; that would be included in iterating with for..in but not in for.
Please don't use for..in to loop arrays. Not. Ever.
To explain why a for loop is faster than a for in loop is basically understand the underlying data structures used to store the data in memory.
Looping through an indexed based array is naturally faster because of the way an array is stored in memory. It's just a location in memory and the items in the array are stored in consecutive locations, aka. in order and next to each other. Generally it's fast to retrieve elements in consecutive order because you don't have to spend time to find it, you just know the next item is always the next location beside it. And because it knows the array.length and can determine which chunks of memory has been portioned off for the array.
It really depends on the JavaScript engine implementation. Because JavaScript is dynamically typed, the interpreter has to do some work to establish the type of a given variable. I suspect there are optimisations in the engine for the classic integer iterator for loop that aren't available when using for...in.
EDIT:
for..in iterates through the enumerable properties of a variable, so var i is assigned the value of each string in your array on each loop.
What is a memory efficient way to link two objects? If you store objects using two arrays with corresponding index values the object won't be released from memory.
The implementation should look like the following.
var obj ={};
var linkedobj = getLinkedObject(obj);
var obj2 ={}
var linkedobj2 = getLinkedObject(obj2);
Objects are general containers
If all you want to do is associate one object with another one, then why not have them point to one another?
var obj = {};
var obj2 = {};
obj.linkedObject = obj2;
obj2.linkedObject = obj;
This would a normal thing to do, and doesn't have bad implications on memory.
Releasing memory
If you are asking about holding a table full of object references, you are correct that the object will not disappear until all of the live references to it are gone. Javascript has a garbage collector, and as long as your table or array has a good reference, it will be backed by memory for you. If you give an object to a table and then want it to be deleted from memory entirely, you can simply remove it from your table also. You could also just remove the table, assuming it doesn't need to hold anything else.
If you are determined to have a getLinkedObject function return an object for another object, you can still allow the objects to each hold the associate reference.
function getLinkedObject(anObject) {
return anObject.linkedObject;
}
This would probably be accompanied by a counterpart:
function linkObjects(anObject, anotherObject) {
anObject.linkedObject = anotherObject;
anotherObject.linkedObject = anObject;
}
Doing this allows you to worry a little less about memory management, which in Javascript (a high-level, dynamic environment with a garbage collector) is typically appropriate.
Unless you use keparo's answer, which from your follow-up comment sounds like not an option, what you're asking for is basically impossible. Because, since you can't augment the original object, you need some method of storing a reference to it. But (since JavaScript has no concept of weak references) this will always prevent it from being garbage collected, contradicting your requirements statement.