Store an object with an array inside? - javascript

Is there a way to store an object with an array[id] = "certain value", so that every single user has a list of favorite things ?
What I'm trying to achieve is having a data object with undefined values at first, and filling them in, so for example Jack and Sam could have an assigned favorite movie saved.
I tried something like this with no success:
Data.js:
module.exports = function() {
return {
favMovie: ""
}
};
App.js:
var person [] = data();
//1st person
person[811767132257839].favMovie = "Matrix";
//2nd person
person[107230716367889].favMovie = "Kill Bill";
//3rd person
person[973676332752239].favMovie = "Avatar";
...
console.log( "Favorite movie: " + person[id].favMovie );

It doesn't sound like you want any arrays at all, just objects.
// Create an object that we'll keep person objects in
var personData = {};
// Add a person object to it for person ID #123
personData[123] = {};
// Set person #123's favorite movie:
personData[123].favMovie = "Avatar";
// Add a different person; this time, we'll add the movie at
// the same time
personData[234] = {
favMovie: "Matrix"
};
When using objects as maps like that, sometimes people create the objects using Object.create(null) to avoid them having any inherited properties (like toString and valueOf and constructor):
person[123] = Object.create(null);
person[123].favMovie = "Avatar";
In ES2015 (aka "ES6"), you might want to use a Map rather than an object for the map of people:
var personData = new Map();
...and then use set and get for the individual person objects.
If the individual person objects get complicated, you might use a constructor function and associated prototype for them, using either ES5 syntax:
function Person() {
// ...
}
Person.prototype.doSomething = function() {
// ...
};
...or ES2015 syntax:
class Person {
constructor() {
// ...
}
doSomething() {
// ...
}
}
Then creating them:
personData[123] = new Person();
// or if using Map
personData.set(123, new Person());
Side note: Even when we write them as numbers, the keys (property names) in objects are always strings (unless you use ES2015 Symbols, which you probably wouldn't here). In contrast, keys in an ES2015 Map can be anything. Key equality in Map instances is determined using the special "same value zero" algorithm (which is basically === except that NaN is equal to itself [whereas it isn't in ===]).

Related

Clone and update in groovy

In javascript there is an easy way to generate cloned object with some of the fields updated:
const person = {
isHuman: false,
name: "gabe"
};
const person2 = {
...person1,
name: 'alice'
}
Is there a way to do something like in groovy without copying all the fields manually? I am writing testcases where I wanna generate data with one attribute changed at a time.
Can you use #Immutable(copyWith = true)
#Immutable(copyWith = true)
class Person {
String first, last
}
def tim = new Person('tim', 'yates')
def alice = tim.copyWith(first:'alice')
assert tim.first == 'tim'
assert alice.first == 'alice'
https://docs.groovy-lang.org/latest/html/gapi/groovy/transform/ImmutableBase.html#copyWith
There are many ways this can be done.
One is to construct instances by spreading in a map, e.g., given:
class Person { String name; Boolean isHuman; }
An instance can be constructed using the same spread-map operator I linked to:
m1 = [ name: "Gabe", isHuman: true ]
p1 = new Person(*:m1)
println p1
// Person: Gabe, isHuman=true
This avoids actual work. An exception will be thrown if a map key isn't an instance property.
A utility method grabbing (non-synthetic) prop names from a class, and iterates while putting the name/value pairs into a map is also an option (and affords a bit more safety):
def toMap(obj) {
obj.class.declaredFields
.findAll { !it.synthetic }
.collectEntries { [(it.name): obj."$it.name" ] }
}
Now we can construct a "prototype" object, but override properties:
p2 = new Person(*:toMap(p1), name: "Alice")
println p2
// Person: Alice, isHuman=true
There are also libraries that do this type of work.
Depending on your actual usecase it may not be necessary to do anything other than passing a map, however (duck typing).

How can I have two objects access the same array [duplicate]

