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.
Related
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.
This question already has answers here:
Most efficient way to create a zero filled JavaScript array?
(45 answers)
How to initialize an array's length in JavaScript?
(20 answers)
Closed 8 years ago.
How to create an array with length 3 and the value for the array element is 0.
if i give the length of the array as 3, then the array should be like below
a[0]=0;
a[1]=0;
a[2]=0;
I have tried this new Array(3), it creates an array a[,,,] of length 3 and new Array(0,0,0) creates an array a[0,1,2], Is it possible to create an array by defining the length and value for the array element?
Thanks in Advance
Is it possible to create an array by defining the length and value for the array element?
If you mean, some kind of pre-initializing constructor or fill operation, no, JavaScript doesn't have that.
If you know you want three elements as of when you're writing the code, you can do this:
a = [0, 0, 0];
It's called an array initializer.
If you don't know in advance (e.g., when writing the code) how big the array should be, you can just fill it as necessary:
a = [];
var index;
for (index = 0; index < initialSize; ++index) {
a[index] = 0;
}
Note that you don't have to pre-allocate room in the array; the array can "grow" as required. (This may seem strange, but standard JavaScript arrays aren't really arrays at all, although JavaScript engines will frequently try to use true arrays as an optimization if they think they can.)
But if you want to, you can tell the engine engine in advance what length you want, by using:
a = new Array(initialSize);
...rather than a = []; above. (More on this near the end.)
If you wanted to, you could add a function to the Array function object to do that:
Array.createFilled(length, value) {
var a = new Array(length); // Or of course, `var a = [];`
var i;
for (i = 0; i < length; ++i) {
a[i] = value;
}
return a;
}
Then using it in the various places you want a pre-filled array:
var a = Array.createFilled(3, 0); // 0,0,0
Side note: Always be sure to declare your variables, e.g., have a var a; somewhere prior to the line above.
Obviously, telling the engine in advance how big the array should be would let it do better optimization, right? Not necessarily! It may help some engines (a small bit), hinder others (a small bit), and/or make no difference:
I'm working with phylogentic trees and I want an object for the tree itself and then an object for each species, 4 species total. I'm trying to have the tree contain the species objects under tree.leaf and then assign an array of attributes to each species but through the tree object, because I'm randomizing the order of the species so I can't depend on species names but I can use leaf placement(Hope that makes sense). I'm having trouble updating the html, a div inside a table though.
Simplified Version:
var tree = new Object();
var speciesA = new Object();
tree.leaf1 = speciesA;
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
var count = 1;
for(attr in speciesA.attributes)
{
//There are 4 divs per speices to display attributes
document.getElementById("A"+String(count)).innerhtml = speciesA.attributes[attr];
count++;// used to specify divs ie A1 = attribute1, A2 = attribute2 etc
}
So I guess my main question is will this work/do what I think it does?
If needed I can pastebin my html and full js files.
What you have should work, but it can be written a bit cleaner. I would suggest this:
var tree = {
leaf1: {attributes: ["Attr1", "Attr2"]}
};
var attributes = tree.leaf1.attributes;
for (var i = 0; i < attributes.length; i++) {
document.getElementById("A"+(i+1)).innerHTML = attributes[i];
}
Things I changed:
Used a javascript literal to make the definition a lot more compact
Used {} and [] for defining arrays and objects rather than new Object() and new Array().
Used for (var i = 0; i < xxx.length; i++) syntax to iterate array elements only, not all properties. This is the "safe" way to iterate elements of an array.
Remove the String(count) as it is not needed. Javascript will auto-convert a number to a string when adding to another string.
Cached the value of the attributes array to save having to deep reference it each time.
Removed separate count variable as the for index can be used
To answer one of your other questions, when you do this:
tree.leaf1 = speciesA;
you have assigned a "reference" to speciesA to tree.left1. A reference is like a pointer. It is not a copy. So, the both refer to exactly the same object. Any change you make to speciesA or to tree.leaf1 is make a change to the exact same object.
So, when you then do this:
//Not sure if this next line assigns to speciesA or what exactly happens
tree.leaf1.attributes = new Array("Attr1","Attr2",etc);
you are indeed modifying the speciesA object since speciesA and tree.leaf1 point to the same object.
In javascript, arrays, objects and strings are assigned by reference. That means that when you assign one to a variable, it just points to the original object. A copy is not made. So, change the object via either either one will change the other (since they both point to the same object). Strings are immutable (a string is never actually changed). Things that feel like modifications to a string always just return a new string so this aspect of javascript doesn't affect strings so much. But, it is very important to know that arrays and objects are assigned by reference.
This question already has answers here:
How can I create a two dimensional array in JavaScript?
(56 answers)
Closed 9 years ago.
I use no add in libraries so what i'm looking for is a pure JavaScript solution.
This is not a duplicate of the thread offered. I want this thread opened up as the people that locked it didn't completely read what I was looking for. Offering some trivial function to initialize a dense array is NOT what I'm after. Read what I wrote.
I'm looking for a constructor, not some function that operates on an array of a known dimension. I'm looking for something that "just happens" when a multidimensional array is touched, and that something has to be an honest to goodness constructor that runs in the "background"to create the array elements on demand with no effort on the part of the programmer in the "foreground".
Correct me if I'm wrong, but when using a two dimensional array, one must first initialize the second dimension before attempting to use it.
It would be something like:
myArray[123] = [];
myArray[123][456] = 'Hi';
Is there some way to create a constructor to do that extra initialization automatically that wouldn't trash the existing functionality for a 1D array?
Alternatively, is there a way to create a new 2DArray object that will automatically allow one to use both dimensions with no prep work?
When the application has no foreknowledge of what the subscripts can be is when this issue becomes problematic.
See that question: Is there a more concise way to initialize empty multidimensional arrays?
Solution:
function createArray(length) {
var arr = new Array(length || 0),
i = length;
if (arguments.length > 1) {
var args = Array.prototype.slice.call(arguments, 1);
while(i--) arr[i] = createArray.apply(this, args);
}
return arr;
}
Simply call with an argument for the length of each dimension. Usage examples:
var multiArray = createArray(100,100); Gives a 2-dimensional array of size 100x100
Before fully defining my question, I must say that >>this question/answer<< doesn't answer my problem, and I have proven it to myself that the given answer doesn't match at all with the actual effect of property vs. variable or cached property (see below).
I have been using HTML5 canvas, and I write raw pixel blocks many times in a second in a 640x480 area.
As advised by some tutorials, it is good to cache the .data property of an ImageData variable (in this case, it would be _SCimgData).
If I cache that property in SC_IMG_DATA, I can putImageData repeatedly in the Canvas with no problem; but if I repeatedly access it directly with _ScimgData.data, the slow-down of the code is noticieable (taking nearly 1 second to fill a single 640x480 Canvas):
var SomeCanvas = document.getElementById("SomeCanvas");
var SCContext = SomeCanvas.getContext("2d");
var _SCimgData = SomeCanvas.getImageData(0, 0, 640, 400);
var SC_IMG_DATA = _SCimgData.data;
Now I have the following doubt:
Would my code be as slow for other kinds of similar accesses?
I need an array of objects for a set of functions that can have several "instances" of an object (created by a regular utility function), and that need the index of the instance in an array of objects, either to create/initialize it, or to update its properties.
My concrete example is this:
var objArray=new Array();
var objArray[0]=new Object();
objArray[0].property1="some string property";
for(var x=0; x<65536; x++)
doSomething(objArray[0].property1, objIDX=0);
Would that code become as unacceptably slow as in the Canvas case, if the properties and functions contained in some properties are called very intensively (several times in a single milisecond, of course using setInterval and several "timer threads" to avoid locking the browser)?
If so, what other alternative is there to speed up access for the different properties of several objects in the main object array?
EDIT 1 (2012-08-27)
Thanks for the suggestions. I have up-voted them since I suspect they will be useful for the project I'm working on.
I am thinking in a combination of methods, using mainly Arrays instead of Objects to build an actual array of "base objects", and addressing array elements by numbers (arr[0]) instead of string array keys (arr["zero"]).
var OBJECTS_SIZE=10
var Obj_Instances=new Array();
Obj_Instances[0]="property or array 1 of Object 0";
Obj_Instances[1]=new Array();
Obj_Instances[1][0]=new ArrayBuffer(128);
Obj_Instances[1][1]=new DataView(Obj_Instances[1][0]);
Obj_Instances[2]="property or array 3 of Object 0";
Obj_Instances[3]=function(){alert("some function here")};
Obj_Instances[4]="property or array 5 of Object 0";
Obj_Instances[5]="property or array 6 of Object 0";
Obj_Instances[6]=3;
Obj_Instances[7]="property or array 8 of Object 0";
Obj_Instances[8]="property or array 9 of Object 0";
Obj_Instances[9]="property or array 10 of Object 0";
Obj_Instances[10]="property or array 1 of Object 1";
Obj_Instances[11]=new Array();
Obj_Instances[11][0]=new ArrayBuffer(128);
Obj_Instances[11][1]=new DataView(Obj_Instances[11][0]);
Obj_Instances[12]="property or array 3 of Object 1";
Obj_Instances[13]=function(){alert("some function there")};
Obj_Instances[14]="property or array 5 of Object 1";
Obj_Instances[15]="property or array 6 of Object 1";
Obj_Instances[16]=3;
Obj_Instances[17]="property or array 8 of Object 1";
Obj_Instances[18]="property or array 9 of Object 1";
Obj_Instances[19]="property or array 10 of Object 1";
function do_Something_To_Property_Number_6(objIdx)
{
//Fix the index to locate the base address
//of the object instance:
///
objIdx=(objIdx*OBJECTS_SIZE);
Obj_instances[objIdx+6]++; //Point to "Property" 6 of that object
}
I would have, say an "instance" of an "object" that takes up the first 10 array elements; the next "instance" would take the next 10 array elements, and so on (creating the initialization in a custom "constructor" function to add the new block of array elements).
I will also try to use jsPerf and JSHint to see which combination result better.
To answer your "doubts", I suggest using JSPerf to benchmark your code. One can't really tell by code alone if the procedure is faster than another unless tested.
Also, I suggest you use the literal notation for arrays and objects instead of the new notation during construction:
var objArray=[
{
property : 'some string property'
}, {
...
},
];
Also, based on your code, it's better to have this since you are using the same object per iteration:
var obj = objArray[0].property1,
objIDX = 0;
for(var x=0; x<65536; x++){
doSomething(obj,objIDX);
}
I realise this is not quite answering your question (as it has already been answered), however as you seem to be looking for speed improvements in regard to function calls that happen thousands of times (as others who find this might also be doing). I thought I'd include this here as it goes against assumptions:
An example function:
var go = function (a,b,c,d,e,f,g,h) {
return a+b+c+d+e+f+g+h;
}
The following is how you would normally call a repetitive function:
var i=500000; while(i--){
go(1,2,3,4,5,6,7,8);
}
However, if none (or a few) of those arguments ever change for this particular usage of the function, then it's far better to do this (from a speed pov - obviously not an asynchronous pov):
var i=500000; go.args = [1,2,3,4,5,6,7,8];
while(i--){
go();
}
In order for the above to work you only need a slight modification to the original function:
var go = function (a,b,c,d,e,f,g,h, i) {
if ( go.args ) {
i = go.args;
a = i[0]; b = i[1];
c = i[2]; d = i[3];
e = i[4]; f = i[5];
g = i[6]; h = i[7];
}
return a+b+c+d+e+f+g+h;
}
This second function runs significantly faster because you are not passing in any arguments (a function called with no args is very quick to initiate). Pulling the values from the .args array doesn't seem to be that costly either (unless you involve strings). Even if you update one or two of the args it's still far faster, which makes it perfect for pixel or imagedata manipulations because you are normally only shifting x & y:
var i=500000; go.args = [1,2,3,4,5,6,7,8];
while(i--){
go.args[2] = i;
go();
}
So in a way this is an example of where an object property can be faster than local vars - if a little convoluted and off topic ;)
Possible browser optimizations notwithstanding, accessing a property of an object is more expensive than accessing a local variable (but not necessarily a global variable or a variable of a parent function).
The deeper the property, the more of a performance hit you take. In other words,
for(var x=0; x<65536; x++)
doSomething(objArray[0].property1, objIDX=0);
would be improved by caching objArray[0].property1, and not repeatedly assigning to objIDX:
var prop = objArray[0].property1;
objIDX = 0;
for(var x=0; x<65536; x++)
doSomething(prop, 0);