How can write these (working) functions using forEach() methods:
function loadAudioMeterHistory(cell) {
var peaks = new Array(4);
for (var i = 0; i < peaks.length; i++) {
var peak,
age;
peak = cell.getAttribute("data-peak-" + i);
age = cell.getAttribute("data-age-" + i);
peaks[i] = new Peak(peak, age);
}
return peaks;
}
function setAudioMeterHistory(cell, peaks) {
for (var i = 0; i < peaks.length; i++) {
cell.setAttribute("data-peak-" + i, peaks[i].peak);
cell.setAttribute("data-age-" + i, peaks[i].age);
}
}
My attempt was the following:
function loadAudioMeterHistory(cell) {
"use strict";
var peaks = new Array(4);
peaks.forEach(function(item, index) {
var p = cell.getAttribute("data-peak-" + index);
var a = cell.getAttribute("data-age-" + index);
item = new Peak(p, a);
});
return peaks;
}
function setAudioMeterHistory(cell, peaks) {
"use strict";
peaks.forEach(function(item, index) {
cell.setAttribute("data-peak-" + index, item.peak);
cell.setAttribute("data-age-" + index, item.age);
});
}
which, behaves differently, in that peaks is never properly created. The savvy javascripter will undoubtedly recognise that I'm attempting to jslint.com my code.
The Peak() method (for brevity's sake) is simply:
function Peak(peak, age) {
this.peak = peak;
this.age = age;
}
What gives?
forEach just iterates over a list but does not return anything. So use map instead and return the newly created object.
function loadAudioMeterHistory(cell) {
"use strict";
var peaks = [0, 1, 2, 3].map(function(item, index) {
var p = cell.getAttribute("data-peak-" + index);
var a = cell.getAttribute("data-age-" + index);
return new Peak(p, a);
});
}
One more problem is peaks is not available outside the scope of loadAudioMeterHistory. So have the function return that which can be passed into the next function call.
function loadAudioMeterHistory(cell) {
"use strict";
return [0, 1, 2, 3].map(function(item, index) {
var p = cell.getAttribute("data-peak-" + index);
var a = cell.getAttribute("data-age-" + index);
return new Peak(p, a);
});
}
function setAudioMeterHistory(cell) {
"use strict";
var peaks = loadAudioMeterHistory(cell);
peaks.forEach(function(item, index) {
cell.setAttribute("data-peak-" + index, item.peak);
cell.setAttribute("data-age-" + index, item.age);
});
}
You can use Array.from() whose second argument is a function to populate the array:
function loadAudioMeterHistory(cell) {
return Array.from({ length: 4 }, (_, i) => {
const peak = cell.getAttribute('data-peak-' + i);
const age = cell.getAttribute('data-age-' + i);
return new Peak(peak, age);
});
}
For the second function, use forEach() like this:
function setAudioMeterHistory(cell, peaks) {
peaks.forEach(({ peak, age }) => {
cell.setAttribute('date-peak-' + i, peak);
cell.setAttribute('data-age-' + i, age);
});
}
Related
I am getting familiar with the prototype world of JavaScript and this keyword. I am new to Web-world. Today when I started playing with prototype I saw some strange behavior but I am not able to get why this is happening. I've created a constructor Group as following:
// Code goes here
function Group(config) {
this.config = config;
this.getId = function() {
return this.config.id;
};
this.setId = function(id) {
this.config.id = id;
};
}
I use it in one MyGroup constructor like this:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(MyGroup, this.g, myAttrs)
}
addGetterSetter is the function I wrote to add getter and setter dynamically to the attributes of MyGroup.
var GET = 'get',
SET = 'set';
function capitalize(str) {
return str.charAt(0).toUpperCase() + str.slice(1);
}
function addGetterSetter(constructor, target, attrs) {
function addGetter(constructor, target, attr) {
var method = GET + capitalize(attr);
constructor.prototype[method] = function() {
return target[method]();
};
}
function addSetter(constructor, target, attr) {
var method = SET + capitalize(attr);
constructor.prototype[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(constructor, target, attrs[index]);
addSetter(constructor, target, attrs[index]);
}
}
Now when I use MyGroup,Group like this:
var items = [{
id: 123,
name: 'Abc'
}, {
id: 131,
name: 'Bca'
}, {
id: 22,
name: 'bc'
}];
var groups = [];
items.forEach(function(item) {
var g = new MyGroup(item);
groups.push(g);
});
groups.forEach(function(g) {
console.log(g.getId()); //don't know why this logs 22 three times instead of all ids
});
In group.forEach I don't know why the id of the last item is getting logged. I am not able to understand what is going wrong. And how will I be able to get of the group for which g.getId() is invoked. Here is the plunkr
It's because you're adding methods to prototype and you overwrite in the loop each time the previous function so the function hold reference to last object when forEach loop finishes. What you need is to add function to this object:
function MyGroup(config) {
var myAttrs = ['id', 'name'];
this.g = new Group(config);
addGetterSetter(this, this.g, myAttrs)
}
function addGetterSetter(object, target, attrs) {
function addGetter(object, target, attr) {
var method = GET + capitalize(attr);
object[method] = function() {
return target[method]();
};
}
function addSetter(object, target, attr) {
var method = SET + capitalize(attr);
object[method] = function(value) {
return target[method](value);
};
}
for (var index = 0; index < attrs.length; index++) {
addGetter(object, target, attrs[index]);
addSetter(object, target, attrs[index]);
}
}
JSFIDDLE
Ineed help with correct sorting in created object.
Object (in for loop):
var labelD = $("#crpc-page label[for='crpc-" + i + "-date']").text();
var valueD = $("#crpc-" + i + "-date").val();
var labelV = $("#crpc-page label[for='crpc-" + i + "-value']").text();
var valueV = $("#crpc-" + i + "-value").val();
console.log("i:" + labelD + " => " + valueD);
console.log("i:" + labelV + " => " + valueV);
dni = Date.parse(valueD);
var sortowanie = {};
var nr = "numer";
var dataD = "dataD";
var wartosc = "wartosc";
sortowanie[nr] = dni;
sortowanie[dataD] = valueD;
sortowanie[wartosc] = valueV;
all_dates.push(sortowanie);
Sorting function
function compare(a, b) {
if (a.numer < b.numer) return -1;
if (a.numer > b.numer) return 1;
return 0;
}
all_dates.sort(compare);
Second alternative sorting function:
function sortElement() {
all_dates.sort(function(a, b){
return a.numer-a.numer;
});
}
sortElement();
And now. My problem is that this function sorts only numer value not all objects inside { ... } .
Example
console returns:
[
{"numer":1428530400000,"dataD":"04/09/2015","wartosc":"3"},
{"numer":1441058400000,"dataD":"09/01/2015","wartosc":"1"},
{"numer":1441576800000,"dataD":"09/07/2015","wartosc":"2"}
]
I wish to recive:
[
{"numer":1441058400000,"dataD":"09/01/2015","wartosc":"1"},
{"numer":1441576800000,"dataD":"09/07/2015","wartosc":"2"},
{"numer":1428530400000,"dataD":"04/09/2015","wartosc":"3"}
]
My brain burns, and I dont know how to switch all elements inside {}
Thanks,
Fantazy
all_dates.sort(function(a,b){
return b.numer-a.numer;
});
It is working according to your need.
Your date parse does not work because it is not a US date.
Instead use
var parts = valueD.split("/");
dni = new Date(parts[2],parts[1]-1,parts[0]).getTime();
DEMO:
function compare(a, b) {
if (a.numer < b.numer) return -1;
if (a.numer > b.numer) return 1;
return 0;
}
function getEURTime(str) {
var parts = str.split("/");
return new Date(parts[2],parts[1]-1,parts[0]).getTime();
}
var EUR = [
{"dataD":"04/09/2015","wartosc":"3"},
{"dataD":"09/01/2015","wartosc":"1"},
{"dataD":"09/07/2015","wartosc":"2"}
]
for (var i=0;i<EUR.length;i++) {
EUR[i].numer=getEURTime(EUR[i].dataD);
}
console.log(EUR.sort(compare))
-----------------File1.html-------------------------
<body>
<div id="tooltip"></div>
<script src="lib/d3.js"></script>
<script src="lib/underscore.js"></script>
<script src="js/mapper.js"></script>
<script>
d3.json('data/readme.json', function (error, data) {
var mpr = chordMpr(data);
_.each(data, function (elem) {
mpr.addToMap(name(elem.name))
})
mpr.setFilter(function (row, a, b) {
/* alert(JSON.stringify(a) +"-------"+JSON.stringify(row)+"-------"+JSON.stringify(b));
alert(a.name + "--" + row.name + "--" + b.name); */
return (name(row.name) === a.name)
})
.setAccessor(function (recs, a, b) {
if (!recs[0]) return 0;
var n = 0;
_.each(recs, function (r) {
//alert(r.imports)
_.each(r.imports, function (i) {
// alert(JSON.stringify(b) + "----" + i);
if (name(i) === b.name) n++;
});
});
return n;
});
alert(/* "*****" + mpr.getMatrix() + "-----" + */ JSON.stringify(mpr.getMap()));
drawChords(mpr.getMatrix(), mpr.getMap());
});
function name(name) {
return name.substring(0, name.lastIndexOf(".")).substring(6);
}
---------------------------File1.html-----------------------------
------------------------------mapper.js---------------------------
//*******************************************************************
// CHORD MAPPER
//*******************************************************************
function chordMpr (data) {
alert(data + "kimi is faster than you");
var mpr = {}, mmap = {}, n = 0,
matrix = [], filter, accessor;
mpr.setFilter = function (fun) {
alert("inside filter");
filter = fun;
return this;
},
mpr.setAccessor = function (fun) {
accessor = fun;
return this;
},
mpr.getMatrix = function () {
matrix = [];
_.each(mmap, function (a) {
if (!matrix[a.id]) matrix[a.id] = [];
_.each(mmap, function (b) {
var recs = _.filter(data, function (row) {
return filter(row, a, b);
})
matrix[a.id][b.id] = accessor(recs, a, b);
});
});
return matrix;
},
mpr.getMap = function () {
return mmap;
},
mpr.printMatrix = function () {
_.each(matrix, function (elem) {
console.log(elem);
})
},
mpr.addToMap = function (value, info) {
if (!mmap[value]) {
mmap[value] = { name: value, id: n++, data: info }
}
},
mpr.addValuesToMap = function (varName, info) {
alert("inside addValuesToMap " + varName + info);
var values = _.uniq(_.pluck(data, varName));
alert(values);
//values is the list of countries in the importer[i] column in CSV form
_.map(values, function (v) {
//v is individual country in the importer[i] column
if (!mmap[v]) {
mmap[v] = { name: v, id: n++, data: info }
}
});
return this;
}
return mpr;
}
//*******************************************************************
// CHORD READER
//*******************************************************************
function chordRdr (matrix, mmap) {
return function (d) {
var i,j,s,t,g,m = {};
if (d.source) {
i = d.source.index; j = d.target.index;
s = _.where(mmap, {id: i });
t = _.where(mmap, {id: j });
m.sname = s[0].name;
m.sdata = d.source.value;
m.svalue = +d.source.value;
m.stotal = _.reduce(matrix[i], function (k, n) { return k + n }, 0);
m.tname = t[0].name;
m.tdata = d.target.value;
m.tvalue = +d.target.value;
m.ttotal = _.reduce(matrix[j], function (k, n) { return k + n }, 0);
} else {
g = _.where(mmap, {id: d.index });
m.gname = g[0].name;
m.gdata = g[0].data;
m.gvalue = d.value;
}
m.mtotal = _.reduce(matrix, function (m1, n1) {
return m1 + _.reduce(n1, function (m2, n2) { return m2 + n2}, 0);
}, 0);
return m;
}
}
I am having difficulty in analysing the code flow in the above code.
In the mpr.setFilter(function (row, a, b)) call, what are row, a and b? I can't find any variables by this name. Also how are the calls translating from one function to other.
Please help.
setFilter is a function which takes an argument of a function that is stored to a "member" variable filter. When the user calls setFilter and passes their function they must know the contract that it takes three arguments. These are your row, a, and b arguments, they aren't assigned here, just there to make the function match later on.
If you trace this a little further that anonymous function passed into setFilter and stored in the variable filter is then called in the getMatrix function in mapper.js. You'll see when it is called the arguments of row, a and b are passed in.
Ain't JavaScript fun?
I'm having trouble converting JSON to Javascript objects when the JSON data has nested objects. The top level 'Person' object gets recreated fine, but the 'Residence' object property does not
function Person(first, last) {
this.FirstName = first;
this.LastName = last;
this.Residence = {};
}
Person.Revive = function (data) {
return new Person(data.FirstName, data.LastName);
}
Object.defineProperty(Person.prototype, "FullName", {
get: function() { return this.FirstName + " " + this.LastName; }
});
Person.prototype.toJSON = function () {
this.__class__ = "Person";
return this;
});
function Residence(lat, long) {
this.Latitude = lat;
this.Longitude = long;
}
Residence.prototype.toJSON = function () {
this.__class__ = "Residence";
return this;
}
Residence.Revive = function (data) {
return new Residence(data.Latitude, data.Longitude);
}
Object.defineProperty(Residence.prototype, "Location", {
get: function () { return this.Latitude + ", " + this.Longitude; }
});
var p = new Person("Foo", "Bar");
p.Residence = new Residence(44, 33);
console.log("Full name = " + p.FullName);
console.log("Location = " + p.Residence.Location);
var serialization = JSON.stringify(p);
console.log(serialization);
var rawObj = JSON.parse(serialization, function (key, value) {
if (value instanceof Object && value.__class__ == 'Person') {
return Person.Revive(value);
}
if (value instanceof Object && value.__class__ == 'Residence') {
return Residence.Revive(value);
}
return value;
});
console.log("Full name = " + rawObj.FullName);
console.log("Location = " + rawObj.Residence.Location);
The JSON.parse function does get a key/value pair for the 'Residence' object, and a new Residence object is created and returned. However, the resulting 'rawObj.Residence' is just an empty object. Can anyone point out what I'm doing wrong?
The console output is as follows:
Full name = Foo Bar
Location = 44, 33
{"FirstName":"Foo","LastName":"Bar","Age":22,"Residence":{"Latitude":44,"Longitude":33,"__class__":"Residence"},"__class__":"Person"}
Full name = Foo Bar
Location = undefined
Fiddle: http://jsfiddle.net/CadGuy/yyq4dqtx/
var p = new Person("Foo", "Bar");
p.Residence = new Residence(44, 33);
Well, if you are constructing your Person objects like that, you'll have to revive them like this as well:
Person.Revive = function (data) {
var p = new Person(data.FirstName, data.LastName);
p.Residence = data.Residence;
return p;
};
Of course, it might be a good idea to make the residence an (optional?) parameter to Person in the first place.
How to use the functionality of dictionary in JavaScript?
Look at this question the specified way is working, but I am setting the function instance as a key like this:
Scale = function ()
{
this.Collections = {};
this.IndexTracker = {};
this.UpdateIndex = function ()
{
var index = 0;
for ( var i = 0; i < this.Collections.length; i++ )
{
this.SetIndex( this.Collections[i], index++ );
}
}
this.SetIndex = function ( obj, value )
{
this.IndexTracker[obj] = value;
}
this.GetIndex = function ( obj, value )
{
return this.IndexTracker[obj];
}
}
this.Collections will hold the some function instance.
The problem here is the function instance is overwritten by the next function instance in this.Collections. The the length of the Collections always is 1. How to solve this?
This is an example:
var Scale = function () {
var _Collections = {},
_IndexTracker = {},
ret = function () {
function UpdateIndex() {
var index = 0,i,l;
for (i = 0,l=_Collections.length; i < l; i++) {
this.SetIndex(_Collections[i], index++);
}
}
function SetIndex(obj, value) {
_IndexTracker[obj] = value;
}
function GetIndex(obj, value) {
return _IndexTracker[obj];
}
return {
UpdateIndex : UpdateIndex,
SetIndex : SetIndex,
GetIndex : GetIndex
};
};
return ret;
}();