Reference indexed collection in Javascript - javascript

I search a way to get in Javascript an object which index by reference.
something like:
var myRefMap = new RefMap();
var a = [{}, [], function () {}];
myRefMap.set(a[0], true);
myRefMap.set(a[1], { hello: 'world' });
myRefMap.set(a[2], 42);
myRefMap.has(a[0]); // true
myRefMap.has(a[1]); // true
myRefMap.has(a[2]); // true
myRefMap.has({}); // false
myRefMap.has([]); // false
myRefMap.has(function () {}); // false
I need this object in order to optimize and avoid an actual heavy array search, during tree browsing within circulars references.
Thanks,

One basic way to do this, provided all the stored values are objects would be something like:
(function () {
var instCount = 0;
self.RefMap = function () {
instCount ++;
var propName = '__RefMap' + instCount + '__';
this.has = function (o) {
return propName in o;
};
this.set = function (o) {
o[propName] = true;
}
this.remove = function (o) {
delete o[propName];
}
}
}());
//then use it like
var myRefMap = new RefMap();
Edit: Arrays and functions are objects too. And you can use Object.defineProperty to hide the "marking" property, depending on the browsers you target.

If your code is saying that you want that last condition to evaluate to true, then just using an object and the 'in' directive should work fine.
var mystuff = {};
var a = [{}, [], function () {}];
mystuff[a[0]] = true;
mystuff[a[1]] = {hello:'world'};
mystuff[a[2]] = 42;
(a[0] in mystuff); // true
({} in mystuff); // true
(a[1] in mystuff); // true
(a[2] in mystuff); // true
If however you wanted ({} in mystuff) to evaluate to false, that's a lot different.

Related

Why won't a boolean object property update?

I have an array of objects. Each object has a method that should update a boolean property in the same object called 'found'.
When I call the function, the property does not update. I am not sure why.
I thought that the 'found' property would be accessible but it isn't??
I have created a minimal version of the problem here:
https://codepen.io/sspboyd/pen/XWYKMrv?editors=0011
const gen_s = function () { // generate and return the object
let found = false;
const change_found = function () {
found = true;
};
const update = function () {
change_found();
};
return {
change_found,
found,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].found); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].found);
When your change_found function changes the value of found, it's changing the value pointed to by your let found variable, but the object returned by your gen_s function still points to the old value.
You can fix your code using the 'holder' pattern, like this:
const gen_s = function () { // generate and return the object
let foundHolder = {value: false};
const change_found = function () {
foundHolder.value = true;
};
const update = function () {
change_found();
};
return {
change_found,
foundHolder,
update
};
};
const s_arr = []; // initialize an array
s_arr.push(gen_s()); // add a new s object to the array
console.log(s_arr[0].foundHolder.value); // returns 'false'
s_arr.forEach((s) => {
s.update();
});
console.log(s_arr[0].foundHolder.value);
Or even better, use a class:
class S {
constructor() { this.found = false; }
change_found() { this.found = true; }
update() { this.change_found(); }
}
const s_arr = [];
s_arr.push(new S());
console.log(s_arr[0].found);
s_arr.forEach(s => s.update());
console.log(s_arr[0].found);

How to handle nested refrence passed to a function in javascript?

I have some objects:
var a = {
toString: () => 'a'
}
var b = {
toString: () => 'b'
}
function someFunc(...params) {
params.forEach((p)=>{
console.log(p); //consoles - {toString: ƒ toString()} for both objects
})
}
someFunc(a,b);
I want to pass these objects to some functions like memoize function, isEqual function, deepCopy function etc. I don't want to use any third party library such as lodash. I want to understand how do we differentiate between these objects inside someFunc?
I have tried : JSON.parse(JSON.stringify()) but this doesn't work in case of objects having functions.
Codesandbox
Edit:
I have tried Implementing the object refrence method.
function someFunc() {
let cache = {};
return function (...params) {
var ObjectReference = [];
let set = {};
params.forEach((p) => {
ObjectReference.push(p);
set["ObjectReference." + ObjectReference.indexOf(p)+p] = true;
});
let key = JSON.parse(JSON.stringify(set))
console.log(key);
if (cache[key]) {
console.log("cached");
} else {
cache[key] = true;
console.log("Not cached");
}
};
}
mem(a, b); //not cached
mem(b, a); //cached - should be **not cached**
console.log(key); gives:
{ObjectReference.0a: true, ObjectReference.1b: true}
{ObjectReference.0b: true, ObjectReference.1a: true}
As we can see the two objects are different. I'm unable to understand why it goes inside cached block?
Edit 2 : The above is happening because the key is getting set as [object object]. To avoid this I tried using Map and WeakMap but they are failing for
mem(a, b); //not cached
mem(a, b); // not cached

