suppose we want to create a new object.
let myObject = {};
and we have some property that exists in another object like :
let b = { foo: "bar"};
is it possible to check if b?.foo append foo to myObject inline in the declaration of the object?
something like this :
let myObject = { b?.foo }
I think the best you can do is :
let myObject = {
some: "prop",
...(b?.foo && {foo:b.foo})
}
Or if you want to pass all the object
let myObject = {
some: "prop",
...(b?.foo && b)
}
The code below does what I want, but I would like to avoid eval. Is there a function in Javascript that looks up an object by its name as defined by in a string?
myobject = {"foo" : "bar"}
myname = "myobject";
eval(myname);
Some context: I am using this for an application in which a large number of nodes in the dom has a html5 data-object attribute, which is used in the handler function to connect back to the model.
Edit: myobject is neither global nor local, it is defined in one of the parent frames of the handler.
If variables are global then:
myobject = {"foo" : "bar"};
myname = "myobject";
window[myname].foo
DEMO
For local:
(function(){
myobject = {"foo" : "bar"};
myname = "myobject";
alert( this[myname].foo );
})();
DEMO
Local Variable Solution:
You could make all objects that you want to access with a string properties of another object. For example:
var objectHolder = {
myobject: {"foo" : "bar"},
myobject2: {"foo" : "bar"},
myobject3: {"foo" : "bar"}
};
And then access your desired object like this:
var desiredObject = objectHolder["myobject"];
Global Variable Solution:
You can access global variables using a string like this:
window["myobject"];
This question is pretty old, but since it's the top result on Google for the query "javascript get object from string", I thought I'd share a technique for longer object paths using dot notation.
Given the following:
var foo = { 'bar': { 'alpha': 'beta' } };
We can get the value of 'alpha' from a string like this:
var objPath = "bar.alpha";
var alphaVal = objPath.split('.')
.reduce(function (object, property) {
return object[property];
}, foo);
// alphaVal === "beta"
If it's global:
window.foo = { 'bar': { 'alpha': 'beta' } };
Just pass window as the initialValue for reduce:
var objPath = "foo.bar.alpha";
var alphaVal = objPath.split('.')
.reduce(function (object, property) {
return object[property];
}, window);
// alphaVal === "beta"
Basically we can use reduce to traverse object members by passing in the initial object as the initialValue.
MDN article for Array.prototype.reduce
since window is a global namespace, you could simply use
window[myname]
We use a fair bit of dotted notation variable structures. Needed a way to traverse them without erroring on undefined, and return value or undefined as the answer. Hope this helps.
function getValueOrUndefined(id) {
let parent = window;
if (id.indexOf(".") !== -1) {
let current = null;
let child = undefined;
let names = id.split(".");
for (let i = 0; i < names.length; i++) {
current = names[i];
child = parent[current];
if (child === undefined)
return child;
else
parent = child;
}
return child;
}
return parent[id];
}
I know you can not set a key value dynamically, but what about the value?
I'm asking b.c. I need to know the best way to initialize an object. Here is how I do it currently:
var object_pipe = {
model : 'MUserAny',
page : {
email: '0'
},
args : {
foo : '0'
}
};
object_pipe.args.foo = localStorage.foo; // Statement A
I'd like to put statement A directly in the object literal but am not sure if it is possible or the correct syntax.
Aslo, Do I need to explicitly declare properties when I can not set them in the object literal as in here...does page need to be there?
var object_pipe = {
model : 'MUserNew',
page : {
}
};
for( var key in form_elements ) {
object_pipe.page[ form_elements[key].name ] = form_elements[key].value ;
}
You don't need to explicitly declare variables but you can just initialize the key with an empty "whatever", can be an array, string, object literal etc. You can add properties later.
var o = {
a: [],
b: {}
}
o.a[0] = 'foo'
o.b.c = 'baz'
o.d = 'pom' // New
What's wrong with this:
var object_pipe = {
model : 'MUserAny',
page : {
email: '0'
},
args : {
foo : localStorage.foo
}
};
DEMO
I'd like to have a set of objects in Javascript. That is, a data structure that contains only unique objects.
Normally using properties is recommended, e.g. myset["key"] = true. However, I need the keys to be objects. I've read that Javascript casts property names to strings, so I guess I can't use myset[myobject] = true.
I could use an array, but I need something better than O(n) performance for adding, finding and removing items.
It needs to be able to tell objects apart by reference only, so given:
var a = {};
var b = {};
then both a and b should be able to be added, because they're separate objects.
Basically, I'm after something like C++'s std::set, that can store Javascript objects. Any ideas?
ES6 provides a native Set:
let s = new Set();
let a = {};
let b = {};
s.add(a);
console.log(s.has(a)); // true
console.log(s.has(b)); // false
Here's a mad suggestion ... key it on the result of JSON.stringify(object)
It's not possible for all objects, but if your object has a .toString() method implemented, it is:
var x = {toString: function(){ return 'foo'; }};
var y = {toString: function(){ return 'bar'; }};
var obj = {};
obj[x] = 'X';
obj[y] = 'Y';
console.log(obj);
// { foo: 'X', bar: 'Y' }
If you want to make this easier, make it a class:
function myObj(name){
this.name = name;
}
myObj.prototype.toString = function(){ return this.name; }
var obj = {};
obj[new myObj('foo')] = 'X';
obj[new myObj('bar')] = 'Y';
I'm answering my own question, but I came up with an alternative solution I thought was interesting and thought it would be useful to share it.
cwolves' answer gave me an idea. Providing an object's toString() method uniquely identifies the instance, properties of an object can be used to store a set of objects. Essentially, to store object x, you can use items[x.toString()] = x;. Note that the value is the object itself, so then the set of objects can be extracted by looking at all item's properties and dumping all the values in to an array.
Here's the class, which I call ObjectSet, in full. It requires objects are uniquely identified by their toString() method, which is OK for my purposes. add, remove and contains should all run in better than O(n) time - whatever javascript's property access efficiency is, which hopefully is either O(1) or O(n log n).
// Set of objects. Requires a .toString() overload to distinguish objects.
var ObjectSet = function ()
{
this.items = {};
this.item_count = 0;
};
ObjectSet.prototype.contains = function (x)
{
return this.items.hasOwnProperty(x.toString());
};
ObjectSet.prototype.add = function (x)
{
if (!this.contains(x))
{
this.items[x.toString()] = x;
this.item_count++;
}
return this;
};
ObjectSet.prototype.remove = function (x)
{
if (this.contains(x))
{
delete this.items[x.toString()];
this.item_count--;
}
return this;
};
ObjectSet.prototype.clear = function ()
{
this.items = {};
this.item_count = 0;
return this;
};
ObjectSet.prototype.isEmpty = function ()
{
return this.item_count === 0;
};
ObjectSet.prototype.count = function ()
{
return this.item_count;
};
ObjectSet.prototype.values = function ()
{
var i, ret = [];
for (i in this.items)
{
if (this.items.hasOwnProperty(i))
ret.push(this.items[i]);
}
return ret;
};
I used Map, solved my case
const objectsMap = new Map();
const placesName = [
{ place: "here", name: "stuff" },
{ place: "there", name: "morestuff" },
{ place: "there", name: "morestuff" },
];
placesName.forEach((object) => {
objectsMap.set(object.place, object);
});
console.log(objectsMap);
For what you're trying to do (sets of objects), there is no native Javascript implementation. You would have to implement this on your own. One way to do this would be to implement a hashing function for your objects. The backing data-type of the set would be an associative array, where the key of the array is the value you get from calling the object's hash function, and the value of the array is the object itself.
Of course, this doesn't address the issue that you highlighted, so you will need to take equality into account as well (implement an equals function perhaps)?
Instead of making the hash function a property of the object itself, you can have a standalone hash function that takes in an object as input and generates a hash value (presumably by iterating over its properties).
Using this method you should be able to get O(1) for insertion, searching, and removing (not counting the order of the hash function, which shouldn't be any worse than O(n), especially if you are iterating over its properties to create your hashed value).
ECMAScript6 Set should behave like that:
Standard: http://www.ecma-international.org/ecma-262/6.0/#sec-set-o-p-v-throw
Unofficial ES6 cheat sheet: https://github.com/lukehoban/es6features#map--set--weakmap--weakset
Working example on Firefox 32 (but not implemented in Chromium 37):
if (Set) {
var s = new Set()
var a = {}
var b = {}
var c = {}
s.add(a)
s.add(b)
s.add(b)
assert(s.size === 2)
assert(s.has(a))
assert(s.has(b))
assert(!s.has(c))
}
This is not surprising since {} != {}: equality compares object addresses by default.
A module that implements it for browsers without support: https://github.com/medikoo/es6-set
Javascript Set's don't do deep object comparison.
Using lodash, this is a unique array with deep object comparison:
const objects = [{ 'x': 1, 'y': 2 }, { 'x': 2, 'y': 1 }, { 'x': 1, 'y': 2 }];
_.uniqWith(objects, _.isEqual);
Just typed this up, it's only briefly tested:
var Set = function Set()
{
var list = [];
var contains;
this.contains = contains = function(x) {
return list.indexOf(x) >= 0;
}
var put;
this.put = put = function(x) {
if (!contains(x))
list.push(x);
return this;
}
var remove;
this.remove = remove = function(x)
{
var idx = list.indexOf(x);
if (idx >= 0)
list.splice(idx,1);
return this;
}
var all;
this.all = all = function()
{
return list.concat();
}
return this;
}
It seems that the inner call of function works when prefixed with this.
Exemple:
var put;
this.put = put = function(x) {
if (!this.contains(x))
list.push(x);
return this;
}
Please use this code as a reference.
const fruits = [
{name: 'apple', price: 100},
{name: 'apple', price: 100},
{name: 'orange', price: 200},
{name: 'grapes', price: 300}
];
const hasFruitDuplicated = () => {
const duplicatedDeleteFruits = fruits.filter((fruit, index) =>
fruits.findIndex(item => item.name === fruit.name && item.price === fruit.price) === index
);
return duplicatedDeleteFruits;
};
Given an array of the following type:
Array<{ foo: T1, bar: T2 }>
You can build a corresponding dictionary of type:
{ [foo: T1]: Set<T2> }
The look-up for { foo: fooValue, bar: barValue } can be performed as follows:
if (fooValue in dictionary && dictionary[fooValue].has(barValue))
This way we can build what would be an ObjectSet<T1, T2>
.
If you now have three elements, you can build the following dictionary:
{ [foo: T1]: ObjectSet<T2, T3> }
and extend your ObjectSet to any number of properties by induction.
That is assuming your types can be used as index signatures.
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to clone js object?
This is another way to create a javascript object (using object literal notation instead of function):
user = {
name: "Foo",
email: "bar#baz.com"
}
Is there a way to clone this object or is it a singleton?
Try this:
var clone = (function(){
return function (obj) { Clone.prototype=obj; return new Clone() };
function Clone(){}
}());
Here's what's going on.
Clone is a dummy constructor.
We assign the object we want to clone to the Clone constructor's prototype.
We call Clone using 'new', so the constructed object has the original object as its constructor's prototype aka (non-standard) __proto__.
The cloned object will share all the properties of the original object without any copies of anything being made. If properties of the cloned object are assigned new values, they won't interfere with the original object. And no tampering of built-ins is required.
Keep in mind that an object property of the newly-created object will refer to the same object as the eponymous property of the cloned object. Assigning a new value to a property of the clone won't interfere with the original, but assigning values to the clone's object properties will.
Try this in chrome or firebug console:
var user = {
name: "Foo",
email: "bar#baz.com"
}
var clonedUser = clone(user);
console.dir(clonedUser);
A detailed explanation of this cloning technique can be found here.
You can use JSON object (present in modern browsers):
var user = {name: "Foo", email: "bar#baz.com" }
var user2 = JSON.parse(JSON.stringify(user))
user2.name = "Bar";
alert(user.name + " " + user2.name); // Foo Bar
See in jsfiddle.
EDIT
If you need this in older browsers, see http://www.json.org/js.html.
I like to use this:
if (typeof Object.create !== 'function') {
Object.create = function (o) {
var F = function () {};
F.prototype = o;
return new F();
};
}
then any object I want to clone can be done as:
user = {
name: "Foo",
email: "bar#baz.com"
};
var user2 = Object.create(user);
As shown in (or similar to) JavaScript The Good Parts
Most of the javascript frameworks have good support for object cloning.
var a= {'key':'value'};
var b= jQuery.extend( true, {}, a );
Object.prototype.clone = function clone(obj) {
obj = obj || this;
var new_obj = {};
for( var p in obj ) {
if ( obj.hasOwnProperty(p) ) {
if( obj[p] !== null && typeof(obj[p]) === "object" ) {
new_obj[p] = clone( obj[p] );
}
else {
new_obj[p] = obj[p];
}
}
}
return new_obj;
};
/* Example */
var foo = {
name: "Foo"
, email: "bar#baz.com"
, obj: {a:"A",b:"B"}
};
var bar = foo.clone();
bar.name = "Bar";
bar.obj.b = "C";
// foo and bar should have a different 'name'
// foo and bar should retain the same email
// foo and bar should have different values for <foo/bar>['obj']['b']
// foo and bar should have the same values for <foo/bar>['obj']['a']
console.dir(foo);
console.dir(bar);