This question already has answers here:
Copy array by value
(39 answers)
Closed 3 years ago.
Class A is instantiated to an object that has an array named this.people that is filled with a bunch of data. Class A instantiates an object of class B and this.people is passed to it's constructor. If object B updates the array, when object A updates it, it overwrites the changes from object B. How can I fix this?
That happens because you're passing a reference of A's people array to B's constructor. You want to make either a "shallow copy" or a "deep copy" of A's people array, since you want B's people array contents to be different.
With a "shallow copy" you copy all of the primitive values in the array to the new one, but if you have compound values (arrays or objects) inside the array, then only the reference to them will be copied, so any changes that you do to the compound values will be reflected in both A and B. With a "deep copy", both primitive and compound values (and not just their references) will be copied to a new place in memory.
If you don't have objects and arrays inside the people array, you can do a shallow copy using Array.from(a.people). Otherwise, you can do a deep copy with JSON.parse(JSON.stringify(a.people))
Snippet:
class B {
constructor(_people) {
// shallow copy:
this.people = Array.from(_people);
// deep copy:
//this.people = JSON.parse(JSON.stringify(_people));
}
}
class A {
constructor() {
this.people = [];
}
func() {
this.objB = new B(this.people);
//do something
}
}
// Usage Example
let objA = new A();
objA.people.push("A");
objA.func();
objA.objB.people.push("B");
console.log(objA.people.toString());
console.log(objA.objB.people.toString());
Some helpful links:
https://medium.com/#gamshan001/javascript-deep-copy-for-array-and-object-97e3d4bc401a
https://dev.to/samanthaming/how-to-deep-clone-an-array-in-javascript-3cig
Give each class its own version of people
class A{
constructor(){
this.people = ["bob","jane","john"]
this.objB = new B(this.people)
}
}
class B{
constructor(people){
this.people = people
}
}
let objA = new A()
objA.objB.people.push("a")
objA.people.push("b")
console.log(objA.people, objA.objB.people)
Pass the array by value with destructuring.
class Family {
constructor(people) {
this.people = people;
}
}
let members = ["mom", "dad"];
let smiths = new Family(members);
let joneses = new Family(smiths.people); // pass by reference
joneses.people.push("Billy");
console.log(smiths.people); // changes to ["mom","dad","Billy"]
let wilsons = new Family([...smiths.people]); // pass by value
wilsons.people.push("Suzy");
console.log(smiths.people); // remains ["mom","dad","Billy"]

Objects types in Javascript

