Unwanted undefined in the web page output [duplicate] - javascript

I have a function that concatenates together the results from an AJAX request.
For some reason, my final string starts with "undefined".
Here is a simplified example that reproduces the problem:
// In practice, fetched via AJAX from a server
var vendors = [{ id_vendor: 'V0001' }, { id_vendor: 'V0002' }];
var row_vendor;
vendors.forEach(function (value) {
row_vendor += value.id_vendor;
});
alert(row_vendor); // undefinedV0001V0002
Why does the value alerted display a leading "undefined"?

You're not initializing your variable, so its value is undefined. Concatenating a string coerces it to the string "undefined" before the concatenation.
Consider:
var x
alert(x + "test") // undefinedtest
Instead, initialize your variable to an empty string before performing concatenation:
var x = ""
alert(x + "test") // test
Note that functionally it is much cleaner to first extract the property you're interested in and then simply join them together:
$.map(vendor, function (v) { return v.vendor_id }).join('')

Your row_vendor variable is not assigned an initial value, so it starts out undefined and then using the += operator on it to concatenate a string results in undefined becoming the string "undefined" (plus the "v0001"). Simply set it to an empty string when you declare it:
var row_vendor = "";

The issue is on this line
$.each(vendor, function(i, value) {
row_vendor += value.id_vendor;
});
In order to use row_vendor for concatenation purpose, you first have to have a default value assigned to it. So what you would need to do is:
var row_vendor = ""; // set it to empty string by default
$.each(vendor, function(i, value) {
row_vendor += value.id_vendor;
});
On a sidenote, you can also concatenate a string using an array. I prefer it this way since it's more pretty and readable.
var row_vendor = []; // empty array
$.each(vendor, function(i, value) {
row_vendor.push(value.id_vendor);
});
console.log(row_vendor.join(",")); // this will separate each value with a comma

Related

JavaScript callback-function in PHP-Array [duplicate]

