Using Javascript, I wrote this code to create an object:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
Now, i'm interested in printing each property & its value so i wrote this code:
for (let eachEle in employee){
if(typeof eachEle=='string' || typeof eachEle=='number'){
console.log(eachEle + ":" + employee[eachEle]);
}
else if(typeof eachEle=='function'){
console.log(eachEle + ":" + employee.eachEle());
}
}
But, on executing, it works fine except for "emp_fullname" & "emp_bonus". Instead of showing the value, it shows me the function:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function() {
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal: "QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary: 13579,
emp_bonus: function() {
return (this.emp_salary * 1);
}
};
for (let eachEle in employee) {
if (typeof eachEle == 'string' || typeof eachEle == 'number') {
console.log(eachEle + ":" + employee[eachEle]);
} else if (typeof eachEle == 'function') {
console.log(eachEle + ":" + employee.eachEle());
}
}
How am I supposed to retrieve the value for those two properties? I'm looking for answers using which I can modify the for...in loop & retrieve the value.
How am i supposed to retrieve the value for those two properties?
The function is the value of those properties. If you want to get the return value of the function, you have to call it.
Note that the typeof check you're doing in your for-in loop is unnecessary. The eachEle variable is the property name, not the property value. In a for-in loop, the name will always be a string. (Not all properties are named with strings, but for-in only covers the ones that are.)
You want to get the value of the property, check if it's a function, and if so call it:
for (let name in employee){
let value = employee[name];
if (typeof value === "function") {
value = employee[name]();
}
console.log(name + ":" + value);
}
Live Example:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let name in employee){
let value = employee[name];
if (typeof value === "function") {
value = employee[name]();
}
console.log(name + ":" + value);
}
You said you just wnated to change the loop, but another approach is to change the object definition to use an accessor property rather than an explicit function:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
get emp_fullname() {
// ^^^ ^^
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
get emp_bonus() {
// ^^^ ^^
return (this.emp_salary*1);
}
};
Then the loop doesn't have to check:
for (let name in employee){
console.log(name + ":" + employee[name]);
}
Live Example:
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
get emp_fullname() {
// ^^^ ^^
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
get emp_bonus() {
// ^^^ ^^
return (this.emp_salary*1);
}
};
for (let name in employee){
console.log(name + ":" + employee[name]);
}
That works because when you get the value of an accessor property, its accessor function is run behind the scenes and that function's return value is provided as the property value.
You need to check the type of value, eachEle is value of key which for your object is always string.
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function() {
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal: "QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary: 13579,
emp_bonus: function() {
return (this.emp_salary * 1);
}
};
for (let eachEle in employee) {
if (typeof employee[eachEle] == 'string' || typeof employee[eachEle] == 'number') {
console.log(eachEle + ":" + employee[eachEle]);
} else if (typeof employee[eachEle] == 'function') {
console.log(eachEle + ":" + employee[eachEle]());
}
}
Two things you need to change
You need to check for the value of element for string, number and function and not the key
While executing the function you need to use the brackets notation since its a dynamic key
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let key in employee){
let eachEle = employee[key];
if(typeof eachEle=='string' || typeof eachEle=='number'){
console.log(key + ":" + employee[key]);
}
else if(typeof eachEle=='function'){
console.log(key + ":" + employee[key]());
}
}
Your mistakes are:
1. You wrote: typeof eachEle insted of: typeof employee[eachEle]:
2. The execute is: employee.eachEle() insted of employee[eachEle](). eachEle is a string.
let employee = {
emp_firstname: "Prasanta",
emp_lastname: "Banerjee",
emp_fullname: function(){
return (this.emp_firstname + " " + this.emp_lastname);
},
emp_id: 673630,
emp_horizontal:"QEA",
emp_vertical: "Insurance",
joining_date: "22/12/2017",
emp_salary : 13579,
emp_bonus : function(){
return (this.emp_salary*1);
}
};
for (let eachEle in employee){debugger
if(typeof employee[eachEle]=='string' || typeof employee[eachEle]=='number'){
console.log(eachEle + ":" + employee[eachEle]);
}
else if(typeof employee[eachEle]=='function'){
console.log(eachEle + ":" + employee[eachEle]());
}
}
In your for loop, you iterate over the keys in the object, and those will never be objects. Instead, you should retrieve the item before checking its type.
for(let key in employee){
let value = employee[key];
if(typeof value=='string' || typeof vlaue=='number'){
console.log(key + ":" + value);
}
else if(typeof value=='function'){
console.log(key + ":" + value());
}
}
Related
I have a popup on a website that displays values from a geoJSON file. Right now, it looks as in the picture below:
This is the current code:
function popUp_cc_210303(f, l) {
var out = [];
if (f.properties) {
var url =
'<a href=/uas_tools/crop_analysis/index.php?crop=Wheat&year=2021&location=Amarillo&sublocation=Irrigation';
var parameters = '';
for (key in f.properties) {
out.push(key + ': ' + f.properties[key]);
parameters += '&' + key.replace(/\ /g, '_') + '=' + f.properties[key];
}
url +=
parameters.replace(/\ /g, '%20') + " target='_blank'>Growth analysis</a>";
out.push(url);
var url2 =
'<a href=/uas_tools/variety_analysis/index.php?crop=Wheat&year=2021&location=Amarillo&sublocation=Irrigation';
url2 += " target='_blank'>Variety analysis</a>";
out.push(url2);
l.bindPopup(out.join('<br />'));
}
}
I am trying to use out.push(key+": "+f.properties[key].toFixed(2)); but it does not work.
This is the geoJSON file structure
{ "type": "Feature", "properties": { "Row name": "row-1", "Col": "1", "plot_num": "?436", "plot_name": "?AOBS", "join_key": "?AOBS?436", "CC201014": 0.0, "CC201104": 0.0016344676538850001, "CC201120": 0.56401258728343395, "CC201217": 8.3524346613304221, "CC210113": 7.7746312091202094, "CC210224": 9.7393145428079926, "CC210303": 7.673018393542411, "CC210311": 14.576431943872961, "CC210323": 31.081778483525209, "CC210331": 30.067189249720045, "CC210408": 62.738628486108894, "CC210412": 63.94711538461538, "CC210418": 73.721694264987974, "CC210423": 70.039654826897262, "CC210430": 98.045130406889243, "CC210504": 91.969625530436502, "CC210510": 93.321666364934728, "CC210517": 85.521939491083955, "CC210525": 88.782478347768162, "CC210601": 95.859434682964093, "CC210607": 15.974798327739503, "CC210610": 0.0085470085470090006, "CC210614": 0.0, "CC210617": 0.0 }
The toFixed() method only works on floats, it appears you may have a string. You could parse it to a float first.
out.push(key + ': ' + parseFloat(f.properties[key]).toFixed(2));
One-liners are not your friend. JavaScript has its own ideas about priority. To force "order of operation", use parenthesis around any important group. Even then, code editors may format, prettify, or remove the parenthesis. Good luck finding the error then! It is best to isolate any complex operation in a named variable. A named variable is more descriptive and easier to read and reuse.
Seems like the code is calling toFixed on all values, even if the value is a string.
for (key in f.properties) {
//The first few prperties are strings, this is throwing an error as String.prototype.toFixed is not defined, so you can't call it.
out.push(key + ': ' + parseFloat(f.properties[key]).toFixed(2));
parameters += '&' + key.replace(/\ /g, '_') + '=' + f.properties[key];
}
Try this instead
for (var key in f.properties) {//include var to not add key to global scope
var val = f.properties[key]
if (typeof val === "number") {val = val.toFixed(2)}
out.push(key + ': ' + val);
parameters += '&' + key.replace(/\ /g, '_') + '=' + val;
}
Also, as noted in other answers, the values with floates might still be strings, if this is the case, you could try:
for (var key in f.properties) {//include var to not add key to global scope
var val = f.properties[key]
if (Number.isNaN(Number(val))) val = Number(val).toFixed(2)
out.push(key + ': ' + val);
parameters += '&' + key.replace(/\ /g, '_') + '=' + val;
}
You could also use the Array.reduce() method:
var out = Object.keys(f.properties)
.reduce((a, c) => (typeof f.properties[c] === `number` ?
a.push(`${c}: ${f.properties[c].toFixed(2)}`) :
a.push(`${c.replace(/\s/, `_`).toLowerCase()}: ${f.properties[c]}`), a), [])
const f = {
"type": "Feature",
"properties": {
"Row name": "row-1",
"Col": "1",
"plot_num": "?436",
"plot_name": "?AOBS",
"join_key": "?AOBS?436",
"CC201014": 0.0,
"CC201104": 0.0016344676538850001,
"CC201120": 0.56401258728343395,
"CC201217": 8.3524346613304221,
"CC210113": 7.7746312091202094,
"CC210224": 9.7393145428079926,
"CC210303": 7.673018393542411,
"CC210311": 14.576431943872961,
"CC210323": 31.081778483525209,
"CC210331": 30.067189249720045,
"CC210408": 62.738628486108894,
"CC210412": 63.94711538461538,
"CC210418": 73.721694264987974,
"CC210423": 70.039654826897262,
"CC210430": 98.045130406889243,
"CC210504": 91.969625530436502,
"CC210510": 93.321666364934728,
"CC210517": 85.521939491083955,
"CC210525": 88.782478347768162,
"CC210601": 95.859434682964093,
"CC210607": 15.974798327739503,
"CC210610": 0.0085470085470090006,
"CC210614": 0.0,
"CC210617": 0.0
}
};
const urls = [
`/uas_tools/crop_analysis/index.php`,
`/uas_tools/variety_analysis/index.php`
];
const div = document.createElement('div');
Object.keys(f.properties)
.reduce((a, c) => (typeof f.properties[c] === `number` ?
a.push(`${c}: ${f.properties[c].toFixed(2)}`) :
a.push(`${c.replace(/\s/, `_`).toLowerCase()}: ${f.properties[c]}`), a), [])
.map(el => {
const br = document.createElement('br');
const span = document.createElement('span');
span.innerText = el;
div.appendChild(span).appendChild(br);
});
const parameters = {
crop: `Wheat`,
year: 2021,
location: `Amarillo`,
sublocation: `Irrigation`
};
urls.map(pathName => {
const url = new URL(pathName, window.location.origin);
Object.keys(parameters)
.map(elem => url.searchParams.set(elem, parameters[elem]));
const br = document.createElement('br');
const a = document.createElement('a');
a.href = url.toString();
a.target = `_blank`;
a.innerText = url.pathname
.split(`/`)
.slice(-2, -1)[0]
.split(`_`)
.map(el => el.charAt(0).toUpperCase() + el.substr(1).toLowerCase())
.join(` `);
div.appendChild(a).appendChild(br);
});
document.querySelector(`body`).appendChild(div);
body {
font-family: sans-serif;
font-size: 12px;
}
I would like to know why using for loop is not displaying a method when iterating the object.
Please check below example where method getFullList is not listed:
let list = {
firstElement: "Element 1",
secondElement: "Element 2",
thirdElement: "Element 3",
getFullList: function() {
return this.firstElement + ', ' + this.secondElement + ', ' + this.thirdElement;
}
};
for (let key in list) {
if (list.hasOwnProperty(key)) {
console.log(key + ' ' + list[key])
}
}
From your question, I guess you're expecting the function to actually be called.
To do so, you'd need to check the type of list[key] and actually call the function
const list = {
firstElement: "Element 1",
secondElement: "Element 2",
thirdElement: "Element 3",
getFullList: function() {
return this.firstElement + ', ' + this.secondElement + ', ' + this.thirdElement;
}
};
for (const key in list) {
if (list.hasOwnProperty(key)) {
const value = list[key];
console.log(key + " " + value);
if (typeof value === "function") {
value();
}
}
}
The console output when logging the function as the value of "getFullList" will be something like
ƒ () {
return this.firstElement + ', ' + this.secondElement + ', ' + this.thirdElement;
}
I am manipulating string to display in UI, Data is being dynamically with below code sometime i don't get header and details so how to make IHeader and IResponse optional for the string concatenation below.
if i dont have IHeader it will break at IHeader.id and throw exception i want to display whatever data is available to render.
main.js
const data = [{
id: "header",
name: "IHeader"
}, {
id: "param",
name: "IParams"
}, {
id: "details",
name: "IResponse"
}]
function buildText(data) {
var IParams;
var IResponse;
var IHeader;
for (var item of data) {
if (item.id === "param") {
IParams = item;
} else if (item.id === "header") {
IHeader = item;
} else if (item.id === "details") {
IResponse = item;
}
}
var text = '';
text += app + '.setConfig({\n' + "env:" + getEnv() + '\n});' + '\n\n';
text += 'let param:' + IParams.name + ' ' + '=' + '' + JSON.stringify(request, null, 4) + ';\n\n';
text += ref + '(' + 'param,(result:' + ' ' + '{' + '\n' + IHeader.id + ':' + IHeader.name + '\n' + IResponse.id + ':' + IResponse.name + '\n' + '})' + ' ' +
' => {\n console.log(result); \n});';
}
1 - You can try to create an object with empty values. That'll prevent the exception.
emptyObject = {id: ""} // more empty keys, if there is
IParam = (item.id === "param") ? item : emptyObject
2 - Or ignore that concatenation of the variable if undefined or null.
if (Iparam) {
// concatenation ..
}
I have just this array :
var sArray = {856:"users", 857:"avatars", 858:"emails"};
and I want to use forEach in a way to get key and value from that:
key = 856
value = user
My $.each code doesn't return the result I'm expecting, and I get instead:
856:user
I must be separate that with : to get key and value from this array.
My code is:
$.each(template_array, function(key, value) {
console.log("key: " + "value: " + value);
});
How to access key and value without separate?
Just take Object.keys for the keys and Array.prototype.forEach for the values in plain Javascript.
var sArray = { 856: 'users', 857: 'avatars', 858: 'emails'};
Object.keys(sArray).forEach(function (key) {
document.write('key: ' + key + ', value: ' + sArray[key] + '<br>');
});
Just concatenate them using +
var template_array = {
856: 'users',
857: 'avatars',
858: 'emails'
};
$.each(template_array, function(key, value) {
console.log('key:' + key + ', value:' + value);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
UPDATE :
I think you have an array then use the following code
var template_array = ['856: users',
'857: avatars',
'858: emails'
];
template_array.forEach(function(v) {
v = v.split(':');
console.log('key:' + v[0] + ', value:' + v[1]);
});
try this one
var template_array = {
856: 'users',
857: 'avatars',
858: 'emails'
};
var date = [];
$.each(template_array,function (key , val){
date.push({key:key, value:val})
});
console.log(date)
var template_array = {
856: 'users',
857: 'avatars',
858: 'emails'
};
for (key in template_array) {
console.log('key:' + key + ', value:' + template_array[key]);
});
This is basically something that makes zero logical sense, and I'm not sure why this is happening.
When you create a function to compare attribute values of an array of objects (essentially JSON object), it refuses to find the index. However, OUTSIDE the function, it seems to work perfectly fine.
However, the problem is
var peoples = [
{ "name": 44, "dinner": "pizza" },
{ "name": 65, "dinner": "sushi" },
{ "name": 33, "dinner": "hummus" }
];
var val = 33;
$("#t").append(get_index_of_array_based_on_value(peoples, val));
function get_index_of_array_based_on_value(array, val) {
$.each(array, function (index, obj) {
$.each(obj, function (attr, value) {
console.log(" attr: " + attr + " == " + value + " (" + val + ") {{" + index + "}} ");
if (value == val) {
return index;
}
});
});
}
http://jsfiddle.net/QStkd/2327/
The above does not work.
The below script does work.
http://jsfiddle.net/QStkd/2330/
The below script is simply the same script except outside the function. When you put stuff into functions it suddenly refuses to find the index based on the value.
You cannot return a value from a $.each call. You are inside a callback, your return doesn't affect the main function.
When you use return inside the $.each callback, it's similar to break/continue in a for/while loop. A falsy value will break the loop, and a truthy value is like calling continue.
You need to return from the main function, get_index_of_array_based_on_value, not from the $.each.
function get_index_of_array_based_on_value(array, val) {
var returnVal = null;
$.each(array, function (index, obj) {
$.each(obj, function (attr, value) {
console.log(" attr: " + attr + " == " + value + " (" + val + ") {{" + index + "}} ");
if (value == val) {
returnVal = index;
return false; // break;
}
});
if(returnVal !== null){
return false; // break the outer loop
}
});
return returnVal;
}
thy this
var peoples = [
{ "name": 44, "dinner": "pizza" },
{ "name": 65, "dinner": "sushi" },
{ "name": 33, "dinner": "hummus" }
];
var val = 33;
$("#t").append(get_index_of_array_based_on_value(peoples, val));
function get_index_of_array_based_on_value(array, val) {
for(var index = 0; index < array.length; index++){
for(var attr in array[index]) {
var value = array[index][attr];
console.log(" attr: " + attr + " == " + value + " (" + val + ") {{" + index + "}} ");
if (value == val) {
return index;
}
}
}
}