This is a fairly general question coming from a newbie in the learning phase and is on something I need clarifying.
I'm currently learning about objects and at this point I'm learning about inheritance. At this point in the lesson I've learned a few different ways to create objects but objects using the this keyword seems to have the most function:
function Person(){
this.eyes = 2;
this.ears = 2;
this.arms = 2;
this.hands = 2;
this.feet = 2;
this.legs = 2;
this.species = "Homo sapien";
}
I understand what I might use this for but then there's an object created this way:
var person = new Object();
person.eyes = 2;
person.ears = 2;
person.arms = 2;
person.hands = 2;
person.feet = 2;
person.legs = 2;
person.species = "Homo sapien";
Because I seem to be able to do things with the former that I can't do with the latter, I'm wondering if there's any reason why I wouldn't just use the former method all the time. Can anyone help me out with this? I don't need a long detailed answer (although one would be appreciated). It's just a question I want to get out of my head so that I don't dwell on it.
Preface: If you're not sure what I mean by the word "prototype" below, skip down to below the divider for an explanation, then come back up here to the top of the answer. :-)
Assuming in your first example that you then call Person via new:
var person = new Person();
...then the only difference between that person and the one you'd get using your second example is related to inheritance: The one created via new Person gets assigned the object on Person.prototype as its underlying prototype.
I'm wondering if there's any reason why I wouldn't just use the former method all the time
If you don't need to use the prototype, then using a constructor function could be unnecessarily complicated. Note that your second form could more concisely be written:
var person = {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
That's called an object initializer: It creates a new object with the properties you see listed. There's never any need to use x = new Object(); if you want a new, blank object, just use x = {};.
When an object is a one-off, creating it directly is often the simplest way to create it.
The key advantage constructor functions have is that they're factories for objects that are fundamentally similar: Have the same set of initial properties, have the same underlying prototype, etc. And the function can accept arguments and use them to outfit the object it's creating in an appropriate way, perhaps do some validation on the construction arguments, etc. That is: They centralize initialization logic.
Constructor functions are not the only way to have function factories. You can also do:
function buildPerson() {
return {
eyes: 2,
ears: 2,
arms: 2,
hands: 2,
feet: 2,
legs: 2,
species: "Homo sapien"
};
}
var person = buildPerson();
And if you want that person to have a prototype (ES5 browsers and higher):
var personPrototype = {
// ...properties for the person prototype...
};
function buildPerson() {
var obj = Object.create(personPrototype);
obj.eyes = 2;
obj.ears = 2;
obj.arms = 2;
obj.hands = 2;
obj.feet = 2;
obj.legs = 2;
obj.species = "Homo sapien";
return obj;
}
var person = buildPerson();
(There's another, more verbose way to define those properties as well.)
JavaScript is amazingly flexible. :-)
"Prototype"
JavaScript uses prototypical inheritance, which is a fancy way of saying that a object A can be "backed" by object B so that if you ask A for a property it doesn't have, the JavaScript engine will look to see if that property exists on B. A quick practical example:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // Creates an object backed by the given prototype
Don't worry about Object.create, for now all you need to know is that it creates a new object and assigns its underlying prototype based on the object you pass into it. So obj is backed by proto.
obj doesn't have a name property, but if we do:
console.log(obj.name);
...we see "proto's name". That's because when the JavaScript engine tried to get name's value from obj, it found that obj didn't have a name property, so it looked to obj's prototype, proto. Having found it there, it used the value from proto.
That only happens when getting the value (except in some advanced cases we can ignore for now). When setting a property's value, it gets set on the object you set it on. So:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto); // `obj` is backed by `proto`
console.log(obj.name); // "proto's name"
obj.name = "obj's name";
console.log(obj.name); // "obj's name"
The purpose of prototypes is reuse, and so it's no surprise that an object can be the prototype of several other objects:
var proto = {
name: "proto's name"
};
var a = Object.create(proto); // `a` is backed by `proto`
var b = Object.create(proto); // `b` is also backed by `proto`
console.log(a.name); // "proto's name"
console.log(b.name); // "proto's name"
a.name = "a's name";
console.log(a.name); // "a's name"
console.log(b.name); // "proto's name"
Prototype objects are normal objects; we can change them:
var proto = {
name: "proto's name"
};
var obj = Object.create(proto);
console.log(obj.name); // "proto's name"
proto.name = "updated";
console.log(obj.name); // "updated"
Since obj doesn't have its own name property, each time we access it, the JavaScript engine goes and looks at its prototype.
The new operator automatically assign a prototype to the objects it creates: It uses the object that the function's prototype property has on it. So:
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function() {
console.log("My name is " + this.name);
};
var p = new Person("Fred"); // Creates an object backed by Person.prototype,
// then calls Person with this referring to the
// object
p.sayName(); // "My name is Fred";
Finally: Since prototype objects are normal objects, they also can have prototypes:
var rootProto = {
name: "root proto's name"
};
var middleProto = Object.create(rootProto);
middleProto.middleProp = "middle property";
var obj = Object.create(middleProto);
console.log(obj.name); // "root proto's name"
console.log(obj.middleProp); // "middle property"
For name, the JavaScript engine looks at obj, doesn't see a name property, and so looks at middleProto. It doesn't see a name property there, either, so it looks at rootProto. It finds it there, so it uses it.
Point of confusion: A lot of people are confused by the fact that the property on constructor functions is called prototype and think that somehow it's the prototype of the function. It isn't. It's just a normal property on function objects (functions are objects and can have properties). The only way it's special is that new uses it when you call the function via new. Non-function objects don't have a prototype property, they're prototype isn't a normal property, it's an internal thing. You can get an object's prototype by passing it into Object.getPrototypeOf:
var proto = {/*...*/};
var obj = Object.create(proto);
Object.getPrototypeOf(obj) === proto; // true

Create a "Dictionary" in javascript

In C# I have a Model with 2 properties and a Dictionary with a String key:
public class Model
{
public string Route { get; set; }
public string Template { get; set; }
}
Dictionary<String, Model> models;
The key is the model name and model is an instance of class model.
I need to create a similar structure in Javascript where I could Get an item from the "Dictionary" given a key or find if there is an item with a specific key in the "Dictionary".
Is something in Javascript that could replicate this?
You could create a function that would represent the random item in your dictionary:
function Model(route, template)
{
this.route = route;
this.template = template;
}
Then you could create an object like below:
var dictionary = {
"key1": new Model("route1", "template1"),
"key2": new Model("route2", "template2")
};
In JavaScript objects are containers for key/value pairs.
How we get the value for a specific key?
var model = dictionary["key1"];
or
var model = dictionary.key1;
If key1 isn't a key of dictionary, then you will get as model the undefined.
How we set the value for a specific key?
dictionary.key5 = new Model("route5", "template5");
What happens if there is already the key5 ?
You just assign a new value for this key. As it would happen, if we were in c#.
Above we used the constructor pattern, in order we create the values of our dictionary. This is a commonly used pattern for the creation of objects with the same properties.
In Javascript, a dictionary with string keys is just a plain object:
var models = {};
Add an element:
model.myKey = 'my value';
Get an element:
var value = model.myKey;
Check that an element exists:
if (model.myKey) { ...
(note that this will yield false for any Javascript falsey value, so if you store things like 0 or '' you should use the more pedantically correct method model.hasOwnProperty('myKey'))
Remove an element:
delete model.myKey;
You can also add elements when creating the object:
var obj = {
'an item': 1,
anotherItem: 'another value'
};
Note that keys can be accessed with a dot notation if they're valid Javascript identifiers:
var value = obj.key;
Or as values in brackets (useful if they're not valid identifiers or if you want to use a variable):
var value = obj['A key'];
var fromVar = obj[someVariableHoldingAKeyName];
(JSHint even has a rule that checks for that)
As for your model class, it could similarly be modeled as an object with keys 'route' and 'template', e.g:
var myModel = { route: 'my route', template: 'my template' };
The next version of ECMAScript introduces Map, which allows to use a value of any data type as key. Map is already supported in a variety of browsers.
Example:
var map = new Map();
map.set('foo', data);
map.get('foo);
As already mentioned, objects are also often used as dictionaries, and sufficient in most cases. However, some care has to be taken:
The default prototype of objects is Object.prototype, so they already contain some "default" entries (like toString or hasOwnProperty). This can be avoided by explicitly creating an object with no prototype: var dict = Object.create(null);
Similar to above, because Object.prototype can be extended, your "dictionary" could be changed as well without you knowing it. Object.create(null) solves that problem as well.
Similar to the other answers. You're probably well off to put your model into an Array (however you're getting them), and then looping through that array to create your dictionary object.
var models = {};
var m1 = {name:'Joe',age:25};
var m2 = {name:'Bill',age:30};
var m3 = {name:'Andy',age:50};
var arr = [m1,m2,m3];
for(var m in arr){
models[arr[m].name] = arr[m];
}
//console.log(models);
var joe = models.Joe;
var joe = models['Joe'];

Javascript change variable based on variable reference

In a program i am writing i need an object variable that looks like this:
var map {
cube: {__pt3arraylocation__:[0,0,0], poly: new Object()},
other: {__pt3arraylocation__:[1,0,0], poly: new Object()}
};
However, i want to be able to type map.cube and have it return the pt3arraylocation as a default unless i specify what i want by typing map.cube.poly
for example: map.cube would return [0,0,0] and map.cube.poly would return the object poly in the object cube
thanks in advance
i want to be able to type map.cube and have it return the pt3arraylocation as a default unless i specify what i want by typing map.cube.poly
for example: map.cube would return [0,0,0] and map.cube.poly would return the object poly in the object cube
You can't do that in JavaScript.
However, as an alternative, it's worth noting that you can add arbitrary properties to arrays if you want to. So for instance:
var map {
cube: [0,0,0],
other: [1,0,0]
};
map.cube.poly = {}; // {} is the same as `new Object()` but not subject to people...
map.other.poly = {}; // ...overriding the `Object` symbol
Then map.cube gives you the array, and map.cube.poly gives you the object you've stored on that array.
How is this possible? Because in JavaScript, arrays aren't really arrays. They're just objects that have an automatic length property, treat a class of property names (all numeric ones) in a special way, and have Array.prototype backing them up. And of course, you can add properties to any object.
There's no literal syntax for doing this, which is why I had to do it with assignments after the object initializer above. But it's perfectly valid. I use it for cross-indexing arrays all the time.
Do be sure, if you do this, that you're not using for..in incorrectly; more.
The best way to do this I would say is like this:
var map {
cube: [0,0,0],
other: [1,0,0]
};
map.cube.poly = new Object();
map.other.poly = new Object();
That is not possible to achive. Maybe you can play around with toString()
var map = {
cube: {
__pt3arraylocation__:[0,0,0],
poly: new Object(),
toString : function() {
return this.__pt3arraylocation__.toString()
}
},
other: {__pt3arraylocation__:[1,0,0], poly: new Object()}
};
map.cube == '0,0,0'
map.cube.split(',') == map.cube.__pt3arraylocation__
There is no way to do that exactly as you want - if you request an object (which map.cube is), you get an object. However, there are a few ways to do something similar.
when used as a parameter to functions or operations that require string, like alert(map.cube) or "sometext" + map.cube, the object is converted to string by calling the toString function. You can therefore define, for example:
map.cube.toString = function() { return this.__pt3arraylocation__.toString(); };
a similar thing happens when there if the object is used in context when a number is needed. In this case, it is converted with valueOf(). So you can use, for example
map.cube.valueOf = function() { return this.__pt3arraylocation__.length; };
or you can obtain the default value via a function call, if you define your object as a function instead
var map = {
cube: function() {
return map.cube.__pt3arraylocation__;
}
}
map.cube.__pt3arraylocation__ = [0,0,0];
map.cube.poly = new Object();
alert(map.cube.__pt3arraylocation__); // 0,0,0
alert(map.cube.poly); // [object Object]
alert(map.cube()); // same as map.cube.__pt3arraylocation__
As you can see, in JavaScript, functions are objects like any other, so you can not only call them, but also set fields and methods to them.
T.J. Crowder is right. Based on his answer I'd like to remark that you can also assign map.cube like this
var map = {
cube: function(){
var val = [0,0,0];
val.poly = {};
return val; }()
};
Or for more values:
function polyval(val){
val.poly = {};
return val;
}
var map = {
cube: polyval([0,0,0]),
other: polyval([1,0,0]),
more: polyval([1,1,0])
/* ... etc */
};

Categories

Resources