How can I see if my object updates in a loop?

I want this code to check if one of the keys in the "states" object updates from false to true, and if it does, then run the code inside of the if-statement. For some reason, even if I update the states variable manually (like I did here). The code never runs.
I'm using the "compareMe" variable to hold the last version of the "states" object by setting it equal to the "states" object at the end of the loop.
I'm sure this is not the best approach, any ideas would help a ton.
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms * 1000)
})
}
var states = { Dad: false, Mom: false, Brother: false, Sister: true }
var compareMe = {}
var loop = 0;
(async () => {
while(true) {
loop++
if (loop === 5) {
states.Dad = true
}
for (const key of Object.keys(states)) {
if(compareMe[key] === false && states[key] === true) {
console.log("Opening Door")
} else {
console.log('No change')
}
}
compareMe = states;
await sleep(5)
}
})();
What you are doing with compareMe = states is create a new reference on the same object, so whenever you mutate states, the mutation reflects on compareMe.
You should perform a clone instead:
compareMe = { ...states };
You can use proxy object to monitor your object for changes.
original answer with more details
var targetObj = {};
var targetProxy = new Proxy(targetObj, {
set: function (target, key, value) {
// function called
console.log(`${key} set to ${value}`);
target[key] = value;
return true;
}
});
targetProxy.newProp = "test"; // console: 'newProp set to test'
However it would be easier for you to just use a library to monitor and watch variables. There are many libraries and frameworks to do this.
Library: Obseravble-Slim
Framework: Angular

_.each find value in array return true or false. using underscore js

//find value in array using function checkValue using underscoreJS _.each.
//return true, else false.
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arg) {
_.each(helloArr, function(helloArr, index) {
if (arg[index] === index) {
return true;
}
return false;
});
};
alert(checkValue("hola"));
The problem with your code is that, _.each will iterate through all the elements of the array and call the function you pass to it. You will not be able to come to a conclusion with that, since you are not getting any value returned from it (unless you maintain state outside _.each).
Note that the values returned from the function you pass to _.each will not be used anywhere and they will not affect the course of the program in any way.
But, instead, you can use _.some as an alternate, like this
var checkValue = function(arg) {
return _.some(helloArr, function(currentString) {
return arg === currentString;
});
};
But, a better solution would be, _.contains function for this purpose. You can use it like this
var checkValue = function(arg) {
return _.contains(helloArr, arg);
};
But, since you have only Strings in the Array, the best solution would be to use Array.prototype.indexOf, like this
var checkValue = function(arg) {
return helloArr.indexOf(arg) !== -1;
};
Try this:
var helloArr = ['bonjour', 'hello', 'hola'];
var checkValue = function(arr, val) {
_(arr).each(function(value) {
if (value == val)
{return console.log(true);}
else {return console.log(false);}
});
};
console.log(checkValue(helloArr,'hello'));
/* Output
false
true
false*/

Ternary execution of functions

I'm working on a project that will do a lot of processing of numbers in arrays. To try and encapsulate some condition logic I've done something like
//ignore the fact that it's a bad idea to extend JS base types
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
So this takes a boolean expression and executes the funcA if the bool is true, and executes funcB if it is not. The kicker here is that args should be the array itself. So here's a fiddle and the code:
var newData = [1, 2, 3, 4];
Array.prototype.ifThenElse = function (statement, funcA, funcB, args) {
return (statement) ? funcA(args) : funcB(args);
};
function timesTwo(arr) {
return arr.map(function (val, ix) {
return val * 2;
});
};
function timesThree(arr) {
return arr.map(function (val, ix) {
return val * 3;
});
};
var nArray = newData.ifThenElse(newData[0] < newData[1],timesTwo,timesThree,newData);
//console.log('This is the nArray ' + nArray);
var expression = !!0 > 100;
var expression2 = !!100 > 0;
var dData = newData.ifThenElse(expression, timesThree, timesTwo, newData);
var eData = newData.ifThenElse(expression2, timesThree, timesTwo, newData);
console.log(dData);//2,4,6,8 <=expression is false, timesTwo called
console.log(eData);//3,6,9,12 <=expression is true, timesThree called
I don't want to hardcode the functions that can be passed to `ifThenElse, but I'd also looking to see if there's a clever solution to make this more LINQ-like and somehow have newData automatically passed as the last parameter of the method
The value of this in a method called from an object generally refers to the object on which it was called.
Because your Array.prototype method is called on an Array, the value of this in the method is a reference to the Array.
So just pass this to pass the Array.
return (statement) ? funcA(this) : funcB(this);

Categories