Javascript "shift" versus "splice" - are these statements equal? - javascript

I just want to confirm if the following two Javascript statements produces the same results, as it seems to me:
First:
var element = my_array.splice(0,1)[0];
Second:
var element = my_array.shift();
I want to substitute the first by the second, in my own code, to improve readability. Can I do this?

They will have the same effect, yes. splice(0, 1) will remove the first element from my_array and return a new array containing that element. shift will do the same, but return the element itself, not an array.
shift is more readable (in my opinion) and is also significantly faster (in Chrome at least):

Both lines of code remove the first element from the array, and return the removed element, they are both supported in all major browsers.
You should use the second one, and the code will be more readable indeed.

shift returns the element that was removed, splice returns an array of elements that were removed.
that being said, the two statements do the same thing and i would agree that the second is more readable.

splice will return as an array but not remove data from the object instead make a copy
shift just give one data from front and also remove from object
For example,
const object = {1}
object.slice(); // return [{1}]
//object will be : {1}
object.shift(); // return {1}
//object will be : {} as shift remove the front data

Related

insertBefore function for arrays and/or HTMLCollections?

Does there exist a function in vanilla JavaScript or jQuery that operates similarly to Node.insertBefore(), but for arrays and/or HTMLCollections?
An example could look something like:
var list = document.getElementsByClassName("stuff");
var nodeToMove = list[0];
var otherNode = list[4];
list.insertBefore(nodeToMove, otherNode);
Basically I'm trying to perform insertBefore() without manipulating the actual DOM, as I want the changes to only be applied to the DOM under certain conditions. If those conditions are met, then I would perform insertBefore() on the actual nodes.
To clarify, I'm looking for a function that would insert an element before a target element at a given index in an array, not necessarily at a given index. Examples I've seen using splice() usually insert an element at a given index, which sometimes puts the element before the target element, and sometimes after, depending on where the element to be moved originally was in the array. I'm looking for something that would reliably put the element to be moved before the target element.
HTMLCollection does not have an insertBefore method. jQuery can apply any jQuery methods both to a single element being selected, as well as many.
https://api.jquery.com/insertBefore/
There is no single method to do this in one step, but there doesn't need to be. If you convert the collection to an Array, you can call the Array.prototype.splice() method to achieve the same result.
Here's an example:
let ary = [1,2,3,4,5];
// Swap 2 and 3
// Start at the 3rd item and remove one item (3).
// Store the removed item
let removed = ary.splice(2,1);
// Start at the second item, don't remove anything, insert the removed
// item at that position
ary.splice(1,null,removed[0]);
// Log the result
console.log(ary);
And, with that knowledge, you can create your own more easily callable function:
let ary = [1,2,3,4,5];
function insertBefore(ary, newItem, target){
ary.splice(target,null,newItem);
}
// Insert 999 before the 3rd array item
insertBefore(ary,999,2)
console.log(ary);
You need to get the index you want, then use Array.splice.
Myself I would do something like this :
const myArr = ['Aurore', 'Dimitri', 'Alban', 'Frédéric'];
const insertBeforeThis = 'Alban';
const eltToInsert = 'Laura';
const index = myArr.findIndex(name => name === insertBeforeThis);
myArr.splice(index, 0, eltToInsert);
Please feel free to try it out in your browser's console. Note i used const for my array, as it fixes the type of the variable as an array but allow me to manipulate it.
MDN: Array.prototype.findIndex()
stackoverflow: How to insert an item into an array at a specific index (JavaScript)?
Have a happy coding time!

Do undefined elements in an array have an impact in JS? [duplicate]

