I want to add a Symbol property to an object for comparing.
Here is the way:
let _sym = Symbol('sym');
let a = {};
a[_sym] = Symbol('_');
let b = {};
b[_sym] = Symbol('_');
console.log(a[_sym] === b[_sym]); // false
Both a and b are objects. So, I can write:
let _sym = Symbol('sym');
Object.prototype[_sym] = Symbol('_');
Object.Equals = function (x, y) {
return x[_sym] === y[_sym];
};
let a = {};
let b = {};
console.log(Object.Equals(a, b)); // true
But the result was changed.
What's wrong here?
in the first case you assign to every object a new symbol instance
in the second, using prototype each object shares the same property, so they are equal
to compare, this code would be equal to the second case (but only for these 2 objects):
let _sym = Symbol('sym');
let val = Symbol('_');
let a = {};
a[_sym] = val;
let b = {};
b[_sym] = val;
console.log(a[_sym] === b[_sym]); // true
For example:
var a = {};
var b = {};
Different objects
a === b // false
The same underlying prototype
a.toString === b.toString // true
Related
I have a memoization problem. There is a value calculated between two objects and I want to store it, such that I can pass in the two number id's from the objects to get the value regardless of the order that I pass in the id's.
I could just store it under both of the id's, or check for both id's, but I was wondering out of curiosity if there was a more efficient solution.
Examples:
Check for both id's:
var storedValues = {};
function generateValue(a, b)
{
if (storedValues[a.id][b.id])
return storedValues[a.id][b.id];
else if (storedValues[b.id][a.id])
return storedValues[b.id][a.id];
else
// Generate value, store it under a.id and return it
}
Store it under both id's:
var storedValues = {};
function generateValue(a, b)
{
if (storedValues[a.id][b.id])
return storedValues[a.id][b.id];
else
// Generate value, store it under a.id and b.id and return it
}
How can I generate a unique map key from two numbers, so I can retrieve the value with those two numbers regardless of the order that I pass them in?
I'm using JavaScript btw.
There are many ways to that, first of all, you can just create a single key for the objectkey e.g.: '11_12'
var storedValues= {};
var id1 = 11;
var id2 = 12;
var calculatedvalue = id1 * id2;
var objectkey = id1+'_'+id2;
storedValues[objectkey] = calculatedvalue;
it is also possible to use nested object:
var storedValues= {};
var id1 = 11;
var id2 = 12;
var calculatedvalue = id1 * id2;
if (storedValues[id1] == null ){
storedValues[id1] = {};
}
storedValues[id1][id2] = calculatedvalue;
More over your ids are always integer you can use Arrays
var storedValuesArr = [];
var id1 = 11;
var id2 = 12;
var calculatedvalue = id1 * id2;
if (!Array.isArray(storedValuesArr[id1])){
storedValuesArr[id1] = [];
}
storedValuesArr[id1][id2] = calculatedvalue;
and in order to return the values regardless of the order:
function generateValue(a, b)
{
if (storedValues[a.id] != null && storedValues[a.id][b.id] !== null)
return storedValues[a.id][b.id]
else if (storedValues[b.id] != null && storedValues[b.id][a.id] !== null)
return storedValues[b.id][a.id];
else
// Generate value, store it under a.id and return it
}
You could sort the keys for setting the value and for getting the value.
function getValue(object, key0, key1) {
return [key0, key1]
.sort((a, b) => a - b)
.reduce((o, k) => (o || {})[k], object);
}
function setValue(object, key0, key1, value) {
var keys = [key0, key1].sort((a, b) => a - b),
last = keys.pop();
object[keys[0]] = object[keys[0]] || {};
object[keys[0]][last] = value;
}
var object = {};
setValue(object, 3, 7, 42);
console.log(getValue(object, 3, 7));
console.log(getValue(object, 7, 3));
console.log(object);
Different approach by using the keys a given.
function getValue(object, key0, key1) {
return key0 in object ? object[key0][key1] : object[key1][key0];
}
function setValue(object, key0, key1, value) {
object[key0] = object[key0] || {};
object[key0][key1] = value;
}
var object = {};
setValue(object, 3, 7, 42);
console.log(getValue(object, 3, 7));
console.log(getValue(object, 7, 3));
console.log(object);
I'm looking for a one-liner way of checking if a key exists and if it doesn't create it.
var myObject = {};
//Anyway to do the following in a simpler fashion?
if (!('myKey' in myObject))
{
myObject['myKey'] = {};
}
Short circuit evaluation:
!('myKey' in myObject) && (myObject.myKey = {})
myObject['myKey'] = myObject['myKey'] || {};
Comment:
I generally prefer the answers provided by #Nindaff and #MoustafaS, depending on the circumstances.
For completeness, you can create key/values, using Object.assign for any keys that did not exist. This is most useful when you have default options/settings you want to use, but allow users to overwrite via arguments. It'd look like this:
var myObject = {};
myObject = Object.assign( { 'myKey':{} }, myObject );
Here's the same thing with a little more output:
var obj = {};
console.log( 'initialized:', obj);
obj = Object.assign( {'foo':'one'}, obj );
console.log( 'foo did not exist:', obj );
obj = Object.assign( {'foo':'two'}, obj );
console.log( 'foo already exists:', obj );
delete obj.foo;
obj = Object.assign( {'foo':'two'}, obj );
console.log( 'foo did not exist:', obj );
Note: Object.assign is not available in IE, but there's a Polyfill
If you want to get the value for a certain key and insert a new default value for that key if it doesn't exist and return that default value, then here you go in a single line:
> x = {}
{}
> x['k']
undefined
> x['k'] ?? (x['k'] = 23) // Insert default value for non-existent key
23
> x['k']
23
> x['z'] = 5
5
> x['z'] ?? (x['z'] = 42) // Will not insert default value because key exists
5
With the new nullish assignment operator this can be simplified to:
x['k'] ??= 23
Obviously you need to add some extra work for keys which can map to null.
You can use the Logical nullish assignment (??=)
var test = {};
(test.hello ??= {}).world ??= "Hello doesn't exist!";
You can use hasOwnProperty or typeof for checking exits or undefine...
There is a designated Proxy internal type that's suitable for this task:
const myObj = new Proxy({}, {
get (target, key) {
return target.hasOwnProperty(key) && target[key] || (target[key] = {});
}
});
typeof myObj.foo === 'object' && (myObj.bar.quux = 'norf') && myObj.bar.quux === 'norf';
You can use Object.keys(), Object.hasOwnProperty()
var key = {myKey:{}}, prop = Object.keys(key).pop(), myObject = {}; if (!myObject.hasOwnProperty(prop)) {myObject[prop] = key[prop]}
console.log(myObject)
JavaScript ES9 (ECMAScript 2018) introduced the spread operator:
myObject={myKey: {}, ...myObject}
myKey will be created if it doesn't already exist but wont be overwritten if it does. For example:
let obj = {a:1,b:2}
let test1 = {...obj,a:3} // == {a:3,b:2}
let test1 = {a:1,b:2,a:3} // == {a:3,b:2}
let test2 = {a:3,...obj} // == {a:1,b:2}
let test2 = {a:3,a:1,b:2} // == {a:1,b:2}
If you dont know whether or not the key of the object exists you you can do something like
object.key = (object.key || default value) operation
Example
const user = {};
user.stat = (user.stat || 0) + 1; // 1
And if you were to call this expression multiple times you'd get the expected behaviour
Example
const user = {};
user.stat = (user.stat || 0) + 1; // 1
user.stat = (user.stat || 0) + 1; // 2
user.stat = (user.stat || 0) + 1; // 3
Its effectively the same using a ternary operator like so
user.stat = user.stat ? user.stat + 1 : 0;
but more compact
function Obj() {}
var a = new Obj();
var b = new Obj();
var hash = {};
hash[a] = 1;
hash[b] = 2;
console.log(hash[a]); // 2
console.log(hash[b]); // 2
console.log(a == b); // false
I thought hash would use the pointer address of a and b as keys, is that not true?
Figured it out. JS hash use toString() as the key. For example this works:
function Obj() {
var str = "" + Math.random();
this.toString = function() {
return str;
}
}
var a = new Obj();
var b = new Obj();
var hash = {};
hash[a] = 1;
hash[b] = 2;
console.log(hash[a]); // 1
console.log(hash[b]); // 2
console.log(a == b); // false
you mixed with object class and array key.
function Obj() {} //create Obj object
var a = new Obj(); //a is instance Obj object
var b = new Obj(); //b is instance Obj object
var hash = {}; //create hash object
hash[a] = 1; //its not create key array in hash object - hash{[{a}]:1}
hash[b] = 2; // hash{[{b}]:2}
//hash = {[Object Object]:2}
console.log(hash[a]); //its return last assign value - 2
console.log(hash[b]); //2
assign object key is not valid
simple thing is
function Obj() {}
var a = new Obj();
var b = new Obj();
a={"name":"David"};
b={"name":"Naest"};
var hash = {};
hash[0] = a;
console.log(hash[0].name); //David
hash[1] = b;
console.log(hash[1].name); //Naest
if u want overwrite object key as another object key
function Hash(){
var hash = new Object();
this.put = function(key, value){
if(typeof key === "string"){
hash[key] = value;
}
else{
if(key._hashtableUniqueId == undefined){
key._hashtableUniqueId = UniqueId.prototype.genarateId();
}
hash[key._hashtableUniqueId] = value;
}
};
this.get = function(key){
if(typeof key === "string"){
return hash[key];
}
if(key._hashtableUniqueId == undefined){
return undefined;
}
return hash[key._hashtableUniqueId];
};
}
function UniqueId(){
}
UniqueId.prototype._id = 0;
UniqueId.prototype.genarateId = function(){
return (++UniqueId.prototype._id).toString();
};
Usage
function Obj() {}
var a = new Obj();
var b = new Obj();
var hash = new Hash();
hash.put(a,1);
hash.put(b,2);
console.log(hash.get(a)); //1
I have a complex javascript object with an array. When I try to set the value for one attribute of an index, it's applied to all items of the array.
Here is a basic example:
var obj = new Object();
obj.arr = [];
obj.arr[0] = {pos:[0,0]};
obj.arr[1] = {pos:[0,0]};
Now if i set a value for an attribute of the object, via a specific index,
obj.arr[0].pos = [10,10];
obj.arr[1].pos = [5,5];
Here it seems to be setting the value [5,5] for both items of the array. The resulting values are:
console.log(obj.arr[0].pos) returns [5,5]
and
console.log(obj.arr[1].pos) also returns [5,5]
My actual object is far more complex, but this is the basic idea of what's happening...
Any ideas?
They share the same link, i.e. several variables/properties of an object are referring to the same value.
Exact answer (where's the error) depends on how your object is composed.
var nested = {a:1};
var obj = {arr:[]};
obj.arr[0] = {pos:0, n:nested};
obj.arr[1] = {pos:0, n:nested};
obj.arr[0].pos = 1;
obj.arr[1].pos == 1; // false
obj.arr[0].nested.a = 2;
obj.arr[1].nested.a == 2; // true
Assignment of the same array/object literals is not the same.
var a = [0];
var b = [0];
b[0] = 1;
a[0] == 1; // false
b = a;
a[0] = 2;
b[0] == 2; // true
a = b = [0];
a[0] = 1;
b[0] == 1; // true
when constructing an object using methods from other objects as an attribute name get Syntax Error: Unexpected token . - cannot find correct syntax
var R = function(a) { this.arg = a; };
R.prototype.name = function() { return this.arg; }
var r1 = new R('abc');
var name1 = r1.name(); // => "abc"
var o1 = { 'abc': r1 } // this works with constant
var o2 = { name1: r1 } // does not work with variable (see answer)
var o3 = { r1.name(): r1 } // this fails - syntax
var o4 = { 'abc': r1.name() } // this works
have tried { (r1.name()): r1 }, but that fails as well.
please note that strings and integers are evaluated as barewords whereas methods and variables are not:
var o5 = { e.1: 123 } // fails
var o6 = { 'e.1': 123 } // succeeds
var o7 = { 1: 123 } // succeeds
var o8 = { '1': 123 } // same as o7
var o2 = { name1: r1 } // this works with variable
This has the same meaning as:
var o2 = { 'name1': r1 }
In other words, it's still treating name1 as a literal string. The key in an object literal must be a constant or a so-called "bareword" -- this is a restriction of the language. Variables and function invocations cannot be used as keys in object literals (but they can be used as values). Using variables will appear to work, but the variable name will be used as the key and not the variable's value.
You will have to do something like:
var o2 = {};
o2[name1] = r1;
var o3 = {};
o3[r1.name()] = r1;
var o4 = { 'abc', r1.name() }
this one should be:
var o4 = { 'abc': r1.name() }
You could create your own property setter
function setProperty (prop,val,obj) {
if (typeof prop === "undefined" || typeof val === "undefined") return undefined;
if (typeof obj === "undefined") obj = {};
obj[prop] = val;
return obj;
}
// use 1
var o1 = setProperty(r1.name(),r1);
// use 2
var o2 = {};
setProperty(r1.name(),r1,o2);