How to access variables and methods of objects within an array [resolved] - javascript

So I have a class that looks something like this:
class Car {
constructor(name, pos) {
this.carName = name;
this.carPos = pos;
}
}
I then end up creating an array of objects using this class as so:
newCar = new Car("Fusion","100 100");
let carManifest = [newCar]
I later in my code go on to carManifest.push() several other Car objects into the array, building it up. Eventually I run into a for loop such that:
for (index = 0; index < carManifest.length; index++) {
if(carManifest[index].carName === 'Honda')
<Do Stuff>
}
Whenever I go to access carManifest[index].carName I get "undefined". I also had a get method within the object for the same variable, but using that in this context wouldn't even compile. I am aware that the array itself does not have these variables, but as far as I'm aware there is no way to declare an array to be of a specific class in JS like you can in Java and C.
Could anyone help me out? I am new to JS and have been stumped on this for the past hour. I will be glad to update this if there is not enough info. Thanks!
Note: Not sure if it matters but I am using Node.js

Change your code from
let carManifest = [newCar]
to push item to array as
carManifest.push(newCar);
/*
function Car (name, pos) {
this.carName = name;
this.carPos = pos;
}
*/
class Car {
constructor(name, pos) {
this.carName = name;
this.carPos = pos;
}
}
newCar = new Car("Fusion","100 100");
let carManifest = [];
carManifest.push(newCar);
for (index = 0; index < carManifest.length; index++) {
if(carManifest[index].carName === 'Fusion'){
console.log(carManifest[index].carName);
}
}

Are you pushing other variables or objects into the same array? There is nothing wrong with the code examples you're showing, you are able to access the variables of the objects this way. You'll have to show more code, where exactly are you getting undefined?

Related

Javascript - Collection of objects with parent properties in common

I'd like to create a collection of objects that works like an array. Some time ago, I made this question and I came up with the following solution with the help of the people that helped me:
Newobj.Collection = function(){
Array.apply(this);
for(var i = 0; i < arguments.length; i++){
for(var j = 0; j < arguments[i].length; j++){
this.push(arguments[i][j]);
}
}
return this
}
Newobj.Collection.prototype = Object.create(Array.prototype);
Newobj.Collection.prototype.push = function(o){
Array.prototype.push.call(this, new Newobj.Element(o));
}
However, this leaves the children unconnected from the parent. For example, imagine this collection has a render() function, which makes its children to print some HTML onto the page. Well, I'd like to be able to say something like:
Newobj.Collection.html_container = '#cont';
Newobj.Collection.render = function(){
$.each(this, function(i, el){
el.render()
})
}
Newobj.Element.render = function(){
$(parent.html_container).html('.......')
}
It should be able to set different collections in one page, so make a global container for all the Newobj.Collections is not a solution. This is an example, and I need this for more complex processes than just a render() function.
Anyone has an idea how can I make an array to be able to access a parent class which it is part of?
If the solution could be JSON.stringifyed and be seen as an array on the server side, it would be great too, though it's not the main problem for this question. Right now, if I set a property to the array, it is seen as an object with size > 0 on the server side.
Thank you!
Create reference to collection in element:
Newobj.Collection.prototype.push = function(o){
Array.prototype.push.call(this, new Newobj.Element(o,this));
}
//element constructor gets as second paramater instance of collection
Newobj.Element=function(o,collection){
//this.parent in every element is collection reference
this.parent=collection;
}
Newobj.Element.prototype.render = function(){
$(this.parent.html_container).html('.......')
}
or no reference in Element option:
Newobj.Collection.render = function(){
var parent=this;
$.each(this, function(i, el){
el.render(parent.html_container)
})
}
Newobj.Element.render = function(html_container){
$(html_container).html('.......')
}
But this version need to have methods parameters.

JavaScript: Cannot set property of undefined

