Effect of array1.concat(array2) not persisting after function call - javascript

this works:
var f = function(a){
a.push(1);
};
var a = [];
f(a);
console.log(a);//[1];
But this:
var f = function(a){
a = a.concat([1]);
};
var a = [];
f(a);
console.log(a);//[];
Does not work. With work I mean that the changes made persist after the function call.
Now I realise that this most likely has something to do with the arguments being passed 'as reference by value', meaning that a change in reference (ie assigning a new object) does not persist after the function call.
So I wonder, is there a persistent version of concat? Or do I manualy have to push all elements from one array into the other?
Edit: All of you suggesting to return the newly created array: that's pretty much exactly what I don't want. If I wanted to do that I wouldn't have created this question. And I certainly would not have ended it specifically asking for a persistent version of concat.

concat returns a new array, it doesn't mutate the source array.
var f = function(a){
return a.concat([1]);
};
var a = f([]);
console.log(a);//[1];
If you do want to mutate the array, just use push.apply to pass array elements as individual arguments to the push function.
var f = function(a) {
a.push.apply(a, [1]);
};
var a = [];
f(a);
console.log(a); //1

That's because the function parameter, a, is not the same as the variable a declared in the outer scope. When you assign a new value to the parameter a, it has no effect on the outer variable.
a = a.concat([1]);
Instead, simply return the new array, and use the return value in the outer scope, like this:
var f = function(a){
return a.concat([1]);
};
var a = [];
a = f(a);
Or perhaps consider using push like this:
var f = function(a){
Array.prototype.push.apply(a, [1, 2, 3]);
};
This will push multiple values onto the source array, so it's pretty much equivalent to concat except that it modifies the original array.

Related

How do higher-order functions like `map()` and `reduce()` receive their data?

I'm trying to write my own higher order function right now and I want to know how functions like map() and reduce() access the array they are being applied to. And not just for arrays either, but with any higher order function like toString() or toLowerCase().
array.map()
^^^ // How do I get this data when I am writing my own higher order function?
array.myOwnFunction(/* data??? */)
I hope this makes sense. I'm sure the answer is out there already, but I'm struggling to know what to search for to find the information.
You can add it to the Array prototype like :
Array.prototype.myOwnFunction = function() {
for (var i = 0; i < this.length; i++) {
this[i] += 1;
}
return this;
};
const array = [1, 2, 3];
const result = array.myOwnFunction();
console.log(result);
Check the polyfill for Array.prototype.map(), this line in particular:
// 1. Let O be the result of calling ToObject passing the |this|
// value as the argument.
var O = Object(this);
Simplifying, this is where the values are received.
The way this works is related to the prototype and to the "thisBinding".
When a function is instantiated using new, the properties of the prototype are attached to the new Function object. As well, an "execution context" is created to maintain the environment. The properties of the prototype are then accessible in the environment through the current instance's this binding using this.
So if you have a function you want to use the data from in an instance, you can use a prototype as well. For many reasons (memory use, readability, reusability, inheritance, polymorphism, etc.) this is the best way to go about doing it. Modifying standard implementations such as Array, Math, Date, etc. are generally discouraged (although there will always be exceptions).
function LineItem(description,price,quantity){
this.description = description;
this.price = price;
this.quantity = quantity;
}
LineItem.prototype.Total = function(){
return this.price * this.quantity;
};
var avocados = new LineItem("avocado",2.99,3);
console.log(avocados.Total());
The main thing to take away here is that the thisBinding allows access to the current instance's object through this. That is where the data access comes from. For example, in an array instance, this references the current array; in a date instance, this references the current date; in the above LineItem example, this references the current LineItem.
Thanks to the responses to this question I was able to write a higher order component that accepts a callback function as an argument. Here is the code as an example:
Array.prototype.myFunction = function (callback) {
const items = this
const newArray = []
for (let item of items) {
item = callback(item)
newArray.push(item)
}
return newArray
}
const array = [1, 2, 3, 4]
const result = array.myFunction((item => {
return item + 1
}))
console.log(result)