I have a JS object I would like to save in Local Storage for future use, and I cannot parse it to a string.
Code:
JSON.stringify({
a: 5,
b: function (param) {
return param;
}
})
Result:
"{"a":5}"
How do I save it for future use, if not with JSON?
(And creating my own Lexer-Parser to interupt string function I dont think is an option)
I'd recommend this approach:
Store arguments and the body in your json:
{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}
Now parse json and instantiate the function:
var f = new Function(function.arguments, function.body);
I think it's save
Usually a question like this indicates an X/Y problem: You need to do X, you think Y will help you do that, so you try to do Y, can't, and ask how to do Y. It would frequently be more useful to ask how to do X instead.
But answering the question asked: You could use replacer and reviver functions to convert the function to a string (during stringify) and back into a function (during parse) to store a string version of the function, but there are all sorts of issues with doing that, not least that the scope in which the function is defined may well matter to the function. (It doesn't matter to the function you've shown in the question, but I assume that's not really representative.) And converting a string from local storage into code you may run means that you are trusting that the local storage content hasn't been corrupted in a malicious way. Granted it's not likely unless the page is already vulnerable to XSS attacks, but it's an issue to keep in mind.
Here's an example, but I don't recommend it unless other options have been exhausted, not least because it uses eval, which (like its close cousin new Function)) can be a vector for malicious code:
// The object
var obj = {
a: 5,
b: function (param) {
return param;
}
};
// Convert to JSON using a replacer function to output
// the string version of a function with /Function(
// in front and )/ at the end.
var json = JSON.stringify(obj, function(key, value) {
if (typeof value === "function") {
return "/Function(" + value.toString() + ")/";
}
return value;
});
// Convert to an object using a reviver function that
// recognizes the /Function(...)/ value and converts it
// into a function via -shudder- `eval`.
var obj2 = JSON.parse(json, function(key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
return (0, eval)("(" + value + ")");
}
return value;
});
document.body.innerHTML = obj2.b(42);
The construct (0, eval)("(" + value + ")"); ensures that eval runs at global scope rather than within the scope of the reviver function. Normally eval has a magic ability to use the scope you call it in, but that only works when you call it directly. Indirect eval as shown (or just var e = eval; e("(" + value + ")");) doesn't have that magic ability, it runs at global scope.
You can't store functions in JSON.
The value in JSON may contain only string, number, object, array, true, false or null:
Check out it on JSON site.
One simple way of doing this is
var dstr = JSON.stringify( { a: 5
, b: x => x
}
, (k,v) => typeof v === "function" ? "" + v : v
);
I've taken to storing the function name, along with the parameter values, in an array, with the first item in the array being the function name prepended with a $, to separate them from normal arrays.
{
"object": {
"your-function": ["$functionName", "param-1", "param-2"],
"color": ["$getColor", "brand", "brand-2"],
"normal-array": ["normal", "array"]
...
}
}
In the above example I have Sass and JS functions to retrieve color values from a global map/object. Parsing the function in this manner naturally requires custom code, but in terms of "storing" functions in JSON, I like this way of doing it.
I have created JSON.parseIt() and JSON.stringifyIt() functions based on the first answer without using eval
JSON.stringifyIt = (obj)=>{
return(
JSON.stringify(obj, function(key, value) {
if (typeof value === "function") {
return "/Function(" + value.toString() + ")/";
}
if(typeof value === "string"){
return "/String(" + value.toString() + ")/"
}
return value;
})
)
}
JSON.parseIt=(json)=>{
return(
JSON.parse(json, function(key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
var string = value.slice(value.indexOf("(") + 1, value.indexOf(")"));
if(/\S+/g.test(string)){
return (new Function(string,value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))))
}else{
return (new Function(value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))));
}
}
if (typeof value === "string" &&
value.startsWith("/String(") &&
value.endsWith(")/")){
value = value.substring(8, value.length - 2);
}
return value;
})
)
}
// DEMO
var obj = {
string:"a string",
number:10,
func:()=>{
console.log("this is a string from a parsed json function");
},
secFunc:(none,ntwo)=>{console.log(none + ntwo)} ,
confuse:"/Function(hello)/"
}
const stringifiedObj = JSON.stringifyIt(obj);
console.log("the stringified object is: ",stringifiedObj);
const parsedObj = JSON.parseIt(stringifiedObj);
// console.log("the parsed object is: ",parsedObj);
console.log(parsedObj.string);
console.log(parsedObj.number);
console.log(parsedObj.confuse);
parsedObj.func();
parsedObj.secFunc(5,6);
The problems I fixed were
Removed eval.
there was a problem in the stringifying and parsing that if I give a string like
"/Function(hello)/" will be a function when parsed
Made it to two functions
Added parameter insertation
For someone that still need include, for whatever reason, the function definition in JSON, this code can help (but can be slow depending object size):
function Object2JsonWithFunctions(o, space = null) {
var functionList = {}
var fnSeq = 0;
var snrepl = function(k,v){
if(typeof v === 'function'){
fnSeq++;
var funcName = `___fun${fnSeq}___`;
var funcText = ''+v;
functionList[funcName] = funcText
return funcName;
}
return v;
}
var RawJson = JSON.stringify(o, snrepl, space);
for(func in functionList){
var PropValue = `"${func}"`;
RawJson = RawJson.replace(PropValue, functionList[func])
}
return RawJson;}
The code will do the normal convert to JSON.
For functions, the original stringify will return as "prop":"function()..." (function as a string)... The code above will create a placeholder (e.g: "prop":"fn1") and create a function list... After, will replace every placeholder to original function body...

How to use a loop to test if a variable exists

I'm trying to construct the variable name and then test if it exists using a while loop but I think I'm creating it when I test for it so keep getting 'true' and the loop goes infinite.
var1 = "value1"
var2 = "value2"
var3 = "value3"
var i = 3
Logger.log(('value'+i)==true)
var i = 4
Logger.log(('value'+i)==true)
/*
var i = 1;
while (("value"+i) != null) {
Logger.log("value"+i)
i++;
}
*/
When I build the loop I want value4 to not exist and stop the loop but it doesn't. Because I've just created it's string I suppose, so how should I be formatting the test? First question here and I have searched but the 'construction' part seems to complicate things. Thanks.
Firstly, I'll clarify a misconception,
I want value4 to not exist and stop the loop but it doesn't. Because I've just created it's string I suppose
'value'+i doesn't create a variable. It represents the string 'value3'. In JS, strings are truthy, so you logger will print true.
Now to the question, how to check if variable exists.
The cleanest way of doing this would be to use a dictionary represented by a simple js object.
let definedVariablesDictionary = {};
definedVariablesDictionary.var1 = 'value1';
let isVarialbeDefined = variable => definedVariablesDictionary[variable] !== undefined;
console.log(isVarialbeDefined('var1')); // true
console.log(isVarialbeDefined('var2')); // false
Variable names are not strings, so your attempt to construct a string that matches the name of a variable won't evaluate that string as code.
If you want to do this, you should create an object with properties that store values, like a variable would. Then you can pass a string of the property name into the object, to retrieve the value of the property.
Also, you shouldn't check to see if the value is null as null is a valid value that a variable or property could have been set to. That check wouldn't tell you explicitly if the property was defined or not, it would only tell you if the value of the property was null. Instead, checking for the existence of the property can be done by just passing the property name into the object. If it exists, then the result is "truthy" and your if statement would proceed into the true branch. If the property doesn't exist, the return value is falsy and you'd proceed into the false branch.
let myObject = {
value1:"test1",
value2:"test2",
value3:"test3"
};
for(var i = 0; i < Object.keys(myObject).length +1; i++){
// Property names can be passed as strings using bracket notation
if(myObject["value" + i]){
console.log("value" + i + " exists and has a value of: " + myObject["value" + i]);
} else {
console.log("value" + i + " is not defined");
}
}

