Default value for object - javascript

I am using the Canvas 2d context to write text to the screen..
To accomplish this I have it run through an array of text objects that I created, right now I have the text objects with 3 properties:
text.text
text.x
text.y
text.text holds the string to write, text.x holds the value for the x position, and text.y holds the value for the y position
Is there anyway I could skip the text.text property?
so for example, right now it looks something like this:
var textStrings = [];
textStrings[0] = {};
textStrings[0].text = "hello";
textStrings[0].x = 0;
textStrings[0].y = 10;
textStrings[1] = {};
textStrings[1].text = "world";
textStrings[1].x = 10;
textStrings[1].y = 10;
But is there any way that I could do something like this instead:
textStrings = [];
textStrings[0] = {};
textStrings[0] = "hello";
textStrings[0].x = "0";
textStrings[0].y = 10;
textStrings[1] = {};
textStrings[1] = "world";
textStrings[1].x = 10;
textStrings[1].y = 10;
basically a default property of an object or something...
right now as soon as I do something like
textStrings[0] = "hello";
it changes textStrings to a string instead of an object, and then I can no longer add properties to it, since its a primitive data type.
Thanks

You can use String objects instead of primitive values:
var a = new String("hello");
a.x = "0";
a.y = 10;
var b = new String("world");
b.x = "10";
b.y = 10;
var textStrings = [a, b];
You might also use special objects. The toString method is automatically used when the object is to be converted to a string:
function Text(t, x, y) {
this.text = t; this.x = x; this.y = y;
}
Text.prototype.toString = function() { return this.text; }
alert(new Text("hello", 0, 0)); // implicit string conversion
console.log(""+new Text("world", 10, 10)); // explicit string conversion
I guess you would have such a constructor function anyway, to simplify the syntax for the textStrings array.

If your text strings are guaranteed to be unique, you could use them for indexing:
var textStrings = {};
textStrings["world"].x = 10;
textStrings["world"].y = 10;
and then you could get a list of your "text" strings (so that you can index through your object) using the following snippet:
textkeys : function (textStrings) {
var accumulator = [];
for (var propertyName in o) {
arr.push(propertyName);
}
return accumulator;
}
from snipplr

Similar to the idea of #Bergi, but using a functional approach for creating the objects:
var textCreator = function (text, x, y) {
var that = {};
that.text = text;
that.x = x;
that.y = y;
that.toString = function () {
return text;
}
return that;
};
textStrings = [];
textStrings[0] = textCreator("hello", 0 ,10);
textStrings[1] = textCreator("world", 10, 10);
And just for completeness: you could extend the String prototype, but that is not advisable, and is practically the same as one of the solutions provided by Bergi.
String.prototype.x = null;
String.prototype.y = null;
textStrings = [];
//textStrings[0] = "hello";
textStrings[0] = new String("hello");
textStrings[0].x = "0";
textStrings[0].y = 10;
//textStrings[1] = "world";
textStrings[1] = new String("world");
textStrings[1].x = 10;
textStrings[1].y = 10;

Related

How to create array of objects from a function call?

Let a function createSquare with accepts arguments side, color which returns an object with properties same as the arguments.The values assigned to the properties should be the values assigned to the function.Other than these properties the object also has one method which return the area of square.Now create an array Box this array should contain the 3 objects which are created by calling createSquare function.And the objects should have the values[(3,black) ,(4,red) ,(5,green) ].
I have used ES5 javascript for this. The initial part I have used constructor to create the object like
function CreateBox(side, color) {
this.side = side;
this.color = color;
//function-1
areaOfSquare = function () {
let a = this.side * this.side;
console.log(a);
};
}
The Second part I am confused how to push the values of object into array.(this is how I thought of)
let box = [];
for (let i = 0; i < 3; i++) {
box[i].push(CreateBox(3, "black"));
}
In order to return an Object the function or class should be initialize the object by adding new keyword like new CreateBox() before the function/class call, example:
let box = [];
for (let i = 0; i < 3; i++) {
box[i].push(new CreateBox(3, "black")); // only thing missing the new keyword
}
//or
let array = [new CreateBox(3, "black"), new CreateBox(4, "yellow"), new CreateBox(5, "blue")]
// Define constructor like method
const CreateBox = (function () {
function CreateBox(side, color) {
this.side = side;
this.color = color;
}
CreateBox.prototype.area = function () {
return Math.pow(this.side, 2);
}
return CreateBox;
}());
// Add boxes into Array with new CreateBox(side, color);
let box = [];
for (let i = 0; i < 3; i++) {
box.push(new CreateBox(i + 1, "black"));
}
// Check the data
box.forEach(b => console.log(`side = ${b.side}, color = ${b.color}, area = ${b.area()}`));

