Comparison between normal array vs generated by back-tick array - javascript

I am creating an array by two way.
my first way is creating an array normally
my second way is creating an array by using backticks function
let array=["1234"];
function createArrayByBakticks(obj)
{
return obj;
}
let backtickArray = createArrayByBakticks `1234`;// it's responding an array
console.log(array); //1st way and it returns an array
console.log(backtickArray ); //2nd way and it returns a same array
backtickArray.push(1);// but it's throwing an error while push a new value.
// Error: Uncaught TypeError: Cannot add property 1, object is not extensible
console.log(backtickArray);
Above both ways are return as a array data. But the second array is not supporting inbuilt function of array which is generated by back-ticks. WHY? And what is the difference between in the both ways?

createArrayByBakticks is used as a so-called tag function. The first argument passed to the function is an array containing all strings of the template literal.
If you dive deep into the language specification, section 12.2.9.3, then you will see the following step is performed after the array has been created:
Perform SetIntegrityLevel(template, "frozen").
This means that in your case objis frozen and no property can be added. That's why invoking push doesn't work.
You can confirm this by calling console.log(Object.isFrozen(backtickArray)).

The array returns from the function by value, meaning it's immutable.
If you use concat, you'll get a new copy of it, which you can modify:
let array = ["1234"];
function createArrayByBakticks(obj) {
return obj;
}
let backtickArray = createArrayByBakticks `1234`; // it's responding an array
console.log(array); //1st way and it returns an array
console.log(backtickArray); //2nd way and it returns a same array
let newArray = backtickArray.concat(1); // a new mutable array is generated
newArray.push(2); // so you can even keep modifying it
console.log(newArray);

Related

Immutability in a for in loop when adding an object to an array

I have a for of with a for in loop inside it, that gets a result from a Neo4J database. Using Object.assign, I take the result object and assign a property from it to a new object. My understanding is this is immutability.
I then want add the new result object to an array for reach result returned.
I can declare an empty array outside the loop and use Array.concat to create new array for each iteration. Another option could be to use Array.push. Neither of these feel immutable because I am either pushing to an array, or overwriting a variable.
Is there a way to end up with a results array, of all object, that is immutable?
let results = []
for (const row of argsArray) {
for (const key in row) {
const neo4jPropInUse = await neo4j.session(null, cypher.ngp(key, row[key]))
if (neo4jPropInUse.length !== 0) {
console.log('IN USE DETECTED')
const thingResult = Object.assign({}, {
[thingSerialNumber]: neo4jPropInUse[0].get(`RESULT`).properties[thingSerialNumber],
key: key
})
results = results.concat([thingResult])
}
}
}
Even if you declare an object with const you can still modify its contents, you just can't reassign it anymore. If your goal is to return an unmodifiable array after the loops are finished you can use Object.freeze which will stop you from modifying the object (shallowly).
Object.freeze(results);
Now it will throw an error if you try to push or pop from that array. Note that this is a "shallow freeze" and you will still be able to modify any values inside objects that are part of the array. Hope this helps.

Rewrite following piece of javascript code

I am trying to create a function that mimics Array.prototype.push.
It takes a variable number of arguments and pushes them into a specific array.
I have managed to do this with the following code:
var array=[];
function append(){
for(var i=0;i<arguments.length;i++)
array.push(arguments[i]);
}
Now my question is:Can I rewrite the append function without using "for loop"?
Thanks in advance.
If you need to get arguments array, you should use Array's slice function on an arguments object, and it will convert it into a standard JavaScript array:
var array = Array.prototype.slice.call(arguments);
You could use Array.prototype.push.apply
function append(){
// make arguments an array
var args = Array.prototype.slice.call(arguments);
// return the number of elements pushed in the array
return Array.prototype.push.apply(array, args);
}
So, what's happening here with args? We use Array.prototype.slice.call with arguments, the purpose being to make arguments an array, because it is a special object. Function.prototype.call is used to call a function with a specific context (aka this), and then the arguments to call the function with (comma separated). Conveniently, it appears that slice() looks at the length property of the this context, and arguments has one too, and when not empty, has properties from 0 to length -1, which allows slice to copy arguments in a new array.
You can rewrite this without a for loop, but you have to use a loop of some sort (you're working with multiple items, it's a necessity).
If you have access to ES6 or Babel, I would use something like:
function append(...args) {
return array.concat(args);
}
Without ES6, you need to work around the fact that arguments isn't a real array. You can still apply most of the array methods to it, by accessing them through the Array prototype. Converting arguments into an array is easy enough, then you can concat the two:
function append() {
var args = Array.prototype.map.call(arguments, function (it) {
return it;
});
return array.concat(args);
}
Bear in mind that neither of these will modify the global array, but will return a new array with the combined values that can be used on its own or assigned back to array. This is somewhat easier and more robust than trying to work with push, if you're willing to array = append(...).
Actually i honestly believe that push must be redefined for the functional JS since it's returning value is the length of the resulting array and it's most of the time useless. Such as when it's needed to push a value and pass an array as a parameter to a function you cant do it inline and things get messy. Instead i would like it to return a reference to the array it's called upon or even a new array from where i can get the length information anyway. My new push proposal would be as follows;
Array.prototype.push = function(...args) {
return args.reduce(function(p,c) {
p[p.length] = c;
return p
}, this)
};
It returns a perfect reference to the array it's called upon.