This question already has answers here:
Deleting array elements in JavaScript - delete vs splice
(29 answers)
Closed 4 years ago.
I couldn't find a question that specifically targets the issue I'm having hence this question is being asked.
I have an array that holds 5 numbers:
var numbers = [0,1,2,3,4];
Once a number is clicked on the frontend (website), the number is removed from the array using the below code:
delete numbers[1];
This removes the correct number but leaves a space where the number was (the space is undefined). I believe this is causing an issue. After a number is removed from the array, I use another function to randomly pick any of the remaining numbers in the array however it sometimes fails. After much thought, I've realized it may be because there are empty spaces in the array after a number is removed and as a result, the code fails to work due to the undefined element.
Is my analogy correct or am I mistaken?
(I have also attempted to use the splice method to remove the number however that then causes an issue with the length of my array because if I later want to remove another number, it removes the wrong one due to the numbers moving around etc).
What you'd want to use is splice
In your specific case, numbers.splice(1,1)
You're correct that delete replaces one of the values in the array with undefined, and does not change the array length. Later on when you randomly choose an element from the array, you can wind up getting that undefined value, because it's still taking up a slot in the array:
var numbers = [0,1,2,3,4];
delete numbers[3];
console.log(numbers)
Instead use splice, which removes the item from the array completely:
var numbers = [0,1,2,3,4];
numbers.splice(3,1) /// remove one element starting at index 3
console.log(numbers)
if I later want to remove another number, it removes the wrong one due to the numbers moving around
You do need to choose one behavior or the other. If you need to preserve indexes as is, then continue to use delete, leaving the undefined values in the array, and rewrite your "choose one at random" function to never pick undefined values:
// start with some undefined values:
var numbers = [0, 1, undefined, undefined, undefined, 5]
var pickRandom = function(numbers) {
// make a copy of the array, removing undefined elements:
var definedValues = numbers.filter(function(item) {
return item !== undefined;
});
if (definedValues.length === 0) {return false}
//choose one at random:
return definedValues[Math.floor(Math.random() * definedValues.length)]
}
// test it:
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
(...but note that this suggests that a simple array is the wrong data structure to use here; you may be better off with an array of objects each with an explicit ID, so you can reference specific ones as needed without worrying about keeping the array index the same.)
If you mean to actually remove the element from the array, leaving your array with 4 elements, then you can use
numbers.splice(1);
This will remove the element in the index 1 from the array and return the section of the new array.

what is use of adding length property to objects in javascript?

Array do support length property as well as string does, but objects don't inherently have a length property.
in case we add a length properly as below.
{"a":0,"b":0,length:2}
what is the use case scenario for above code
An object doesn't have a length, per se. It depends on what this length represents.
For example, in the code you posted, it's not immediately obvious why the length is 4, but it might make sense in the context of what that object actually represents.
Here are both methods of getting the length.
You'll notice if you keep track of your own length the display code is a bit shorter but you need a whole function to add a new key, you'd even need another function to remove them.
object.keys changes the keys into an array which we can get the length from this, of course, take a few milliseconds more as it has to do the convert.
I generally run with the assumption a computer is going to make fewer mistakes than me so, if I can, I should load as much work as possible onto it.
// initial set up
let obj1 = {"a":0,"b":0};
let obj2 = {"a":0,"b":0,length:2};
// initial lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
// adding standard way
obj1["c"] = 0;
// adding to accomidate with length
function addObj2(key, value) {
obj2[key] = value;
obj2.length++;
}
addObj2("c",0);
console.log("--");
// new lengths
console.log("obj1: "+Object.keys(obj1).length);
console.log("obj2: "+obj2.length);
I hope this makes sense.

Why do getElementsByTagName() always returns an array?