How to store a javascript function in JSON

I have a JS object I would like to save in Local Storage for future use, and I cannot parse it to a string.
Code:
JSON.stringify({
a: 5,
b: function (param) {
return param;
}
})
Result:
"{"a":5}"
How do I save it for future use, if not with JSON?
(And creating my own Lexer-Parser to interupt string function I dont think is an option)
I'd recommend this approach:
Store arguments and the body in your json:
{"function":{"arguments":"a,b,c","body":"return a*b+c;"}}
Now parse json and instantiate the function:
var f = new Function(function.arguments, function.body);
I think it's save
Usually a question like this indicates an X/Y problem: You need to do X, you think Y will help you do that, so you try to do Y, can't, and ask how to do Y. It would frequently be more useful to ask how to do X instead.
But answering the question asked: You could use replacer and reviver functions to convert the function to a string (during stringify) and back into a function (during parse) to store a string version of the function, but there are all sorts of issues with doing that, not least that the scope in which the function is defined may well matter to the function. (It doesn't matter to the function you've shown in the question, but I assume that's not really representative.) And converting a string from local storage into code you may run means that you are trusting that the local storage content hasn't been corrupted in a malicious way. Granted it's not likely unless the page is already vulnerable to XSS attacks, but it's an issue to keep in mind.
Here's an example, but I don't recommend it unless other options have been exhausted, not least because it uses eval, which (like its close cousin new Function)) can be a vector for malicious code:
// The object
var obj = {
a: 5,
b: function (param) {
return param;
}
};
// Convert to JSON using a replacer function to output
// the string version of a function with /Function(
// in front and )/ at the end.
var json = JSON.stringify(obj, function(key, value) {
if (typeof value === "function") {
return "/Function(" + value.toString() + ")/";
}
return value;
});
// Convert to an object using a reviver function that
// recognizes the /Function(...)/ value and converts it
// into a function via -shudder- `eval`.
var obj2 = JSON.parse(json, function(key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
return (0, eval)("(" + value + ")");
}
return value;
});
document.body.innerHTML = obj2.b(42);
The construct (0, eval)("(" + value + ")"); ensures that eval runs at global scope rather than within the scope of the reviver function. Normally eval has a magic ability to use the scope you call it in, but that only works when you call it directly. Indirect eval as shown (or just var e = eval; e("(" + value + ")");) doesn't have that magic ability, it runs at global scope.
You can't store functions in JSON.
The value in JSON may contain only string, number, object, array, true, false or null:
Check out it on JSON site.
One simple way of doing this is
var dstr = JSON.stringify( { a: 5
, b: x => x
}
, (k,v) => typeof v === "function" ? "" + v : v
);
I've taken to storing the function name, along with the parameter values, in an array, with the first item in the array being the function name prepended with a $, to separate them from normal arrays.
{
"object": {
"your-function": ["$functionName", "param-1", "param-2"],
"color": ["$getColor", "brand", "brand-2"],
"normal-array": ["normal", "array"]
...
}
}
In the above example I have Sass and JS functions to retrieve color values from a global map/object. Parsing the function in this manner naturally requires custom code, but in terms of "storing" functions in JSON, I like this way of doing it.
I have created JSON.parseIt() and JSON.stringifyIt() functions based on the first answer without using eval
JSON.stringifyIt = (obj)=>{
return(
JSON.stringify(obj, function(key, value) {
if (typeof value === "function") {
return "/Function(" + value.toString() + ")/";
}
if(typeof value === "string"){
return "/String(" + value.toString() + ")/"
}
return value;
})
)
}
JSON.parseIt=(json)=>{
return(
JSON.parse(json, function(key, value) {
if (typeof value === "string" &&
value.startsWith("/Function(") &&
value.endsWith(")/")) {
value = value.substring(10, value.length - 2);
var string = value.slice(value.indexOf("(") + 1, value.indexOf(")"));
if(/\S+/g.test(string)){
return (new Function(string,value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))))
}else{
return (new Function(value.slice(value.indexOf("{") + 1, value.lastIndexOf("}"))));
}
}
if (typeof value === "string" &&
value.startsWith("/String(") &&
value.endsWith(")/")){
value = value.substring(8, value.length - 2);
}
return value;
})
)
}
// DEMO
var obj = {
string:"a string",
number:10,
func:()=>{
console.log("this is a string from a parsed json function");
},
secFunc:(none,ntwo)=>{console.log(none + ntwo)} ,
confuse:"/Function(hello)/"
}
const stringifiedObj = JSON.stringifyIt(obj);
console.log("the stringified object is: ",stringifiedObj);
const parsedObj = JSON.parseIt(stringifiedObj);
// console.log("the parsed object is: ",parsedObj);
console.log(parsedObj.string);
console.log(parsedObj.number);
console.log(parsedObj.confuse);
parsedObj.func();
parsedObj.secFunc(5,6);
The problems I fixed were
Removed eval.
there was a problem in the stringifying and parsing that if I give a string like
"/Function(hello)/" will be a function when parsed
Made it to two functions
Added parameter insertation
For someone that still need include, for whatever reason, the function definition in JSON, this code can help (but can be slow depending object size):
function Object2JsonWithFunctions(o, space = null) {
var functionList = {}
var fnSeq = 0;
var snrepl = function(k,v){
if(typeof v === 'function'){
fnSeq++;
var funcName = `___fun${fnSeq}___`;
var funcText = ''+v;
functionList[funcName] = funcText
return funcName;
}
return v;
}
var RawJson = JSON.stringify(o, snrepl, space);
for(func in functionList){
var PropValue = `"${func}"`;
RawJson = RawJson.replace(PropValue, functionList[func])
}
return RawJson;}
The code will do the normal convert to JSON.
For functions, the original stringify will return as "prop":"function()..." (function as a string)... The code above will create a placeholder (e.g: "prop":"fn1") and create a function list... After, will replace every placeholder to original function body...