I'm pretty new to JS and I'm trying to wrap my head around the object topic in JS.
What I'm trying to do is to set a property of an object prototype to an uninitialized array, so that I can later add multiple objects to that array (for instances of the prototype object)
My code looks like this so far:
function cocktail(){
this.prototype.ingredients = [];
this.printIngredients = function() {
var i;
for (i = 0; i<this.ingredients.length; ++i) {
console.log(this.ingredients.fluid);
console.log(this.ingredients.amount);
}
}
}
var Mojito = new cocktail();
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();
That throws:
TypeError: Cannot set property 'ingredients' of undefined
If I change my code into :
this.ingredients = [];
it works but the printIngredients() method prints undefined twice. When I do:
var array = [];
array.push({"a":1, "b":2});
console.log(array[0].a, array[0].b)
everything works as I would expect it to. Can someone clarify what I'm doing wrong and where my thoughts got mixed up?
Change your code to
function cocktail(){
this.ingredients = []; //this doesn't have prototype property
this.printIngredients = function() {
var i;
for (i = 0; i<this.ingredients.length; ++i) {
console.log(this.ingredients[i].fluid);//use the counter variable to get the fluid value at current counter value
console.log(this.ingredients[i].amount);//use the counter variable to get the amount value at current counter value
}
}
}
var Mojito = new cocktail();
console.log(Mojito.ingredients)
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();
Alternatively, if you are familiar with class-based languages, you could use modern JavaScript to avoid some of the confusion.
class Cocktail {
constructor() {
this.ingredients = []
}
printIngredients() {
// let is like var, but scoped to blocks instead of functions
// for...of iterates on values instead of keys/indices
for (let ingredient of this.ingredients) {
console.log(ingredient.fluid)
}
}
}
This kind of JavaScript is available from:
Chrome 49
Edge 13
Firefox 44
Node.js 6
Documentation:
Classes
let
for...of
well, first you want to remove printIngredients method out of the constructor function, it will improve performance when it comes to a larger project since you don't have to create different copies every time you instantiate the constructor function, secondly, it is a convention to capitalize the first letter of your constructor. Last but not least, use let and const as they limit the scope to block rather than var that's function scope.
function Cocktail(){
this.ingredients = [];
}
Cocktail.prototype.printIngredients = function() {
// for in ... iterates on keys rather than values
for (let i in this.ingredients) {
console.log(this.ingredients[i].fluid);//use the counter variable to get the fluid value at current counter value
console.log(this.ingredients[i].amount);//use the counter variable to get the amount value at current counter value
}
}
const Mojito = new Cocktail();
console.log(Mojito.ingredients)
Mojito.ingredients.push({"fluid":"White Rum", "amount":0.05});
Mojito.printIngredients();

Counter array in Javascript