Variable value is not changing according to the variable

So here's the thing. I've declared the following variables to concat my object:
var newObj = obj[property];
var fullObj = newObj[id];
Then I'm matching the value of "fullObj" with the value of another obj named "Array". I do it like this:
fullObj = Array;
Then "fullObj" gets the new value, but the original object, which is something like: "obj.property.id" does not. Any ideas?
EDIT:
This is the function
function updateData(obj, Array, id, property) {
var newObj = obj[property];
var fullObj = newObj[id];
fullObj = Array;
}
The property that I'm sending back is "obj", with all its inner elements (obj.property.id).
As you can see, "fullObj" is the same thing as saying that last object construction. Imagine something like "object.id["0"]. So imagine the value of "Array" is "object.id["1"]. I'm giving "fullObj" that value by matching them both, but the original object won't get it.
Am I being clear enough?
The problem is that you are re-assigning the value for the fullObj variable. You can access the referenced object like that, but you can't change it.
Anyway, i don't see the point of doing that the way you are doing it. You can assign the value directly like this:
function updateData(obj, Array, id, property) {
obj[property][id] = Array;
}
You changed the reference of fullObj to some other reference (Array). The reference of newObj[id] remains the same.
Example
var a = [1];
var b = a;
b = [2];
console.log(a, b); // it logs [1] [2]

javascript equivalent of php call_user_func