add a value to localstorage, instead of replacing it

i want the value from newUsername to be added to the localStorage setUsernamesArray, whereas in my code, it replaces the entire value.
Code
$('#signUpButton').click(function() {
var newUsername = $('#usernameSignInBox').val();
signedUpUsernames.push(newUsername);
localStorage.setItem('setUsernamesArray', signedUpUsernames);
});
If you want to add to the array, you must realise that the value in localStorage isn't an array, it is a string. If you want that string to represent an array, and you want to update that array, you must do the following things:
read the string, localStorage.getItem('setUsernamesArray'),
then convert it to an array with JSON.parse,
then push to the array,
and then store it again with localStorage.setItem('setUsernamesArray', JSON.stringify(array))
localStorage always store values as a string, so stringify your array and store,
localStorage.setItem('setUsernamesArray', JSON.stringify(signedUpUsernames));
And before reading it just parse it,
var arrayFrmStorage = JSON.parse(localStorage.getItem("setUsernamesArray"))
localStorage.setItem will replace value of the key in localStorage.
Consider localStorage as a variable. when you do
var a = "Hello";
a = " World"
value of a is replaced. To avoid it, we use +=
var a = "Hello";
a += " World"
Similarly, you will have to create another object with updated value and write this to localStorage.
Following is an example.
function setValueToLS(key, prop, value){
var _local = {};
if(localStorage.getItem(key))
_local = JSON.parse(localStorage.getItem(key));
_local[prop] = value;
localStorage.setItem(key, JSON.stringify(_local));
}

How can I add a array as a property with the following syntax?

var Items = {
FormVariables: function()
{
if (this.array === 'undefined')
{
this.array = [];
}
return this.array;
}
};
This was my attempt at it and I get an error of it being undefined. Can I even have variables within Items scope like I am attempting. If so, what does the syntax look like?
I am only asking if this can be done using the var variableName = {} syntax.
EDIT:
Accessing it
var formVars = new Array();
formVars.push('[');
for (var item in gd["FormVariables"])
{
formVars.push('"' + item + '":"' + gd["FormVariables"][item] + '"');
}
formVars.push(']');
The real goal here is to take all these items and convert it to a JSON array of key/value pairs
Yes, you can use []. [] is a shortcut for new Array, just like {} is for new Object.
this.array = [];
By the way, there are no 'compiler errors' since JavaScript is not a compiled language but an interpreted one.
Also, your checking does not make much sense. You'd probably want:
if (typeof this.array === 'undefined')
since typeof returns a string. Checking for the string 'undefined' is not the same as checking for 'real' undefined. For the string, it must have been set explicitly to those characters, which is almost never the case.

Categories

Resources