JavaScript: generated object with multiple objects inside -> one object

this is how my object looks like:
, but I need just one object like
obj = {
var: "DB3,B0",
zahl: "DB3,Int2",
zahl2: "DB3,Int4",
...
...
};
How do I convert it?
I tried different things but it all won't work inside a for loop.
I generate my Object from a string with a code like this:
var text = msg.payload;
var nt = text.split(" ");
var n = nt.length;
var add = [];
var name = [];
var ab = [];
var variables = {};
for (var i = 0; i < n; i++) {
ab[i] = nt[i].split(";");
add[i] = ab[i][0];
name[i] = ab[i][1];
variables[i] = {[name[i]] : add[i]};
}
msg.payloadvars = variables;
return msg;
I think it should be quite simple but I don't come to any solution.
input looks like
DB3,B0;var DB3,Int2;zahl DB3,Int4;zahl2 DB3,Int6;zahl3 DB3,Int8;zahl4
DB3,Int10;zahl5 .....
You could split the string by groups and then for value and key.
var string = 'DB3,B0;var DB3,Int2;zahl DB3,Int4;zahl2 DB3,Int6;zahl3 DB3,Int8;zahl4 DB3,Int10;zahl5',
target = Object.assign(
...string.split(' ').map(s => (([v, k]) => ({ [k]: v }))(s.split(';')))
);
console.log(target);
Use Array.reduce
let str = "DB3,B0;var DB3,Int2;zahl DB3,Int4;zahl2 DB3,Int6;zahl3 DB3,Int8;zahl4 DB3,Int10;zahl5";
let obj = str.split(" ").reduce((a,c) => {
let v = c.split(";");
Object.assign(a, {[v[1]]: v[0]});
return a;
}, {});
console.log(obj);
if you want to make single object then you should try this:
var variables = {};
for (var i = 0; i < n; i++) {
ab[i] = nt[i].split(";");
add[i] = ab[i][0];
name[i] = ab[i][1];
variables[name[i]] = add[i];
}
console.log(variables);

How to do I unshift/shift single value and multiple values using custom methods?

