I have a two-part issue.
1) I need to access a list of unique values nested within a complicated object. I am able to output the object via a console.log as such:
console.log(dataStore);
This outputs the following (in part):
`Object
getResponses: function getResponses(ids)
arguments: null
caller: null
length: 1
name: "getResponses"
prototype: Object
__proto__: function ()
<function scope>
Closure
responseCache: Object
12345: gr.Response
12346: gr.Response
etc...
getImg: function (imageId)
etc... `
I need a call that gathers the list of numeric values under responseCache: 12345, 12346, 12347, etc. The total amount of these values may very. Could be 10, could be 100 in the list.
2) I need to create a conditional statement that compares the value for a variable that is not a part of the object above. For example:
variableX = variableXvalue;
if ("variableXvalue" is one of the unique values in "responseCache") {
//then do this
}
Not sure if it matters for the purposes of the question here, but the variableX is in a loop that iterates through attributes on a page. It loops through all matching tags/attributes on a page, and needs to compare those attribute values with the full list of responseCache values each time it loops.
Thank you for considering this question.
Let's look at an example of how this sort of code could be written.
var obj = (function() {
var responseCache = {
12345: 12,
12348: 34,
12355: 56
};
return {
getResponses: function getResponses(ids) {
return responseCache[id];
}
};
})();
console.log(obj);
If you run that code in your console, you'll get able to drill down and see essentially the same output as what you're seeing. Now, how can you directly access responseCache? You can't. It's effectively private and only directly accessible from within that closure. Outside code cannot access that variable directly. You can only indirectly access it if any functions on obj use it.
Related
I am running a self invoked function, and I would like to change the Array object in it, and only in its scope.
var foo = "Foo Outer";
(function(){
var foo = 'Foo Inner !';
console.log('INNER>',foo);
// prints INNER> Foo Inner !
var Array = {};
var Array = Object.getPrototypeOf([]).constructor;
Array.prototype.filter = ()=>{return "Array filter inner"}
console.log('INNER> array filter literal:', [1,2,3].filter(x=>x));
// prints INNER> array filter literal:Array filter inner
})()
console.log('OUTER> foo ', foo);
// prints OUTER> foo Foo outer
console.log('OUTER> Array filter', [1,2,3].filter(x=>x));
// prints OUTER> Array filter Array filter inner
// I want ->
// OUTER> Array Filter [1,2,3]
How can I variable shadow Array and its methods only inside the scope of the self invoked function, while keeping it the same for the rest of the script ?
So in javascript, Arrays are passed around by reference. That means that you're always referencing the same "source" thing. If you mutate the array in one place, those changes will be reflected on all the references to that array.
That means that if you want changes to one version of shadow Array to be different than another version, you need to make a copy of it and change that copy.
It also looks like what you're really trying to accomplish here is a local monkey patch of the native array filter method. I believe that the technique you're looking for here is a proxy. Using a proxy, you can intercept the call to the native filter() method and substitute in your own. Proxies were introduced in ECMAScript2015.
see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy
This previous answer might be most relevant to you Extending Array / Proxy in ES6 correctly?
Apparently the answer (as was written in the comment by #Bergi) is that it isn't possible to variable shadow Array)
The following code example is what i found here on the internet
arr[1].push('native', 'laravel');
with a description of
Here we use the javascript array push method to add two new elements(items) to the inner sub-array.
which was exactly what i wanted to accomplish!
But when i tried it several times by my self it always went like this:
let mainArr = [];
console.log("mainArr: ", mainArr);
// Working as expected: created an empty array
let emptyArr = [];
console.log("emptyArr: ", emptyArr);
// Working as expected: created an empty array
for (i = 0; i < 3; i++) {
mainArr.push(emptyArr);
}
console.log("mainArr: ", mainArr);
// Working as expected: pushed 3 times the "emptyArr" into "mainArr"
let newArr = [["X"], [90]];
mainArr[0].push(newArr);
console.log("mainArr[0]: ", mainArr[0]);
console.log("mainArr[1]: ", mainArr[1]);
console.log("mainArr[2]: ", mainArr[2]);
// NOT working as expected: pushed "newArr" into every of the three arrays within the "mainArr" !!!
// How can I solve this?
Would love to hear some tips :)
Thanks!
That's because arrays are objects in JS, ie non-primitive type of variables.
Long explanation
Javascript has 5 data types that are passed by value: Boolean, String, Number, null and undefined. These are called primitive types.
And it has 3 data types that are passed by reference: Array, Function, and Object. These are all technically Objects.
When you assign a non-primitive value to a variable what happens is that a reference of that value is assigned, not the actual value. Ie, that reference points to the object’s location in memory. The variables don’t actually contain the value.
In your case
When you push emptyArr 3 times you don't insert the value (ie. a new empty array) you insert the same memory reference of emptyArr. These 3 references point to the same location in memory that has that value of an empty array. Given that, now you insert newArr to the referenced value of the mainArr[0], but the rest elements mainArr[1], mainArr[2] are references that point to the same value as the one pointed by mainArr[0].
Hope it makes sense.
Otherwise, You can refer here
https://stackoverflow.com/a/430958/4700560 or I also find this article very visually descriptive and helpful https://blog.penjee.com/passing-by-value-vs-by-reference-java-graphical
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.
I have a scoped variable that stores an archive:
viewScope.MY_SCOPE = new Array();
viewScope.MY_SCOPE.push(["id0", 0, true]);
viewScope.MY_SCOPE.push(["id1", 1, false]);
viewScope.MY_SCOPE.push(["id2", 3, true]);
now I want to update one of item.
viewScope.MY_SCOPE[1][2] = "true";
and this fails with the error:
Error while executing JavaScript action expression put(int index,FBSValue value) not supported in JavaWrapperObject.
How do I update a specific item in the array?
When adding the SSJS array object to the scope, it is converted to a java.util.Vector. Hence, if you want to set the value, you should use
viewScope.MY_SCOPE[1].set(2,"true");
instead of viewScope.MY_SCOPE[1][2] = "true";.
I think the problem is that using ...[2] = "true" tries to execute the put method of the given object. While put is available in Maps like HashMaps or the scope maps, Vectors use set instead of put to change values. For that reason, you get the "action expression put(...) not supported" error. In contrast to this, it's no problem to get the variable with viewScope.MY_SCOPE[1][2] because the get method is availiable in both HashMaps and Vectors.
When storing arrays in scope variables, I like to put the value into a properly typed javascript variable, make edits, and then replace the scope variable with the updated value.
In your case I would do the following:
var tempVar = viewScope.MY_SCOPE.toArray(); //convert to array to make sure properly typed
tempVar[1][2] = true;
viewScope.put(MY_SCOPE,tempVar);
Update:
After testing your code along with mine, I too get the same error. To be honest, I never would have messed with multi dimensional arrays in the first place. This is a perfect opportunity to use an array of objects:
var tempVar = []; // initialize the array
tempVar.push({val1:"id0",val2:0,val3:true});
tempVar.push({val1:"id1",val2:1,val3:false});
tempVar.push({val1:"id2",val2:3,val3:true});
viewScope.put("MY_SCOPE",tempVar);
Then to change the desired value:
var tempVar = [];
tempVar = viewScope.get("MY_SCOPE");
tempVar[1].val3 = true;
viewScope.put("MY_SCOPE",tempVar)
I tested this method and it works fine.
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'";