I have a class (LiveScript) that is instantiated once, but its render method is called many times. Each object created in the render method must have a unique key that stays the same across all invocations of render:
class Test
->
console.log 'constructor, called only once'
render: ->
test = {key: 4124312}
test1 = {key: 234897}
test2 = {key: 87234}
This works, but instead of hardcoding the key I'd rather generate it. Using a random number will not work since that will generate a new key on each invocation of render. Having some list of keys outside this class and popping items of them won't work either because the order of the created objects in render could change. Any idea if and how I could generate the keys?
Generating them is one thing - it sounds like you need a way to persist the unique objects with a key that doesn't change during your execution context. This is called persistence.
In JS, you can use an object literal to store your objects, where the key of each entry in your storage object is the unique key of your stored objects:
{
1234: { name: "test", key: 1234 },
2345: { name: "test1", key: 2345 },
3456: { name: "test2", key: 3456 }
}
Related
JS noob here. I want to store a list of option for a dropdown in an array. I want a key to be associated with every value something like this
var newArray = [
{
key: "key",
val:({value:"val", label:"label"}, {value:"val",label:"label"})
}
]
The code above returns undefined when I try to read val. What is the solution? Thanks
var newArray = [
{
key: "key",
val:[{value:"val", label:"label"}, {value:"val",label:"label"}]
}]
The only thing i changed were parentheses () into [], because it's the thing that declares an array. Now, if you want to read the val key, you need to do this stuff.
You have an array named "newArray". It only has 1 element (which is also the first).
Now lets get the first element of the array by newArray[0]. Now you have accessed the object inside the array. Now you can read the the value by newArray[0].val. And now you have entered a new array, which elements you can read with newArray[0].val[0] and newArray[0].val[1]
I have an array of objects with meta information.
Here is the schema for a object.
this.state.slotData [{
availability: boolean,
id: number,
car: {
RegistrationNumber : string,
Color: string
}, {...}, {...}, ...]
Now, for any incoming car, I record car details
I am further checking if any slots are available, and if so, updating the slotData state.
I filter() the slotData to find all available slots then refer availableSlots[0] to access the id of the nearest empty slot.
Now, I just have to update this.state.slotData without mutating it.
If you want to apply immutable update and add car as a single object in slotData array you should first spread whole slotData array and than add car object like this:
const updatedSlotData = [...slotData, carObj];
this.setState({ slotData: updatedSlotData });
As long as you make a copy first, you can safely mutate the copy.
i'm struggling with declaring and accessing data in nested arrays in Javascript
i can easily do it in C using nested structures, declaring first the lowest-level structure and including an array of it when declaring the upper-level structure and so on. I end up with a structure containing an array of structures, each containing an array of structures, etc...
but i have only 3 days of Javascript experience so far...
Just to help you understand how i need the data to be organized, here's an example:
Let's imagine a library, this library has several floors, each floor has the same type of properties (name, number of books...), each floor has several departments and each has the same type of properties, each department has several shelves and so on...
let's say the 1st floor get's its name from some famous mathematician, and is split into two departments: 1/ arithmetics and 2/ geometry
the ideal for me would be to work with the data this way:
library.floor[0].name = 'Fermat'
library.floor[0].department[0].name = 'arithmetics'
library.floor[0].department[1].name = 'geometry'
library.floor[0].department[1].shelve[4].authors = // authors list
so far i've tried this:
var library =
{
floors: [
{floor_name:'Fermat'},
{has_a_printing_machine:true},
{departments:[
{department_name:'group_theory'},
{shelves:[
{shelf_name:'letters_f_z},
{authors: ["Frobenius","Lagrange"]}]}]}]
};
i can get data from:
log(library.floors[0].floor_name); // ouputs 'fermat'
log(library.floors[2].departments[0].department_name); // outputs 'group_theory'
log(library.floors[2].departments[1].shelves[1].authors[1]); // outputs 'Lagrange'
but it isn't what i need, i can't access a 'departments' property for each floor for instance... and i'd like to add data dynamically in these arrays.
i'm doing it wrong and i can't figure out how to do it right...
thanks for your help!
You're misunderstanding JavaScript object literals. They are completely different that structs in C. Structs are type declarations, JavaScript object literals are actual objects.
You should stop putting one key/value pair per object, and start making uniform objects that contain the same attributes.
When you write [ { department_name: ... }, { shelves: ... } ] you are defining an array that contains two unrelated objects, one containing a department_name property, and the other containing a shelves property. These objects know nothing about each other, or that they are contained in the same array.
Instead of this...
[
{
department_name: 'group_theory'
},
{
shelves: [
{
shelf_name: 'letters_f_z'
},
{
authors: ["Frobenius","Lagrange"]
}
]
}
You should be writing:
{
departments: [
{ # This entire object is a department. It has a name and shelves
name: 'group_theory',
shelves: [
{ # This entire object is a shelf. It has a name and authors.
name: 'letters_f_z',
authors: ["Frobenius","Lagrange"],
}
]
}
]
}
To put it a different way, when you write this...
floors: [
{floor_name:'Fermat'},
{has_a_printing_machine:true},
{departments:[...]}
]
You are not making an array of floors, you're making an array of three totally unrelated objects, one that contains a floor_name property, one that contains a has_a_printing_machine property, and one that contains a departments property. If you want all three objects to have all three properties, you need to declare them that way:
floors: [
{ name: 'floor_one', has_a_printing_machine: true, departments: [] },
{ name: 'floor_two', has_a_printing_machine: false, departments: [ ... ] },
{ name: 'floor_three', has_a_printing_machine: true, departments: [] },
]
You almost had it. Each floor is an entity on its own, with its properties. One of its properties is the list of departments, and each department is an entity itself too (again, with its own properties). And same with the shelves.
Each instance of an entity/struct/register is a dictionary, with its properties mapped as key:value pairs. So, for instance, a shelf could be:
var my_shelf = {
shelf_name:'letters_f_z',
authors: ["Frobenius","Lagrange"]
};
A department (with its shelves) may be:
{
department_name:'group_theory',
shelves:[
{
shelf_name:'letters_f_z',
authors: ["Frobenius","Lagrange"]
},
{...}
]
}
I think at this point you can extrapolate this construction to the floors level, having an array of department registries as the value of the departments property.
Unfortunately, unlike TypeScript, which is a statically-typed superset of JavaScript, you can't enforce each register to actually have a certain set of properties. So you'll have to be extra-cautious when creating the instances so every property is initialized since its very beginning.
Let's say for example, I have the following Javascript object:
var Object = {
Person_A: { name: 'James', age: 40, country: 'Spain' },
Person_B : { name: 'Smith', age: 50, country: 'France' }
}
I want to know how many properties there are in the object Object, and access these properties numerically e.g. through Object[n].
Until now (I don't use Javascript objects much, but I do use JSON as a return format when working with AJAX) I didn't know that Javascript objects don't have a length method and can't be accessed numerically.
I've tried to convert the Javascript object into the same type of JSON that is returned when I make AJAX calls (the JSON is returned as an object with a length method, and is numerically accessible - just read another thread, and maybe I'm wrong about this - double checking now) using JSON.parse(JSON.stringify(Object)) but that simply returns the same exact Object.
So, my question is, what's the most efficient way to take an object like the example, and make it accessible numerically and have a length method.
Any help would be greatly appreciated (and please ask if you need any clarification of my question).
Thanks.
This cannot be done with meaning. The properties of JavaScript objects have no inherent order1.
The length property is a special member of Arrays. (Arrays are just objects that have a specific [[prototype]] and understand how to magically update length -- and have a few other internal rules defined -- that's it!)
Update for comment:
If the index is required, use an Array:
var people = [
{ id: "Person_A", data: { name: 'James', age: 40, country: 'Spain' } },
{ id: "Person_B", data: { name: 'Smith', age: 50, country: 'France' } }
]
people[0].id // "Person_A"
1 JSON "has order" only when serialized as text but implementations, including those that turn it into JavaScript objects, work without access [or assumption] about order; there is no order guarantee for properties per the JSON standard. Just because properties in an object "look" ordered in JSON (or a JS Object Literal), does not imply an order.
If you want to completely replace that object with an array accessible numerically, you could first loop through it to build that new array:
var newArray=new array();
for(i in object){
array.push(i);
}
You can now access that array numerically
function numericIndices(obj) {
var i=0, x;
for( x in obj) {
obj[i] = obj[x];
i++;
}
// next line is OPTIONAL:
obj.length = i;
}
Given an object, this will add the numeric indices to that object. So after running it through that function, the object will have both string keys and numeric keys. If you have the optional line too, you automatically get a length property as well.
How to get reference count for an object
Is it possible to determine if a javascript object has multiple references to it?
Or if it has references besides the one I'm accessing it with?
Or even just to get the reference count itself?
Can I find this information from javascript itself, or will I need to keep track of my own reference counters.
Obviously, there must be at least one reference to it for my code access the object. But what I want to know is if there are any other references to it, or if my code is the only place it is accessed. I'd like to be able to delete the object if nothing else is referencing it.
If you know the answer, there is no need to read the rest of this question. Below is just an example to make things more clear.
Use Case
In my application, I have a Repository object instance called contacts that contains an array of ALL my contacts. There are also multiple Collection object instances, such as friends collection and a coworkers collection. Each collection contains an array with a different set of items from the contacts Repository.
Sample Code
To make this concept more concrete, consider the code below. Each instance of the Repository object contains a list of all items of a particular type. You might have a repository of Contacts and a separate repository of Events. To keep it simple, you can just get, add, and remove items, and add many via the constructor.
var Repository = function(items) {
this.items = items || [];
}
Repository.prototype.get = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
return this.items[i];
}
}
}
Repository.prototype.add = function(item) {
if (toString.call(item) === "[object Array]") {
this.items.concat(item);
}
else {
this.items.push(item);
}
}
Repository.prototype.remove = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
this.removeIndex(i);
}
}
}
Repository.prototype.removeIndex = function(index) {
if (items[index]) {
if (/* items[i] has more than 1 reference to it */) {
// Only remove item from repository if nothing else references it
this.items.splice(index,1);
return;
}
}
}
Note the line in remove with the comment. I only want to remove the item from my master repository of objects if no other objects have a reference to the item. Here's Collection:
var Collection = function(repo,items) {
this.repo = repo;
this.items = items || [];
}
Collection.prototype.remove = function(id) {
for (var i=0,len=this.items.length; i<len; i++) {
if (items[i].id === id) {
// Remove object from this collection
this.items.splice(i,1);
// Tell repo to remove it (only if no other references to it)
repo.removeIndxe(i);
return;
}
}
}
And then this code uses Repository and Collection:
var contactRepo = new Repository([
{id: 1, name: "Joe"},
{id: 2, name: "Jane"},
{id: 3, name: "Tom"},
{id: 4, name: "Jack"},
{id: 5, name: "Sue"}
]);
var friends = new Collection(
contactRepo,
[
contactRepo.get(2),
contactRepo.get(4)
]
);
var coworkers = new Collection(
contactRepo,
[
contactRepo.get(1),
contactRepo.get(2),
contactRepo.get(5)
]
);
contactRepo.items; // contains item ids 1, 2, 3, 4, 5
friends.items; // contains item ids 2, 4
coworkers.items; // contains item ids 1, 2, 5
coworkers.remove(2);
contactRepo.items; // contains item ids 1, 2, 3, 4, 5
friends.items; // contains item ids 2, 4
coworkers.items; // contains item ids 1, 5
friends.remove(4);
contactRepo.items; // contains item ids 1, 2, 3, 5
friends.items; // contains item ids 2
coworkers.items; // contains item ids 1, 5
Notice how coworkers.remove(2) didn't remove id 2 from contactRepo? This is because it was still referenced from friends.items. However, friends.remove(4) causes id 4 to be removed from contactRepo, because no other collection is referring to it.
Summary
The above is what I want to do. I'm sure there are ways I can do this by keeping track of my own reference counters and such. But if there is a way to do it using javascript's built-in reference management, I'd like to hear about how to use it.
No, no, no, no; and yes, if you really need to count references you will have to do it manually. JS has no interface to this, GC, or weak references.
Whilst you could implement a manual reference-counted object list, it's questionable whether all the extra overhead (in performance terms but more importantly code complexity) is worth it.
In your example code it would seem simpler to forget the Repository, use a plain Array for your lists, and let standard garbage collection take care of dropping unused people. If you needed to get a list of all people in use, you'd just concat the friends and coworkers lists (and sort/uniquify them if you needed to).
You may interest to look into reduce functions, and array.map functions. map could be used to help identify where your collections intersect, or if there is an intersection at all. A user defined reduce function could be used like a merge (kinda like overriding the addition operator so that you can apply operation to objects, or merge all collections on "id" if that is how you define your reduce function - then assign the result to your master reference array, I recommend keeping a shadow array that holds all of the root object/values in case you would like to REWIND or something). Note: one must be careful of prototype chains when reducing an object or array. The map function will be very helpful in this case.
I would suggest not to remove the object or record that is in your Repository as you may want to reference it again later. My approach would be to create a ShadowRepository that would reflect all records/objects that have at least one "Reference". From your description and code presented here it appears you are initializing all of the data and storing reference to 1,2,4,5 as appears in your code.
var contactRepo = new Repository([
{id: 1, name: "Joe"},
{id: 2, name: "Jane"},
{id: 3, name: "Tom"},
{id: 4, name: "Jack"},
{id: 5, name: "Sue"}
]);
var friends = new Collection(contactRepo,[
contactRepo.get(2),
contactRepo.get(4)
]);
var coworkers = new Collection(contactRepo,[
contactRepo.get(1),
contactRepo.get(2),
contactRepo.get(5)
]);
From the initialization of the Repository and the collections, what you are asking "Remove item from repository if there are no references to it" item 3 would need to be removed immediatly. You can however track the references in a few different ways.
I have considered using Object.observe for a similar situation. However, Object.observe does not work in all browsers. I have recently turned to WatchJS
I am working on understanding the code behind Watch.JS to allow a list of observers on an object to be created dynamically this would allow one to also remove an item that is no longer watched, though I suggest to remove the reference at the point of access - What I mean is a variable that shares the immediate lexical scope with an object that has given a single point of reference to it's sibling can be removed making it no longer accessable outside of the object that had exposed the record/item/property/object of it's sibling. With the reference that all of your other references depended on removed access to the underlying data is stopped. I am generating unique id for origin references to avoid accidentally reusing the same one.
Thank you for sharing your question and the structure you are using, it has helped me consider one of my own specific cases where I was generating uniquely identified references to a lexical sibling these unique ids were kept on the ONE object that had scope, After reading here I have reconsidered and decided to expose only one reference then assign that reference to a variable name where ever it is needed such as in creating a watcher or observer or other Collection.