I have prototypes to recreate how array methods work, pop/push/shift/etc, and I would like to extend the functionality to do the following:
Push/Pop/shift/unshift multiple values
array.push(0);
array.push(1);
array.push(2);
expect(array.pop()).to.be(2);
expect(array.pop()).to.be(1);
expect(array.pop()).to.be(0);
Push/Pop/unshift/etc single values
array.push(0);
array.push(1);
expect([0,1]);
array.pop(1);
expect([0]);
My assumption is that I would need a global array variable to store the elements. Is that the right?
Here is my code:
var mainArray = []; // array no longer destroyed after fn() runs
function YourArray(value) {
this.arr = mainArray; // looks to global for elements | function?
this.index = 0;
var l = mainArray.length;
if(this.arr === 'undefined')
mainArray += value; // add value if array is empty
else
for(var i = 0; i < l ; i++) // check array length
mainArray += mainArray[i] = value; // create array index & val
return this.arr;
}
YourArray.prototype.push = function( value ) {
this.arr[ this.index++ ] = value;
return this;
};
YourArray.prototype.pop = function( value ) {
this.arr[ this.index-- ] = value;
return this;
};
var arr = new YourArray();
arr.push(2);
console.log(mainArray);
My assumption is that I would need a global array variable to store
the elements. Is that the right?
No. That is not right.
You want each array object to have its own, independent set of data. Otherwise, how can you have multiple arrays in your program?
function YourArray(value) {
this.arr = []; // This is the data belonging to this instance.
this.index = 0;
if(typeof(value) != 'undefined')) {
this.arr = [value];
this.index = 1;
}
}
////////////////////////////////////
// Add prototype methods here
///////////////////////////////////
var array1 = new YourArray();
var array2 = new YourArray();
array1.push(2);
array1.push(4);
array2.push(3);
array2.push(9);
// Demonstrate that the values of one array
// are unaffected by the values of a different array
expect(array1.pop()).to.be(4);
expect(array2.pop()).to.be(9);
It's a bit late for this party, admitted but it nagged me. Is there no easy (for some larger values of "easy") way to do it in one global array?
The standard array functions work as in the following rough(!) sketch:
function AnotherArray() {
this.arr = [];
// points to end of array
this.index = 0;
if(arguments.length > 0) {
for(var i=0;i<arguments.length;i++){
// adapt if you want deep copies of objects
// and/or take a given array's elements as
// individual elements
this.arr[i] = arguments[i];
this.index++;
}
}
}
AnotherArray.prototype.push = function() {
// checks and balances ommitted
for(var i=0;i<arguments.length;i++){
this.arr[ this.index++ ] = arguments[i];
}
return this;
};
AnotherArray.prototype.pop = function() {
this.index--;
return this;
};
AnotherArray.prototype.unshift = function() {
// checks and balances ommitted
var tmp = [];
var alen = arguments.length;
for(var i=0;i<this.index;i++){
tmp[i] = this.arr[i];
}
for(var i=0;i<alen;i++){
this.arr[i] = arguments[i];
this.index++;
}
for(var i=0;i<tmp.length + alen;i++){
this.arr[i + alen] = tmp[i];
}
return this;
};
AnotherArray.prototype.shift = function() {
var tmp = [];
for(var i=1;i<this.index;i++){
tmp[i - 1] = this.arr[i];
}
this.arr = tmp;
this.index--;
return this;
};
AnotherArray.prototype.isAnotherArray = function() {
return true;
}
AnotherArray.prototype.clear = function() {
this.arr = [];
this.index = 0;
}
AnotherArray.prototype.fill = function(value,length) {
var len = 0;
if(arguments.length > 1)
len = length;
for(var i=0;i<this.index + len;i++){
this.arr[i] = value;
}
if(len != 0)
this.index += len;
return this;
}
// to simplify this example
AnotherArray.prototype.toString = function() {
var delimiter = arguments.length > 0 ? arguments[0] : ",";
var output = "";
for(var i=0;i<this.index;i++){
output += this.arr[i];
if(i < this.index - 1)
output += delimiter;
}
return output;
}
var yaa = new AnotherArray(1,2,3);
yaa.toString(); // 1,2,3
yaa.push(4,5,6).toString(); // 1,2,3,4,5,6
yaa.pop().toString(); // 1,2,3,4,5
yaa.unshift(-1,0).toString(); // -1,0,1,2,3,4,5
yaa.shift().toString(); // 0,1,2,3,4,5
var yaa2 = new AnotherArray();
yaa2.fill(1,10).toString(); // 1,1,1,1,1,1,1,1,1,1
Quite simple and forward and took only about 20 minutes to write (yes, I'm a slow typist). I would exchange the native JavaScript array in this.arr with a double-linked list if the content can be arbitrary JavaScript objects which would make shift and unshift a bit less memory hungry but that is obviously more complex and slower, too.
But to the main problem, the global array. If we want to use several individual chunks of the same array we need to have information about the starts and ends of the individual parts. Example:
var globalArray = [];
var globalIndex = [[0,0]];
function YetAnotherArry(){
// starts at the end of the last one
this.start = globalIndex[globalIndex.length-1][1];
this.index = this.start;
// position of the information in the global index
this.pos = globalIndex.length;
globalIndex[globalIndex.length] = [this.start,this.index];
}
So far, so well. We can handle the first array without any problems. We can even make a second one but the moment the first one wants to expand its array we get in trouble: there is no space for that. The start of the second array is the end of the first one, without any gap.
One simple solution is to use an array of arrays
globalArray = [
["first subarray"],
["second subarray"],
...
];
We can than reuse what we already wrote in that case
var globalArray = [];
function YetAnotherArray(){
// open a new array
globalArray[globalArray.length] = [];
// point to that array
this.arr = globalArray[globalArray.length - 1];
this.index = 0;
}
YetAnotherArray.prototype.push = function() {
for(var i=0;i<arguments.length;i++){
this.arr[ this.index++ ] = arguments[i];
}
return this;
};
// and so on
But for every new YetAnotherArray you add another array to the global array pool and every array you abandon is still there and uses memory. You need to manage your arrays and delete every YetAnotherArray you don't need anymore and you have to delete it fully to allow the GC to do its thing.
That will leave nothing but gaps in the global array. You can leave it as it is but if you want to use and delete thousands you are left with a very sparse global array at the end. Or you can clean up. Problem:
var globalArray = [];
function YetAnotherArray(){
// add a new subarray to the end of the global array
globalArray[globalArray.length] = [];
this.arr = globalArray[globalArray.length - 1];
this.index = 0;
this.pos = globalArray.length - 1;
}
YetAnotherArray.prototype.push = function() {
for(var i=0;i<arguments.length;i++){
this.arr[ this.index++ ] = arguments[i];
}
return this;
};
YetAnotherArray.prototype.toString = function() {
var delimiter = arguments.length > 0 ? arguments[0] : ",";
var output = "";
for(var i=0;i<this.index;i++){
output += this.arr[i];
if(i < this.index - 1)
output += delimiter;
}
return output;
}
// we need a method to delete an instance
YetAnotherArray.prototype.clear = function() {
globalArray[this.pos] = null;
this.arr = null;
this.index = null;
};
YetAnotherArray.delete = function(arr){
arr.clear();
delete(arr);
};
// probably won't work, just a hint in case of asynch. use
var mutex = false;
YetAnotherArray.gc = function() {
var glen, indexof, next_index, sub_len;
indexof = function(arr,start){
for(var i = start;i<arr.length;i++){
if (arr[i] == null || arr[i] == undefined)
return i;
}
return -1;
};
mutex = true;
glen = globalArray.length;
sublen = 0;
for(var i = 0;i<glen;i++){
if(globalArray[i] == null || globalArray[i] == undefined){
next_index = indexof(globalArray,i);
if(next_index == -1){
break;
}
else {
globalArray[i] = globalArray[next_index + 1];
globalArray[next_index + 1] = null;
sublen++;
}
}
}
globalArray.length -= sublen - 1;
mutex = false;
};
var yaa_1 = new YetAnotherArray();
var yaa_2 = new YetAnotherArray();
var yaa_3 = new YetAnotherArray();
var yaa_4 = new YetAnotherArray();
yaa_1.push(1,2,3,4,5,6,7,8,9).toString(); // 1,2,3,4,5,6,7,8,9
yaa_2.push(11,12,13,14,15,16).toString(); // 11,12,13,14,15,16
yaa_3.push(21,22,23,24,25,26,27,28,29).toString();// 21,22,23,24,25,26,27,28,29
yaa_4.push(311,312,313,314,315,316).toString(); // 311,312,313,314,315,316
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
11,12,13,14,15,16
21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/
YetAnotherArray.delete(yaa_2);
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/
YetAnotherArray.gc();
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
21,22,23,24,25,26,27,28,29
311,312,313,314,315,316
*/
But, as you might have guessed already: it doesn't work.
YetAnotherArray.delete(yaa_3); // yaa_3 was 21,22,23,24,25,26,27,28,29
globalArray.join("\n");
/*
1,2,3,4,5,6,7,8,9
21,22,23,24,25,26,27,28,29
*/
We would need another array to keep all positions. Actual implementation as an exercise for the reader but if you want to implement a JavaScript like array, that is for arbitrary content you really, really, really should use a doubly-linked list. Or a b-tree. A b+-tree maybe?
Oh, btw: yes, you can do it quite easily with a {key:value} object, but that would have squeezed all the fun out of the job, wouldn't it? ;-)

Swapping two properties of objects with function in javascript

I am trying to write a function that will take two objects, people in this case, and swap only two of their attributes. Here is my function for the Person:
function Person (tall, weight, gender, iq, favoriteColor) {
this.tall = tall;
this.weight = weight;
this.gender = gender;
this.iq = iq;
this.favoriteColor = favoriteColor;
}
var joe = new Person("6-2", 180, "male", 130, "blue");
var bob = new Person("5-11", 150, "male", 120, "red");
So i want to swap JUST their IQs and favoriteColor.
So far I have:
function Swap(a, b) {
var i = a;
a = b;
b = i;
console.log(a, b);
}
This obviously swaps all their properties, but i cannot figure out how to swap just two and still have them log as objects. I have tried:
function Swap(a, b) {
var a = a.iq + a.favoriteColor;
var b = b.iq + b.favoriteColor;
var i = a;
a = b;
b = i;
console.log(a, b);
}
but this returns in the console:
120red 130blue.
Technically it swapped the two values, but their structure as an object is gone and the other three properties that they were supposed to keep of their own are also gone. How do I write the swap function to do this?
Thanks!
This is what you want. You need to swap the individual fields. You can't add them like you are doing. Also, it's best not to use the same name for variables that you've already declared, it's just too confusing.
function Swap(a, b) {
var i = a.iq;
a.iq = b.iq;
b.iq = i;
i = a.favoriteColor;
a.favoriteColor= b.favoriteColor;
b.favoriteColor = i;
console.log(a, b);
}
function Swap(a, b) {
var newBIq = a.iq
var newBColor = a.favoriteColor;
var newAIq = b.iq
var newAColor = b.favoriteColor;
a.iq = newAIq;
a.favoriteColor = newAColor;
b.iq = newBIq;
b.favoriteColor = newBColor
console.log(a, b);
}
Here you see the 4 values needed. I hope the naming helps understanding better than just i,j :D
If we take this solution to swap values...
b = [a, a = b][0];
...we could do this...
function Swap(a, b) {
b.iq = [a.iq, a.iq = b.iq][0];
b.favoriteColor = [a.favoriteColor, a.favoriteColor = b.favoriteColor][0];
}
and if you can use ECMAScript 6, you could even do
function Swap(a, b) {
[a.iq, b.iq] = [b.iq, a.iq]
[a.favoriteColor, b.favoriteColor] = [b.favoriteColor, a.favoriteColor]
}
This will swap all the values for the keys in an array of keys between objects a and b:
function Swap(a,b, keys){
for(var i=0; i<keys.length; i++){
var currentKey = keys[i];
var temp = a[currentKey];
a[currentKey] = b[currentKey];
b[currentKey] = temp;
}
}

How to parse bracket tag on Javascript

I have tag like this, how the best way to get every key and value of those attribute and populate it within an array (number of attribute will be increasing)?
myData = '[data attr1="value1" attr2="value2" attr3="value3"]';
and get result array :
var arr = new Array();
arr['attr1'] = "value1";
arr['attr2'] = "value2";
arr['attr3'] = "value3";
and so on...
This probably does what you want, though it assumes that tag is already in the format you have described, i.e. a singular occurrence of [data ... ].
Also, the regular expression is purely based on what I've seen in your question; not sure whether it will break on other strings.
function decode(tag)
{
var r = /(\w+)="([^"]*)"/g,
h = {};
while ((m = r.exec(tag)) !== null) {
h[m[1]] = m[2];
}
return h;
}
Since you have string key in the data, use jquery object instead of array.
var arr = {};
var str = '[data attr1="value1" attr2="value2" attr3="value3"]​​​';
var n = str.split('[data ');
var str_arr = n[1].replace(']','').split(" ");
jQuery.each(str_arr,function(val){
var x = str_arr[val].split('=');
arr[x[0]] = x[1].replace('"','').slice(0,-1);
});
console.log(arr);
Try this code. It may help you.
Here is the DEMO
Though it can be more optimized if you put some more details about your code.
var tagRe = /\[(\w+)((?:\s+\w+="[^"]{0,50}")*)\s*]/g;
var attrRe = /\b(\w+)="([^"]*)"/g;
function parse(text) {
var result = [];
tagRe.lastIndex = 0; // reset start position
var tagMatch = tagRe.exec(text);
while (tagMatch) {
var currentTag = { 'name': tagMatch[1], 'attrs': {} };
var attrString = tagMatch[2];
attrRe.lastIndex = 0;
var attrMatch = attrRe.exec(attrString);
while (attrMatch) {
var attrName = attrMatch[1];
var attrValue = attrMatch[2];
currentTag.attrs[attrName] = attrValue;
attrMatch = attrRe.exec(attrString); // next match
}
result.push(currentTag);
tagMatch = tagRe.exec(text);
}
return result;
}
parse('[data attr1="value1" attr2="value2" attr3="value3"]');
> [{name:'data',attrs:{attr1:'value1',attr2:'value2',attr3:'value3'}}]
This works for any number of tags in the string. The name of the tag does not matter.

Categories

Resources