Javascript syntax: var array = [].push(foo);

Where foo is a defined variable, why is it that the following code:
var array = [].push(foo);
when outputted, equals 1?
From my tests, outputting array will simply output the length of the array.
So the code:
var array = [10,20].push(foo);
would give a value of 3.
As a related question (and to clarify what my code intended to do), why does this not intuitively do what it appears to do, ie:
var array = [];
array.push(foo);
where outputting array gives the expected result of [foo]?
When you use push method it returns length of array. So when you do:
var array = [10,20].push(foo);
you get [10, 20, foo] length of this array is three. But as you say var array it stores returned length from push method in this variable.
Array.prototype.push() always returns the new number of elements in the array. It does not return this instance or a new Array instance. push() is a mutator actually changes the contents of the array.
instead you can try
var array, foo = 30;
(array = [10,20]).push(foo);
console.log(array)
push is a function and it returns an integer representing the length of the array.
Imagine the definition of this function as
int push(object obj);
When you do this:
var array = [].push(foo);
You are actually running the function and returning the value.
Because the return value of push is the new length of the array Documentation and examples.
In your second example, you cited outputting the array, which is going to give you the new array in both cases. However, the returned result of your second case is the new array length as well
var array = [];
array.push(foo); //If you do this in the console, you'll see that 1 gets returned.
console.log(array); //While this will print out the actual contents of array, ie. foo
The definition of push() method including two parts in javascript: Part 1: it adds one or more elements to the end of an array, part 2: it returns the new length of the array.
I think you are missing the part 2 in your understanding of this method.

Creating multi-dimensional arrays in javascript, error in custom function

I was trying to define an array (including other arrays as values) in a single javascript statement, that I can loop through to validate a form on submission.
The function I wrote to (try to) create inline arrays follows:
function arr(){
var inc;
var tempa = new Array(Math.round(arguments.length/2));
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
This is called three times here to assign an array:
window.validArr = arr(
'f-county',arr('maxlen',10, 'minlen',1),
'f-postcode',arr('maxlen',8, 'minlen',6)
);
However in the javascript debugger the variable is empty, and the arr() function is not returning anything. Does anyone know why my expectations on what this code should do are incorrect?
(I have worked out how to create the array without this function, but I'm curious why this code doesn't work (I thought I understood javascript better than this).)
Well from what your code does, you're not really making arrays. In JavaScript, the thing that makes arrays special is the management of the numerically indexed properties. Otherwise they're just objects, so they can have other properties too, but if you're not using arrays as arrays you might as well just use objects:
function arr(){
var inc;
var tempa = {};
for(inc=0; inc<arguments.length; inc=inc+2) {
tempa[arguments[inc]]=arguments[inc+1];
}
return tempa;
}
What you're seeing from the debugger is the result of it attempting to show you your array as a real array should be shown: that is, its numerically indexed properties. If you call your "arr()" function as is and then look at (from your example) the "f-county" property of the result, you'll see something there.
Also, if you do find yourself wanting a real array, there's absolutely no point in initializing them to a particular size. Just create a new array with []:
var tempa = [];
Your code works. Just inspect your variable, and you will see that the array has the custom keys on it. If not expanded, your debugger shows you just the (numerical) indixed values in short syntax - none for you.
But, you may need to understand the difference between Arrays and Objects. An Object is just key-value-pairs (you could call it a "map"), and its prototype. An Array is a special type of object. It has special prototype methods, a length functionality and a different approach: to store index-value-pairs (even though indexes are still keys). So, you shouldn't use an Array as an associative array.
Therefore, their literal syntax differs:
var array = ["indexed with key 0", "indexed with key 1", ...];
var object = {"custom":"keyed as 'custom'", "another":"string", ...};
// but you still can add keys to array objects:
array.custom = "keyed as 'custom'";

remove intermediary object from map object

I have a couple of these and think (know) that I'm doing something wrong (or could be simpler).
html:
<div class='item-to-select' data-global-id='55'>some</div>
var l=$(this).map(function(){
t=new Object();
t.global_id=$(this).data('global-id');
return t;
}).get();
var list=l[0]; // want to remove this
How would I remove this intermediary object? Or a better way
thx
If you mean that you don't want to have to define the l variable just so you can use it once in setting up your list variable you can do this:
var list = $(this).map(function(){
return {
global_id : $(this).data('global-id')
};
}).get()[0]; // note the [0] directly after .get()
The return from any function that returns an array (or array-like object) doesn't have to be assigned to a variable before you can use it. So:
var temp = someFuncReturnsArray();
console.log(temp[0]);
// can be replaced by
console.log(someFuncReturnsArray()[0]);
Of course if you need to do further processing on the returned array you need to put it in a variable. E.g., if you need to test its length, or if the function could possibly return null in some situations, etc. In the example above if an empty array was returned then obviously [0] will be undefined.
But if you only need the return value once you can just use it directly.
Note that I've removed the t variable from your code too. When creating an empty object it is considered good practice to say obj = {} rather than saying obj = new Object(). But you can create an object with properties in one step if the property values are already known. In the case of your function the t object you create isn't manipulated in any way other than adding a single property to it before you return it, so you can simply return an object literal directly instead of doing it in three steps.
The jQuery .get() method accepts an index.
So, you can write :
var list=$(this).map(function(){
t=new Object();
t.global_id=$(this).data('global-id');
return t;
}).get(0);

Categories