Why is it that if I have only one h1 element in the document, I still have to use the index to access it?
Like the following doesn't work.
document.getElementsByTagName('h1').innerHTML = "SHUSHAN";
but if I do
document.getElementsByTagName('h1')[0].innerHTML = "SHUSHAN";
It does work.
Even though I only have one h1, why do I have to specify?
Short answer: This is so that you can have some sanity.
If you don't know whether you will get a single element or a collection of elements, you would have to write defensive, type-checking (stupid) code like this
let foo = document.getElementsByTagName('h1')
if (foo instanceof HTMLCollection)
// do something with all elements
else
// do something with just one element
It makes way more sense for the function to always return a known type, an HTMLCollection of HTMLElement objects
If you only care about getting the first element, you can use destructuring assignment
let [first] = document.getElementsByTagName('h1')
console.log(first) // outputs just the first h1
This is fine because the assignment clearly shows that it's expecting an array (or array-like) of elements but only cares about assigning an identifier to the first value
You should also be aware of the newer document.querySelector and document.querySelectorAll functions …
document.querySelector will select at most one element from the document or returnnull
document.querySelectorAll will always return an HTMLCollection, but may be empty if no elements match the selector.
Here's how I'd write your code in 2017
setTimeout($ => {
// get the element to change
let elem = document.querySelector('h1')
// update the text of the element
elem.textContent = 'SHUSHAN'
}, 3000)
<h1>wait 3 seconds ...</h1>
getElementsByTagName - the method name itself implies that it will return multiple elements - i.e. an array. The method always returns an array, with the length equal to the number of matching elements. As such you must always access the elements by the index of the element in the array.
Arrays must be accessed by index regardless of how many values it holds. Do some reading on array data types to get a better understanding of the concept.
The point is that getElementsByTagName always returns a HTMLCollection of elements, which works mostly as an array. If there is only one element in this collection, then its index is 0.
This is the reason why you must specify the index, even if there is only one element in the document.
Click here or here to see more documentation about this.

Using javascript's indexOf on an array of svg text elements

I am working with an svg file which has a number of text elements within it. The text elements are all numbers. I am able to get the list of values and put them into an array with the following line of code.
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
I am able to access .length property and also the access the array elements by index such as [0].textContent. However, when I try to use the .indexOf() function on the array, I receive an error message that the object (my array) does not support the property or method of indexOf.
I am able to setup a for loop to iterate through the array checking each value looking for the presence or absence of a certain value. I would like something with the simplicity of the indexOf functionality which tells me whether or not something is present within the array and where it is if present. Is there a to get .indexOf() working with the svg text element array? Or is there a similar alternative which does not require the use of loops and flags?
I think the problem lies in the fact that I have an array of text elements and not an array of strings. But I'm not sure how to directly get the array of the text element's textContent
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
//var fretdata = document.getElementById("fretinformation").getElementsByTagName("text").textcontent;
//18th fret is the upper fret limit
//0 fret (open string) is the lower fret limit
//var zerolocation=fretdata.indexOf("0");
for (fd=0;fd<fretdata.length;fd++){
if(fretdata[fd].textContent=="0"){
document.getElementById("downkey").setAttribute("onclick",null);
document.getElementById("downkey").getElementsByTagName("polygon")[0].style.fill="#D3D3D3";
}
}
Iterating in the loop works. The two lines commented out using the .indexOf do not.
Thanks, --christopher
What you have is not an array, it's a nodeList.
A nodeList has length, and is array-like, but array methods like indexOf, forEach etc. doesn't work on nodeLists.
You can convert a nodeList to an array like this
var array = Array.prototype.slice.call(fretdata);
but in your case you really shouldn't, you should stick to the iteration instead.
Iterating the elements is really an option, but if you don't like it, you may have 2 more options depending on your setup:
The following code requires map function (check compatibility here, it basically requires IE9+) and slice function compatibility (same, IE9+).
var fretdata = document.getElementById("fretinformation").getElementsByTagName("text");
alert([].slice.call(fretdata).map(function(o) { return o.textContent; }).indexOf("1"));
The other one requires jQuery, it handles a lot of stuff for you.
alert($( "#fretinformation > text" ).filter(function() { return $(this).text() === "1"; } ).length);
use ES6 spread operators
var fretdata = [...(document.getElementById("fretinformation").getElementsByTagName("text"))]
This internally works as
var array = Array.prototype.slice.call(fretdata);

Categories

Resources