I am trying to make two arrays. the unique array can get the elements (no repeats) from the text array, and the counter one can count the frequency of each elements. but something is wrong with the counter one.
var unique_array=new Array();
var counter_array=new Array();
var unique=true;
for (i=0;i<text_array.length;i++){
if (unique_array.length==0){
unique_array.push(text_array[0]);
counter_array.push(1);
}
else if(unique_array.length>0&&unique_array.length<=text_array.length){
for (j=0; j<unique_array.length;j++){
if (text_array[i]==unique_array[j]){
counter_array[j]=counter_array[j]+1;// something wrong with the
alert(counter_array[j]);
var unique=false;
}
}
if (unique==true){
unique_array.push(text_array[i]);
counter_array.push[1];
}
unique=true;
}
You could also simplify the code down using a hashmap and some ES5 higher-order functions:
var text_array = ["a1","a1","a2","a3","a2","a4","a1","a5"];
var counts = {};
text_array.forEach(function(el) {
counts[el] = counts.hasOwnProperty(el) ? counts[el]+1 : 1;
});
var unique_array = Object.keys(counts);
var counter_array=unique_array.map(function(key) { return counts[key]; })
You can do this much more simply using an object. Let the values be the keys of an object, then just increment the count of each property as you go. At the end, you can get an array of the unique keys and their values:
var text_array = ['foo','bar','foo','fum','fum','foo'];
var i = text_array.length;
var obj = {};
while (i--) {
if (obj.hasOwnProperty(text_array[i])) {
obj[text_array[i]]++;
} else {
obj[text_array[i]] = 1;
}
}
console.log('Unique values: ' + Object.keys(obj)); // Unique values: foo,fum,bar
console.log('Value counts: ' + Object.keys(obj).map(function(v){return obj[v]})); // Value counts: 3,2,1
Note that the sorting of counts in the output is purely coincidental.
As Jasvir posted, you can make it pretty concise:
var obj = {};
text_array.forEach(function(v) {
obj.hasOwnProperty(v)? ++obj[v] : obj[v] = 1;
});
But the first example is a bit easier to digest.
I think the approach is what's making it difficult. A hash table / associative array would be much easier to work with.
With a hash table (an object {} in JS), you can store each word in a key and increment the value of the key when you encounter the word again. Then, at the end, just go through the hash table and gather up all the keys which have small values. Those are your unique words.
function get_unique_words(text_array) {
var hash_table, i, unique_words, keys;
hash_table = {};
for(i = 0; i < text_array.length; i++) {
if(hash_table[text_array[i]] === undefined) {
hash_table[text_array[i]] = 1;
} else {
hash_table[text_array[i]]++;
}
}
// go through the hash table and get all the unique words
unique_words = [];
keys = Object.keys(hash_table);
for(i = 0; i < keys.length; i++) {
if(hash_table[keys[i]] === 1) {
unique_words.push(keys[i]);
}
}
return unique_words.sort();
}
console.log(get_unique_words(
['blah', 'blah', 'blah', 'goose', 'duck',
'mountain', 'rock', 'paper', 'rock', 'scissors']
));
Some issues and suggestions :
Don't use var twice for the same variable.
Browsers deal with it ok, but for clarity you should only be declaring your variables once.
Always localize your loop counters - forgetting a var before your i and j will cause them to become global variables.
This is relevant when you have a page with lots of code - all global variables will show up in the debugger's watch list at all times, making it harder to debug your code.)
Use the array literal notation [] instead of the function form Array.
The function form is longer and it's easier to forget the new. It's also easier to read (IMO).
Use more whitespace (it won't bite), such as before and after an equals sign:
var x = 1;
// vs.
var x=1;
It makes the code easier to read and most people don't overdo it.
Indent your code when it's inside a block (e.g. function, if, else, while, for, etc.).
This makes it easier to read the control flow of the code and will help prevent bugs.
Use three equals signs (===) unless you are using loose equality on purpose.
This will help someone looking at your code later (probably yourself) understand better what the test is supposed to be testing.

looping through objects to return objects with 'distinct' property - Javascript

I have a list of objects as shown in the image.
These all have the property statusCode: 62467 but the journey property goes like: 0,1,2,3,3,4,4,4,4
I want to loop through these objects and return the FIRST of the duplicated (they are not the same object, just that both have the same journey number and the same status code) objects with the same journey number.
So I want to return the bold objects: 0,1,2,3,3,4,4,4,4
$.each(points, function (index, point) {
for (i = 0; i < journeyNumber.length; i++) {
if (point.k.journey === journeyNumber[i] && point.k.statusCode === '62467') {
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
}
});
The screenshot is the log of console.log(point), so ideally I would like another loop inside which returns only the first object of the same journey number.
Hope this makes sense and thank you for your time.
Try this,
var temp = [];
$.each(points, function (index, point) {
if (temp.indexOf(point.k.journey) === -1) {
temp.push(point.k.journey);
console.log(point);
latlngs.push(point.j.aa.k);
latlngs.push(point.j.aa.B);
}
});
Create a fresh object with status codes and check against that.
var journeys = {};
for(object in points){
// extract the properties you want (or use them directly, this is not necessary)
var journey = points[object].journey;
var status = points[object].statusCode;
// use the typeof operator to see if the journey has already been set before
if(typeof journeys[journey] == "undefined"){
// then define it.
journeys[journey] = status;
}
}
(Please note I am not actually correctly referencing the journey and statusCode, you'd have to do something like objects[object][k].journey to access the right property, but thats not really the point)
You can even add anything you want into the journeys object, nesting another object with the extracted latitude and longitude, or even just nesting the entire object in the journey!
journeys[journey] = points[object];
Now you can get every journey by looping through them again, and the associated first statusCode:
for(journey in journeys){
console.log("First instance of journey " + journey + " had statusCode " + journeys[journey]);
}

Can I select 2nd element of a 2 dimensional array by value of the first element in Javascript?

I have a JSON response like this:
var errorLog = "[[\"comp\",\"Please add company name!\"],
[\"zip\",\"Please add zip code!\"],
...
Which I'm deserializing like this:
var log = jQuery.parseJSON(errorLog);
Now I can access elements like this:
log[1][1] > "Please add company name"
Question:
If I have the first value comp, is there a way to directly get the 2nd value by doing:
log[comp][1]
without looping through the whole array.
Thanks for help!
No. Unless the 'value' of the first array (maybe I should say, the first dimension, or the first row), is also it's key. That is, unless it is something like this:
log = {
'comp': 'Please add a company name'
.
.
.
}
Now, log['comp'] or log.comp is legal.
There are two was to do this, but neither avoids a loop. The first is to loop through the array each time you access the items:
var val = '';
for (var i = 0; i < errorLog.length; i++) {
if (errorLog[i][0] === "comp") {
val = errorLog[i][1];
break;
}
}
The other would be to work your array into an object and access it with object notation.
var errors = {};
for (var i = 0; i < errorLog.length; i++) {
errors[errorLog[i][0]] = errorLog[i][1];
}
You could then access the relevant value with errors.comp.
If you're only looking once, the first option is probably better. If you may look more than once, it's probably best to use the second system since (a) you only need to do the loop once, which is more efficient, (b) you don't repeat yourself with the looping code, (c) it's immediately obvious what you're trying to do.
No matter what you are going to loop through the array somehow even it is obscured for you a bit by tools like jQuery.
You could create an object from the array as has been suggested like this:
var objLookup = function(arr, search) {
var o = {}, i, l, first, second;
for (i=0, l=arr.length; i<l; i++) {
first = arr[i][0]; // These variables are for convenience and readability.
second = arr[i][1]; // The function could be rewritten without them.
o[first] = second;
}
return o[search];
}
But the faster solution would be to just loop through the array and return the value as soon as it is found:
var indexLookup = function(arr, search){
var index = -1, i, l;
for (i = 0, l = arr.length; i<l; i++) {
if (arr[i][0] === search) return arr[i][1];
}
return undefined;
}
You could then just use these functions like this in your code so that you don't have to have the looping in the middle of all your code:
var log = [
["comp","Please add company name!"],
["zip","Please add zip code!"]
];
objLookup(log, "zip"); // Please add zip code!
indexLookup(log, "comp"); // Please add company name!
Here is a jsfiddle that shows these in use.
Have you looked at jQuery's grep or inArray method?
See this discussion
Are there any jquery features to query multi-dimensional arrays in a similar fashion to the DOM?

Categories