I am using two classes in javascript.
class Challenge and class Modules, that extends Challenge.
in Challenge i have this constructor:
constructor() {
this.handles = [];
}
and this method:
bla() {
let elmnts = document.querySelectorAll("p"); // 5x
for(let i=0; i < elmnts.length; i++) {
let elmnt = elmnts[i];
this.handles[elmnt['id']] = elmnt; // saves the handles to each element in separate array for later use
}
}
in the child Class i am trying to use this "this.handles" array, but it is always empty.
It is not "undefined" but it is an empty array as i defined it in the constructor. its like the entries have never been set... but they are (as console.log() shows, when i insert it directly after the for()-loop)
console.log(this.handles); // --> []
Why does this happen?
this.handles is an array. So when you are doing this.handles[elmnt['id']], elmnt['id'] returns a string, whereas an array expects (positive) integer for index. So the elements are not set in the array.
Maybe you meant this.handles to be an object?
class Ex1 {
constructor() {
this.handles = {};
}
bla() {
let elmnts = document.querySelectorAll("p"); // 5x
for (let i = 0; i < elmnts.length; i++) {
let elmnt = elmnts[i];
this.handles[elmnt['id']] = elmnt; // saves the handles to each element in separate array for later use
}
}
}
class Ex2 extends Ex1 {
constructor(){
super();
}
m1(){
console.log(this.handles);
}
}
let p1 = new Ex2();
p1.m1();
p1.bla();
p1.m1();
<p id="one">1</p>
<p id="two">2</p>
<p id="three">3</p>
<p id="four">4</p>
<p id="five">5</p>
You need to understand the following things:
In Javascript...
... Arrays are always index-based (0 pointing to the first array element).
... you append elements to an array using arr.push(el).
... Arrays are also objects, so adding arbitrary properties also works (which is what you are doing by using the p element id as a key and assigning it the element reference). See this example:
If you need an array (which preserves order and can easily be iterated later on), just spread the NodeList you got from querySelectorAll('p') into the array using the ES6 spread syntax ...:
this.handles = [...document.querySelectorAll("p")];
Related
Currently, I have an empty new object and I want to populate values from an existing object to new object because I want to use an object with only limited properties from the existing object (e.g. I only want the four properties instead of eight).
Here's how I am doing the mapping so far:
const newObject: any = {};
for (let i = 0; i < this.PRODUCT_DATA.length; i++) {
newObject._productSkuKey = this.PRODUCT_DATA[i]._productSkuKey;
newObject._storeKey = this.itemPriceForm.get('location').value;
newObject._price = this.PRODUCT_DATA[i]._price;
newObject._status = this.PRODUCT_DATA[i]._isActive;
this.updatedProducts.push(newObject);
}
So far, it looks to be storing the values from the existing object to newObject. However, it is only saving the last object values and not the different values from the object. How can I fix this to save all values (not just the last values for every object in the array)?
You need to make a copy of that before pushing in array
const newObject: any = {};
for (let i = 0; i < this.PRODUCT_DATA.length; i++) {
newObject._productSkuKey = this.PRODUCT_DATA[i]._productSkuKey;
newObject._storeKey = this.itemPriceForm.get('location').value;
newObject._price = this.PRODUCT_DATA[i]._price;
newObject._status = this.PRODUCT_DATA[i]._isActive;
this.updatedProducts.push(Object.assign({}, newObject));
// Or
// this.updatedProducts.push({ ...newObjec });
}
Or Simply create object inside loop. I love to use Array.prototype.forEach and Array.prototype.map
this.updatedProducts = this.PRODUCT_DATA.map(({_productSkuKey, _price, _isActive})=> ({
_productSkuKey,
_storeKey: this.itemPriceForm.get('location').value,
_price,
_status: _isActive
});
Avoid declaring newObject as 'const'. This is an updated code that works for me.
//avoid using a const, as you cannot override it
let newObject: any = {};
for (let i = 0; i < this.PRODUCT_DATA.length; i++) {
newObject._productSkuKey = this.PRODUCT_DATA[i]._productSkuKey;
newObject._storeKey = this.itemPriceForm.get('location').value;
newObject._price = this.PRODUCT_DATA[i]._price;
newObject._status = this.PRODUCT_DATA[i]._isActive;
this.updatedProducts.push(newObject);
//after pushing the object, empty all the current contents
newObject={};
}
I'm adding three different objects to an ArrayList, but the list contains three copies of the last object I added.
For example:
for (Foo f : list) {
System.out.println(f.getValue());
}
Expected:
0
1
2
Actual:
2
2
2
What mistake have I made?
Note: this is designed to be a canonical Q&A for the numerous similar issues that arise on this site.
This problem has two typical causes:
Static fields used by the objects you stored in the list
Accidentally adding the same object to the list
Static Fields
If the objects in your list store data in static fields, each object in your list will appear to be the same because they hold the same values. Consider the class below:
public class Foo {
private static int value;
// ^^^^^^------------ - Here's the problem!
public Foo(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
In that example, there is only one int value which is shared between all instances of Foo because it is declared static. (See "Understanding Class Members" tutorial.)
If you add multiple Foo objects to a list using the code below, each instance will return 3 from a call to getValue():
for (int i = 0; i < 4; i++) {
list.add(new Foo(i));
}
The solution is simple - don't use the static keywords for fields in your class unless you actually want the values shared between every instance of that class.
Adding the Same Object
If you add a temporary variable to a list, you must create a new instance of the object you are adding, each time you loop. Consider the following erroneous code snippet:
List<Foo> list = new ArrayList<Foo>();
Foo tmp = new Foo();
for (int i = 0; i < 3; i++) {
tmp.setValue(i);
list.add(tmp);
}
Here, the tmp object was constructed outside the loop. As a result, the same object instance is being added to the list three times. The instance will hold the value 2, because that was the value passed during the last call to setValue().
To fix this, just move the object construction inside the loop:
List<Foo> list = new ArrayList<Foo>();
for (int i = 0; i < 3; i++) {
Foo tmp = new Foo(); // <-- fresh instance!
tmp.setValue(i);
list.add(tmp);
}
Your problem is with the type static which requires a new initialization every time a loop is iterated. If you are in a loop it is better to keep the concrete initialization inside the loop.
List<Object> objects = new ArrayList<>();
for (int i = 0; i < length_you_want; i++) {
SomeStaticClass myStaticObject = new SomeStaticClass();
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
}
Instead of:
List<Object> objects = new ArrayList<>();
SomeStaticClass myStaticObject = new SomeStaticClass();
for (int i = 0; i < length; i++) {
myStaticObject.tag = i;
// Do stuff with myStaticObject
objects.add(myStaticClass);
// This will duplicate the last item "length" times
}
Here tag is a variable in SomeStaticClass to check the validity of the above snippet; you can have some other implementation based on your use case.
Had the same trouble with the calendar instance.
Wrong code:
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// In the next line lies the error
Calendar newCal = myCalendar;
calendarList.add(newCal);
}
You have to create a NEW object of the calendar, which can be done with calendar.clone();
Calendar myCalendar = Calendar.getInstance();
for (int days = 0; days < daysPerWeek; days++) {
myCalendar.add(Calendar.DAY_OF_YEAR, 1);
// RIGHT WAY
Calendar newCal = (Calendar) myCalendar.clone();
calendarList.add(newCal);
}
Every time you add an object to an ArrayList, make sure you add a new object and not already used object. What is happening is that when you add the same 1 copy of object, that same object is added to different positions in an ArrayList. And when you make change to one, because the same copy is added over and over again, all the copies get affected.
For example,
Say you have an ArrayList like this:
ArrayList<Card> list = new ArrayList<Card>();
Card c = new Card();
Now if you add this Card c to list, it will be added no problem. It will be saved at location 0. But, when you save the same Card c in the list, it will be saved at location 1. So remember that you added same 1 object to two different locations in a list. Now if you make a change that Card object c, the objects in a list at location 0 and 1 will also reflect that change, because they are the same object.
One solution would be to make a constructor in Card class, that accepts another Card object. Then in that constructor, you can set the properties like this:
public Card(Card c){
this.property1 = c.getProperty1();
this.property2 = c.getProperty2();
... //add all the properties that you have in this class Card this way
}
And lets say you have the same 1 copy of Card, so at the time of adding a new object, you can do this:
list.add(new Card(nameOfTheCardObjectThatYouWantADifferentCopyOf));
It can also consequence of using the same reference instead of using a new one.
List<Foo> list = new ArrayList<Foo>();
setdata();
......
public void setdata(int i) {
Foo temp = new Foo();
tmp.setValue(i);
list.add(tmp);
}
Instead of:
List<Foo> list = new ArrayList<Foo>();
Foo temp = new Foo();
setdata();
......
public void setdata(int i) {
tmp.setValue(i);
list.add(tmp);
}
I am trying to create a array with multiple fields in it.
For Example:
var person1 = {firstname:"Bob", lastname:"Smith", middlename:"happy"};
The problem I have is that I have 5000 variables I want to create so it would become:
var person1 = {firstname:"Bob", lastname:"Smith", middlename:"happy"};
var person2 = {firstname:"John", lastname:"Jones", middlename:"Long"};
..
var person5000 = {firstname:"Jim", lastname:"Cook", middlename:"Shorty"};
I think it would be silly to have 5000 lines of code to declare the variables.
So I want to be able to declare the variables on page load and then later assign the values to each.
I was trying to do this using the following code but I am guessing I am doing something wrong.
(I am loading some dummy data into the variables for testing)
<!DOCTYPE html>
<html>
<body>
<script>
var person = new Array (firstName:"", lastName:"", middleName:"");
for (var i = 0; i < 5000; ++i) {
person[i] = {firstName:"First"+i, lastName:"Last"+i, middlename:"Middle"+i};
}
alert(person1["firstName"]); // should alert First1
alert(person6["lastname"]); // should alert Last6
</script>
</body>
</html>
I was hoping to later in my code set the value using:
(I am pretty sure this code should work, but can't test it since I can't declare the variables correctly)
person1[firstname] = "Terry"; // should replace First1 with Terry
And then to receive a value using:
alert(person1[firstname]); // should alert Terry since it was changed
Anyone know what is wrong with my code since it's not returning the value ?
I am guessing I am declaring the variables wrong? If so how should I declare them ?
You appear to be confused about the difference between arrays and objects in Javascript. Arrays have numeric indexes, objects have named properties. So the initialization
new Array(firstName:"", lastName:"", middleName:"");
makes no sense. Not to mention, it's not valid Javascript syntax; property: value pairs can only be used in object literals, not in argument lists. If you use new Array(...), the argument should either be a single number, which is the size of the array to allocate, or a list of initial array element (with no property: prefixes. But the preferred way to create a new array is simply with the [] literal for an empty array; it will grow as necessary when you assign to it.
When you create an array, you don't get separate variables for each element. You access them using array[n] notation.
// Create an empty array
var person = [];
// Fill up the array
for (var i = 0; i < 5000; ++i) {
person[i] = {firstName:"First"+i, lastName:"Last"+i, middlename:"Middle"+i};
}
// Access elements
alert(person[1].firstName);
alert(person[6].middleName);
// Change elements
person[1].firstName = "Terry";
I believe this should work as you intended:
var person = new Array();
for (var i = 0; i < 5000; ++i) {
person[i] = {firstName:"First"+i, lastName:"Last"+i, middleName:"Middle"+i};
}
alert(person[1]["firstName"]);
alert(person[6]["lastName"]);
As pointed out by others, the person array is filled with objects, not arrays. You can use either property or associative array syntax with them.
I have JavaScript "Class" that makes js objects smarter. I serialize these objects to localStorage and restore them. But these restored object are not instances of a class. Restored objects are just property-sets. So, I do set __proto__ of these objects.
And I've read that using __proto__ is wrong (slow and deprecated) approach to make objects smarter.
What is smart solution for these problem? How to restore JavaScript objects so that they will be instances of the corresponding classes?
var showMarks = function (locals) {
var myMarks = locals.myMarks = locals.myMarks.slice(0, 120);
for (var i = myMarks.length - 1; i >= 0; i--) {
myMarks[i].__proto__ = Mark.prototype;
}
}
showMarks(JSON.parse(localStorage.myMarks));
UPDATE According to comment, I added a replacement of original literal objects foreach myMarks
You could first instanciate your class, then loop through your object's properties to set them after instanciation
var mark, key;
for (var i = myMarks.length - 1; i >= 0; i--) {
mark = new Mark();
for (key in myMarks[i]) {
if (myMarks[i].hasOwnProperty(key)) {
mark[key] = myMarks[i][key];
}
}
// replace previous plain object with the new instance of Mark
myMarks[i] = mark;
}
I suppose you can add a property indicating the class they belongs to before storing them (ie: .__class).
Then, you can write a function (let's say restore(obj)):
function restore(obj){
switch(obj.__class){
case "Class1":
return new Class1(obj.a, obj.b);
}
return null;
}
The correct solution is to have a method to serialize and one to unserialize your instance. JSON.stringify/parse work well for plain objects, but if you want more, you have to make your custom methods.
Example with class that has private properties:
function Cls(name) {
var private_name = name; // private!
this.getName = function() { return private_name; }
}
Cls.prototype.sayHi = function() {
console.log(this.getName() + ' says hi!');
}
// serialization
Cls.prototype.toJSON = function() {
return JSON.stringify({ // add what you need to reconstruct the class in it's current state
name : this.getName()
});
}
Cls.fromJSON = function(str) {
return new Cls(JSON.parse(str).name); // you might need to have a special case in the constructor for this
}
// usage:
var c = new Cls('me');
var serialization = c.toJSON();
var clone = Cls.fromJSON(serialization);
clone.sayHi()
I have various elements with same class (cCameras). I am able to push the elements into the empty array but for some reason I cannot access the elements inside the array.
var eCamerasArray = [];
// elements in this class are being pushed into the array 'cCameras'
$(".cCameras").each (function (){ eCamerasArray.push (this); });
// Firebug gives me an array with elements inside.
console.log (eCamerasArray);
for( var i = 0; i < eCamerasArray.length; i++) {
// Firebug gives me [undefined].
console.log (eCamerasArray[i]);
}
You could just write $(".cCameras").toArray() to get the same result, possibly one that works.