I've found this topic which I've implemented (see accepted answer):
javascript equivalent of PHP's call_user_func()
However, I am having a problem with multiple parameters. I realize what I was doing was turning my parameters into strings and treating it like 1 parameter, but I don't know how to fix this because I am dynamically creating the parameters.
Meaning, I have defined in my code the following:
var a = new Array();
a[0] = new Array();
a[0][0] = 'alert';
a[0][1] = '\'Hello World\'';
a[1] = new Array();
a[1][0] = 'setTimeout';
a[1][1] = 'alert("goodbye world")';
a[1][2] = '20';
Later, I was calling them like this:
var j = 0;
var len = 0;
var fx = '';
var params = '';
for( i in a ){
params = '';
len = a[i].length;
fx = a[i][0]; // getting the function name
a[i].splice( 0, 1 ); // removing it from array
if( len > 1 ){
params = a[i].join(", "); // trying to turn the parameters into the right format, but this is turning it into strings I think
params = params.replace(/\\'/g,'\''); // bc i was adding slashes with PHP
}
window[fx](params);
}
I don't have to use arrays to do this. I don't understand JS OOP (haven't tried yet), though I am comfortable with PHP OOP, so I don't know if there is a way to do this there.
Any help on passing multiple parameters would be appreciated.
Thanks.
First thing to do: Scrap your entire code, start over. Your approach will not get you anywhere where you'd want to be. (Unfortunately I can't tell you where you'd want to be because I cannot make sense of your example.)
There are three ways to call a function in JavaScript.
function foo() { console.log(arguments); }
// 1. directly
foo(1, 2, 3);
// 2. trough Function.call()
foo.call(this, 1, 2, 3);
// 3. trough Function.apply()
var args = [1, 2, 3];
foo.apply(this, args);
call and apply are similar. They let you decide which object the this keyword will point to inside the function (that's the important bit!).
apply accepts an array of arguments, call accepts individual arguments.
The closest thing to call() is PHP's call_user_func(). The closest thing to apply() is PHP's call_user_func_array().
JavaScript objects share something with PHP arrays: They are key/value pairs.
// an anonymous function assigned to the key "foo"
var obj = {
foo: function () { console.log(arguments); }
};
This means you can access object properties either with the dot notation:
// direct function call
obj.foo(1, 2, 3);
Or through square bracket notation (note that object keys are strings):
var funcName = "foo";
obj[funcName](1, 2, 3);
obj[funcName].call(obj, 1, 2, 3);
obj[funcName].apply(obj, [1, 2, 3]);
Square bracket notation gives you the freedom to choose an object property dynamically. If this property happens to be a function, apply() gives you the freedom to choose function arguments dynamically.
Every top-level function that has not been declared as the property of some object will become the property of the global object. In browsers the global object is window. (So the function foo() in my first code block above really is window.foo.)
Note that this does not work like in PHP. It will point to the object the function has been called on, not the object the function "belongs to". (The concept "belongs to" does not really exist in JavaScript. Things can be modeled that way, but it's only a convention.)
With direct calling (obj.foo(1, 2, 3)), this will point to obj. With call and apply, this will point to whatever object you want to. This is a lot more useful than it sounds at first. Most of the time when you want to call functions dynamically, you will end up using apply.
Check out Function.apply:
function test(a, b) { console.log([a, b]) }
test.apply(null, [1, 2]); // => [ 1, 2 ]
Late to the party, but now with ES6 you can simply do
function FunctionX(a,b,c,d){
return a + b + c + d;
}
let fx = "FunctionX";
let params = [ 1, 10, 100, 200 ];
let answer = window[fx]( ... params);
let answer2 = globalThis[fx]( ... params ); // this is more cross-platform
to unpack your argument array

How did the value of Object Array in javascript be operated?

I feel puzzled when I rethink of these two functions:
The first one goes like this:
var test = [1,2,3];
var ele = test[0];
ele= 2;
alert(test[0]);
The result is 1. I think this is obvious. But when I meet this:
var test = [{id:1},{},{}];
var ele = test[0];
ele.id = 2;
alert(test[0].id);
The result turns to be 2
So could anyone tell me that how the javascript work when it happens like this in the object array?
In JavaScript, objects are assigned by reference, rather than copied in memory. So if you assign an existing object to a different variable, both will point to the same object in memory. Modifications to either will therefore be reflected in both.
var a = {id: 1, name: "bob"};
var b = a;
console.log(b.name); // bob
b.name = "bill";
console.log(a.name); // bill
So in your example, executing ele.id = 2; operates on the memory location holding the object at test[0]. The change to the id property of that object is reflected in both variables referencing it (test[0], ele)
Note that if you had assigned the entire array test to ele, modifying one of the array members would have been reflected in both test, ele since Arrays are objects in Javascript:
var test = [1,2,3];
// Assign array test to ele
var ele = test;
// Modify one member
ele[0] = 2;
alert(test[0]); // 2

JavaScript array of pointers like in C++

I'm faced with a situation in JavaScript when I need to update an object via its pointer similar to ะก++ array of pointers to objects
Example code for my issue:
var foo = new Array();
var bar = function(){
this.test = 1;
foo.push(this); // push an object (or a copy of object?) but not pointer
};
var barInst = new bar(); // create new instance
// foo[0].test equals 1
barInst.test = 2;
// now barInst.test equals 2 but
// foo[0].test still equals 1 but 2 is needed
So, how can I solve this? Should I use a callback or something like this or there is an easy way to help me to avoid copying the object instead pushing the raw pointer into an array?
JS is pass-by-value, so your original assignment was this.test = the value of 1, in my example, it's this.test = the object pointed to by ptr, so when I change ptr this.test changes as well.
var foo = [],
ptr = {val: 1},
bar = function(){
this.test = ptr;
foo.push(this); // push an object (or a copy of object?) but not pointer
},
barInst = new bar(); // create new instance
// foo[0].test.val equals 1
ptr.val = 2;
// foo[0].test.val equals 2
Although if you thought that foo.push(this); was similar, it isn't. Since this is an object, the array will indeed contain "raw pointers" to objects, just like you want. You can prove this simply:
foo[0].test = 3;
// barInst.test === 3
Which shows that it is indeed a pointer to the object that was pushed onto the array
"create object method pointer"
Object.defineProperty(Object.prototype,'pointer',{
value:function(arr, val){
return eval(
"this['"+arr.join("']['")+"']"+
((val!==undefined)?("="+JSON.stringify(val)):"")
);
}
});
ex of use
var o={a:1,b:{b1:2,b2:3},c:[1,2,3]}, arr=['b','b2']
o.pointer(arr) // value 3
o.pointer(['c',0], "new_value" )

Categories

Resources