Javascript - make array of objects and understanding constructors - javascript

I know this question has been asked before, but they're always project specific and I can't find what i'm looking for.
I need an array of objects in javascript. I have declared a class as :
var svgData = {.....}
(the keyword class isn't available in esversion: 5)
and I have an array variable :
var svgContent = [];
I tried doing it like you would in C# where you would write :
svgContent[0] = new svgData();
However you would normally create a constructor for it, which as far as I can tell, doesn't exist in javascript. I have been using a function like this:
function SvgData (....) {
this.var = ...;
etc.
}
but the problem is that there is no link between this and the class, and as such I have an issue that when I try to access a variable in the array using a for loop like this:
for(var i = 0; i < length; i ++){
console.log(svgContent[i].var);
}
it returns the same number repeatedly (its just overriding itself, since the way i have done it has linked every array element to the exact same variable svgData{}.
How do I make an instance of a class (object)? And how do you link the constructor to the variable?

You could easily change your code to get what you want (as far as I understand):
function SvgData(value) {
this.var = value;
// ...
}
// use this instead of your svgData variable:
SvgData.prototype = {
// ...
}
var svgContent = [];
svgContent.push(new SvgData("value"));
Read more on JavaScript prototypes.

You should consider the fact the JavaScript is a standalone language and implement things in its own way. From your question, I understand you want an array (which is still an object in JS, just with some special properties) of objects and you want those object to be made from a template (let's say a "class").
You've mentioned that there are no constructors, since there are no classes. But the way you've used function SvgData is exactly how you can design "classes". That's called a constructor function and it's special because it has no other statements than assignments to this object and thus it implicitly returns the this object (a constructor function is any function which returns the this object).
The syntax: new SvgData is basically syntax sugar for: create a new empty object (from "new") and assign to it the this object that is returned from whatever function comes next.
function SvgData (val) {
this.var = val;
}
var myLength = 10;
var myArr = [];
for (var i = 0; i < myLength; i ++) {
myArr.push(new SvgData(i));
}
console.log(myArr);
This should do what you want it to do. You can test it here.

Related

JavaScript array value to variable

I am trying to get into Fuse to create mobile apps and they use JavaScript for their logic. I never used JavaScript before and just recently completed their getting started course. Most of the stuff is pretty easy to understand, but I am having trouble with the way they use variables at one point. It would be nice, if somebody could explain how variables behave in JavaScript.
So the problem I have goes as follows:
for (var i = 0; i < hikes.length; i++){
// A new variable gets the value of the array
var hike = hikes[i];
if (hike.id == id){
// The variable gets a new value
hike.name = "foo";
break;
}
}
So, in my understanding of programming, the array hikes should be unchanged and only the variable hike should have foo as the name value. But in reality, the array now also has the name foo.
I guess the variable works as a pointer to the address of the arrays value, but maybe somebody can help me to better understand that concept.
Yes you're right, objects and arrays are always passed as references:
a = {}; // empty object
b = a; // references same object
b.foo = 'bar';
a.foo; // also 'bar'
You can create a deep copy of the array using JSON.parse(JSON.stringify(hikes)); and then use that copied array for manipulation:
var hikes = [
{
'id': 10
}
];
var id = 10;
var tempHikes = JSON.parse(JSON.stringify(hikes));
for (var i = 0; i < tempHikes.length; i++){
// A new variable gets the value of the array
var hike = tempHikes[i];
if (hike.id == id){
// The variable gets a new value
hike.name = "foo";
console.log('hike is ', hike);
break;
}
}
console.log(hikes);
arrays in javascript are passed by reference, whenever you modify an element in an array that change will occur anywhere you are accessing that array, to avoid such issues you have to use Array.from(arg) which creates a new array of from the arg parameter. This also applies to objects, to avoid such issues with objects, you have to use Object.create(obj) to create a new obj of from obj parameter or you can use let newObj = Object.assign( {} , obj ) , whenever you make any modification to the members of newObj the obj object does not see it, in other words there is no direct linkage between this two object, same thing applies for array
Boolean, null, undefined, String, and Number values are called primitive types.
When you assign something that is not a primitive type, namely arrays, functions and objects you are storing a reference to that.
That means that hikes[i] contains a reference to the object, where reference roughly means a pointer to it's location in memory.
When you assign hike = hikes[i] you are copying over the reference and not the actual object. So in fact hike still points to the same object as hikes[i], so any changes to that object are visible on both occasions.
If you want to copy the underlying object, there are different ways of doing so. One of them is Object.assign:
var hike = Object.assign({}, hikes[i])
This is because of pass by reference. All you need to do is create a new object (string, number ...) that you can work on.
for (var i = 0; i < hikes.length; i++){
var hike = hikes.slice(i,i+1)[0];
if (hike.id == id){
hike.name = "foo";
break;
}
}
slice also create a deep copy. you can use splice or assign or ((key1, key2)=>(key1, key2))(obj) etc.

JavaScript array as function input

I am be beginner in JavaScript, and do not know how to make a simple function with an array/vector as an input. This is the code I have:
function semGPA(credits) {
var c = credits.length;
return c;
}
I want to pass a list of numbers (ex. credits={3,4,5,6}), and have it tell me that there are 4 elements in the variable. So far, I have not found any built in functions that create a working function. Everything I try to use other than +-*/ results in a TypeError. Here it says the property "length" is undefined.
It's not entirely clear what you want. You can pass an array as credits and your function will work fine (although it's a bit pointless as is, since you can just directly call length on your array):
semGPA([1,2,3,4]); // returns 4
Perhaps you meant that you wanted to do something like this?
function semGPA() {
var c = arguments.length;
return c;
}
Which you can call like this:
semGPA(1,2,3,4); // returns 4
Which uses the arguments object which is a special object passed to functions that can be used to access all the arguments (including unnamed arguments) passed to a function.
As mentioned in the comments the example you have is an Object and not an array.
var array = [1,2,3,4,5]
var object = {1,2,3,4,5} ==> This is not a valid object in Javascript.
The object notation above expects a key-value pair. something like
var object = {1: 1, 2: 2, 3: 3}
The length property does not exist on an object. However, if you want to check the number of elements in an Object you can make use of the below code which is self explanatory:
var credits = {1:1,2:2,3:3,4:4}
function semGPA(credits) {
var creditKeysArray = Object.keys(credits); //this will give you an array of keys
var creditLength = c.length;
return creditLength;
}

Javascript - Performing actions on Array elements on creation [duplicate]

This question already has answers here:
Subclassing Javascript Arrays. TypeError: Array.prototype.toString is not generic
(7 answers)
Closed 6 years ago.
I'm trying to create an Object/Class in Javascript that behaves like an Array but with some added functionalities.
I've achieved this with these simple lines:
var Newclass = Array
Newclass.prototype.get_by_id = function(){}
However, I'm trying to perform some actions just when I call this new class, so elements I'm adding to this are treated (and transformed, if needed) in a specific way.
I'm wondering if there is a way of making it on the fly, so I could do something like:
var a = New Newclass('hello', 'goodbye', 'good afternoon')
And automatically, get variable a to be (for example):
console.log(a)
["HELLO", "GOODBYE", "GOOD AFTERNOON"]
I know how to do it with loops and Array functions (like map and so), but I'd like to know if there is anyway to overwrite the constructor (on this Newclass) so it gets applied automatically for everyone of its elements on creation, without breaking anything.
EDIT
Thank you everyone for your time and answers. However, I must say this is not a duplicate, as I'm not asking how to work with arguments (or if they exist), but how to work with them on the construction of an Array derivated class, which I find is totally different.
Even knowing the arguments parameter exists, I still don't know how to process these arguments on the constructor of the Array and having still all the native functions of this kind of object.
You can make your own derivative of an Array:
function uppercaseStringArray(){
Array.call(this);
for(var i = 0; i < arguments.length; i++) this.push(arguments[i]);
}
uppercaseStringArray.prototype = Object.create(Array.prototype);
uppercaseStringArray.prototype.push = function(string){
Array.prototype.push.call(this, string.toUpperCase());
}
This works exactly like you expect and it still has all the properties normal arrays have:
function uppercaseStringArray(){
Array.call(this);
for(var i = 0; i < arguments.length; i++) this.push(arguments[i]);
}
uppercaseStringArray.prototype = Object.create(Array.prototype);
uppercaseStringArray.prototype.push = function(string){
Array.prototype.push.call(this, string.toUpperCase());
}
var a = new uppercaseStringArray('tomato', 'apple', 'pear');
console.log(a);
document.write('[' + a.join(', ') + ']');
You could modify the push method to take an unlimited amount of arguments. Please note, however, that this is not a full array, as a[5] = 'thingy' will not modify the length of your array, so be sure to use only methods to add and remove from your array.
This also indentifies itself as both an Array and an uppercaseStringArray using instanceof. And you can add your own methods to the array, like your get_by_id function in its prototype.

Substitute array values into a loop to create new arrays

I don't program in javascript much so feel free to tell me if this is a crazy idea.
I'd like to take values in an array and build arrays off of those values. For example, using the "people" array below, I want to create empty arrays "jack_test", "john_test", "mary_test", etc.
var people = ["jack","john","mary"];
for (var i = 0; i < people.length; i++){
//I'd like to execute code here that would create new arrays like jack_test = [], john_test= [], etc.
}
UPDATE: poor question, sorry about that. I'm really at a beginners level with this stuff so bear with me. Let's try a little different scenario (sorry if it strays from original question too much):
Say I have an array like "people", though in reality, it'll be much longer. Then I have another array that has associated body weights, i.e.
var weights = [150,180,120]
For each person, I'd like to take their starting weight in the array "weights" and add some constant to it to form variables (or as #Pointy points out, form property names) "jack_weight","john_weight" etc.
If I've set this up wrong in my mind and there's some more efficient method, please let me know.
You cannot "construct" variable names in JavaScript*, but you can construct object property names.
var people = ["jack","john","mary"], tests = {};
for (var i = 0; i < people.length; i++){
//I'd would like to execute code here that would create new arrays like jack_test = [], john_test= [], etc.
tests[people[i]] = "something";
}
That will create properties of the "tests" object with names taken from your array. Furthermore, people[i] could be any expression, if you wanted to do something like add prefixes to the names.
* yes I know, there's eval(). edit and globals, which are object properties and thus a special case of the above example really, except with additional hazards ("special" global symbols etc).
You can't exactly replicate var jack_test = [], which is locally scoped, but you can do this either globally scoped via the window object or locally within any other object.
var people = ["jack","john","mary"];
for (var i = 0; i < people.length; i++) {
// assigns the property globally
window[people[i]+'_test'] = [];
}
console.log(jack_test); // []
This works because in the global scope (i.e. outside of any functions), variables like var x = 'whatever' are assigned to window, so these are synonymous:
var x = 'whatever';
window.x = 'whatever';
Instead of using window, you can assign properties dynamically to any object using the same method.
var myObj = {};
var myProp = 'foo';
myObj[myProp] = 'foo value';
console.log(myObj.foo); // 'foo value'

How to hydrate a WinJS.Class

I am serializing and storing an object that was created from a WinJS.Class like this:
var myClass = WinJS.Class.define(...);
var myObject = new myClass();
var serialized = JSON.stringify(myObject);
//store the object
And later I'm pulling the object out of storage and I want to deserialize it and cast it as a myClass. Is that possible with WinJS out of the box or do I need to create a constructor for my class that is capable of taking an object that can turn it into a new object?
I haven't broken into TypeScript yet, and I think that would help out in this situation, but until then I'm wondering how to do it with plain JavaScript/WinJS.
There are a few ways to handle this, and none are particularly special to WinJS. Simply put: JSON serialization only serializes and deserializes the obje values, not its methods, prototype, or other type information.
Option 1: Copy values to new instance of your class
This is usually best accomplished by having your constructor take the deserialized object as a parameter and copying the data to the new instance.
There are a variety of variations of this. Using the object constructor is generally the best for performance, as this typically enables the JS engine to apply the greater number of optimizations to the object.
WinJS.UI.setOptions can be helpful here, or you can just copy the data using a simple loop like this:
var keys = Object.keys(source);
for (var i = 0, len = keys.length; i < len; i++) {
var key = keys[i];
destination[key] = source[key];
}
Option 2: Setting __proto__
Warning: This can have significantly adverse performance effects, so it's not appropriate in some situations. But occasionally it can be handy.
Object.setPrototypeOf(myObject, myClass.prototype);
Note that setPrototypeOf is relatively new. It's there on Win8.1 for web apps (which I'm guessing this is about) and in IE 11, but not available in Safari, for example. On older browsers/ Safari, assigning to proto is the equivalent (but if available, setPrototypeOf is better).
This will attach methods from myClass to the object, but in addition to the negative performance effects, also does not run your constructor on the object - so it still may not be in exactly the same state as the object you originally serialized.
Other helpful thing: JSON "revivers"
JSON.parse takes an optional second parameter, called a "reviver". This lets you provide a function that gets the opportunity to transform each node of the JSON being deserialized. This can be useful for rehydrating serialized dates into JavaScript Date objects, for example. It also gets the opportunity to transform the top-most object, which could be useful in some cases to turn the deserialized object into the "class" you want.
Javascript is a dynamic language so I think you dont need to cast the deserialized object, just treat it as myClass type and that's it. Hope it helps you.
You should consider using the 'Options' constructor pattern, where the option value is the deserialized object:
// MovieModel Constructor
// ----------------------
function MovieModel(options) {
this._titleValue = options.title || "Sample Title";
}
Where the movie methods closure is something like this:
// MovieModel Methods
// ------------------
var movieModelMethods = {
title: {
get: function () {
return this._titleValue;
},
set: function (val) {
this._titleValue = val;
this.dispatchEvent("title");
}
}
};
Since WinJS class define can only specify one constructor function (as far as I understand it), you may use the static members to define a factory function that will take the serialized data as a parameter. This factory methdod will actually create a new instance and will set the values one by one and return the new object.
It as some advantages like the fact that you can actually manage the data structure changes over the time you enhance the app...
The drawback is that you cannot write new MySuperClass() all the time...
...
// let's suppose we already called JSON.parse(data);
create: function(serializedData) {
var newObj = new MySuperClass();
newObj.name = serializedData.name || "";
newObj.color = serializedData.color || "";
return newObj;
}
Then you will call somewhere else in the app :
var myInstance = MySuperClass.create(serializedDataFromfile);
You should just be able to call JSON.parse after pulling it out of local storage:
var myObject2;
myObject2 = JSON.parse(localStorage["mySeriazliedObject"];

Categories