JavaScript false Boolean evaluates as true after assign as false - node.js

My variable keeps evaluating as true and goes inside the IF block. How is this possible? Even after I assign it as false.
this.model.hasQ1 = false
console.log('type ', typeof this.model.hasQ1) //don't know why typeof is a string
//const test = this.model.hasQ1 === 'true' //this will error out, but shouldn't if the top is typeof is a string
if(this.model.hasQ1){ //this should be false
console.log('hasQ1 ', this.model.hasQ1) //this gets printed anyways
}
//output: hasQ1 false

Okay, so did the toString() trick and it evaluates as expected. Can someone explain why? FYI, this is from a Typescript class, but I usually don't have to do this.
//model was assign this way, yet appears as a string (see next line)
this.model.hasQ1 = false;
//console log of this model appears like this
....,
hasQ1: 'false' }
//This fixes the issue
if(this.model.hasQ1.toString() === 'true'){
console.log('I should not see this')
}

you can force to compare the variable as string to make sure it works:
if(this.model.hasQ1.toString() == "true"){ //this should be false
console.log('hasQ1 ', this.model.hasQ1) //this gets printed anyways
}

var model = { hasQ1: null };
model.hasQ1 = false;
console.log('type ', typeof model.hasQ1) //typeof is boolean
if (model.hasQ1) { //this is false
console.log('hasQ1 ', model.hasQ1) //this is not printed
}
//output: hasQ1 false
You have to provide the class in order to figure out what's wrong with your code.

Related

preventing value compilation errors

Bixby raises "Value Compilation Errors" in the debugger whenever I run a script that brings back Empty Optional Values. The variable model is correct in that these values really are optional, i.e not needed for the user task to succeed. So you can simply ignore the debugger errors and everything will work, EXCEPT that the Story testing tool will report these runs as "failed." This means that the Story tool is almost useless for these cases, and that's a big problem.
Can someone show me how to code to avoid them?
Thanks to a tip from #mincheng I finally figured out how to do this. The key is to delete any object properties that are null, undefined, or empty strings. I loop over my array of objects with the delete function.
// remove undefined properties here
const removeEmpty = (obj) => {
Object.keys(obj).forEach(key => {
if (obj[key] && typeof obj[key] === 'object') removeEmpty(obj[key]);
else if (obj[key] === undefined || obj[key] === null || obj[key] === "") delete obj[key];
});
return obj;
};
for (var i = 0; i < altBrainsData.length; i++) {
//console.log('i is', i);
//console.log('function object', i, 'is', altBrainsData[i])
//console.log(removeEmpty(altBrainsData[i]))
altBrainsData[i] = removeEmpty(altBrainsData[i])
}

using Object name in if statement both true and false?

I try to use my object name for an if statement.. but both come up as true, why?
var moduleInfo = new Object("moduleInfo");
moduleInfo ["name"] = "Module: Export"
if (moduleInfo !== "moduleInfo"){
console.log("window is NOT modulInfo")
}
if (moduleInfo == "moduleInfo"){
console.log("window IS modulInfo")
}
The !== is comparing by type, and you are comparing an object with a primitive type of string. replacing either that operator with != or replacing the second one with === will probably get you a more consistent/desired result.
== converts the operands to the same type before making the comparison
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators

mongoose.findOneAndUpdate() changes the value being saved in my Express app

I found one other person asking about a value override, but its unanswered. Hopefully someone can point out the dumb thing im missing! Here's the gist...
var vote = req.body.vote;
var boolVote;
(vote === 'good') ? boolVote = true : boolVote = false;
// these square brackets were the issue ----------\/
Model.findOneAndUpdate({firstname:'Jane'},{$set:{'event.attempt.judge1':[boolvote]}},
{new: true},(err,lifter)=>{console.log(lifter.event.attempt.judge1})
Ive chopped it down to its basic function because in-program boolVote will console.log as the correct value (true if vote==='good', false otherwise) but no matter how i rearrange things it ALWAYS updates to the DB as true...
Originally boolVote was this
var boolVote = ()=>(vote === 'good') ? true : false;
which didnt work either. I can change the value in the mongo CLI without issue.
Has anyone else had issues saving a FALSE value to MongoDB? If so, what does it take to get this working, and if not what am i doing wrong???
Thanks in advance for any help, im pulling hair here.
You can write ternary simply like this, i'm not familiar with js but in other program languages like java the syntax is same as below
var boolVote = vote === 'good' ? true : false;
or
var boolVote = ( vote === 'good' ) ? true : false;
but when you do this
var boolVote = () => ( vote === 'good' ) ? true : false;
here boolVote is a Function with no arguments, so you need call boolVote() to get its value
EDIT
event.attempt.judge1 is a field, but when enclosed with square bracket as an array in the update method, regardless of true/false the non empty array resolved to true, same updated in db
Model.findOneAndUpdate(
{firstname:'Jane'},
{$set:{'event.attempt.judge1':boolvote}}, //removed []
{new: true},
(err,lifter)=>{console.log(lifter.event.attempt.judge1)}
)

I have created an API in which I am updating some parameters

If I am updating all parameters it's working fine but if I am updating
separately any parameter then other parameters getting null.
I don't know how to handle this condition.
I want that if I am updating one parameter it should not affect other
properties.
router.put('/session/addActivity/:sessionID',function(req,res){
Session.findOne({_id:req.params.sessionID},function(err,session){
if(err){
return res.send(err);
}
if(session){
session.qanda.isEnable = req.body.qanda_enabled;
session.qanda.isModerate = req.body.qanda_moderation;
session.qanda.isCommentEnable = req.body.qanda_comments;
session.qanda.isAnonymousResponse = req.body.qanda_anonymousResponse;
session.poll.isEnable = req.body.poll_enabled;
session.poll.isMultiSelect = req.body.poll_MultiSelect;
session.poll.answerLimit = req.body.poll_answerLimit;
session.pulse.isEnable = req.body.pulse_enabled;
session.pulse.isAnonymousResponse = req.body.pulse_anonymousResponse;
session.pulse.votesLimitPerUser = req.body.pulse_votesPerUser;
session.save(function(err,session){
if(err){
return res.send(err);
}
else{
res.json(session);
}
});
}
})
});
The problem is, you're explicitly setting the parameters, regardless of whether the data in req.body is set or not.
So, if it's not set (null) it's then clearing the corresponding property on your session object.
The only way to sort this out would be to explicitly check each parameter on your req.body object first:
if("undefined" !== typeof req.body.qanda_enabled){
session.qanda.isEnable = req.body.qanda_enabled;
}
if("undefined" !== typeof req.body.qanda_moderation){
session.qanda.isModerate = req.body.qanda_moderation;
}
if("undefined" !== typeof req.body.qanda_comments){
session.qanda.isCommentEnable = req.body.qanda_comments;
}
if("undefined" !== typeof req.body.qanda_anonymousResponse){
session.qanda.isAnonymousResponse = req.body.qanda_anonymousResponse;
}
//etc.....

How do I get the result of class getters into JSON? [duplicate]

Take this object:
x = {
"key1": "xxx",
"key2": function(){return this.key1}
}
If I do this:
y = JSON.parse( JSON.stringify(x) );
Then y will return { "key1": "xxx" }. Is there anything one could do to transfer functions via stringify? Creating an object with attached functions is possible with the "ye goode olde eval()", but whats with packing it?
json-stringify-function is a similar post to this one.
A snippet discovered via that post may be useful to anyone stumbling across this answer. It works by making use of the replacer parameter in JSON.stringify and the reviver parameter in JSON.parse.
More specifically, when a value happens to be of type function, .toString() is called on it via the replacer. When it comes time to parse, eval() is performed via the reviver when a function is present in string form.
var JSONfn;
if (!JSONfn) {
JSONfn = {};
}
(function () {
JSONfn.stringify = function(obj) {
return JSON.stringify(obj,function(key, value){
return (typeof value === 'function' ) ? value.toString() : value;
});
}
JSONfn.parse = function(str) {
return JSON.parse(str,function(key, value){
if(typeof value != 'string') return value;
return ( value.substring(0,8) == 'function') ? eval('('+value+')') : value;
});
}
}());
Code Snippet taken from Vadim Kiryukhin's JSONfn.js or see documentation at Home Page
I've had a similar requirement lately. To be clear, the output looks like JSON but in fact is just javascript.
JSON.stringify works well in most cases, but "fails" with functions.
I got it working with a few tricks:
make use of replacer (2nd parameter of JSON.stringify())
use func.toString() to get the JS code for a function
remember which functions have been stringified and replace them directly in the result
And here's how it looks like:
// our source data
const source = {
"aaa": 123,
"bbb": function (c) {
// do something
return c + 1;
}
};
// keep a list of serialized functions
const functions = [];
// json replacer - returns a placeholder for functions
const jsonReplacer = function (key, val) {
if (typeof val === 'function') {
functions.push(val.toString());
return "{func_" + (functions.length - 1) + "}";
}
return val;
};
// regex replacer - replaces placeholders with functions
const funcReplacer = function (match, id) {
return functions[id];
};
const result = JSON
.stringify(source, jsonReplacer) // generate json with placeholders
.replace(/"\{func_(\d+)\}"/g, funcReplacer); // replace placeholders with functions
// show the result
document.body.innerText = result;
body { white-space: pre-wrap; font-family: monospace; }
Important: Be careful about the placeholder format - make sure it's not too generic. If you change it, also change the regex as applicable.
Technically this is not JSON, I can also hardly imagine why would you want to do this, but try the following hack:
x.key2 = x.key2.toString();
JSON.stringify(x) //"{"key1":"xxx","key2":"function (){return this.key1}"}"
Of course the first line can be automated by iterating recursively over the object. Reverse operation is harder - function is only a string, eval will work, but you have to guess whether a given key contains a stringified function code or not.
You can't pack functions since the data they close over is not visible to any serializer.
Even Mozilla's uneval cannot pack closures properly.
Your best bet, is to use a reviver and a replacer.
https://yuilibrary.com/yui/docs/json/json-freeze-thaw.html
The reviver function passed to JSON.parse is applied to all key:value pairs in the raw parsed object from the deepest keys to the highest level. In our case, this means that the name and discovered properties will be passed through the reviver, and then the object containing those keys will be passed through.
This is what I did https://gist.github.com/Lepozepo/3275d686bc56e4fb5d11d27ef330a8ed
function stringifyWithFunctions(object) {
return JSON.stringify(object, (key, val) => {
if (typeof val === 'function') {
return `(${val})`; // make it a string, surround it by parenthesis to ensure we can revive it as an anonymous function
}
return val;
});
};
function parseWithFunctions(obj) {
return JSON.parse(obj, (k, v) => {
if (typeof v === 'string' && v.indexOf('function') >= 0) {
return eval(v);
}
return v;
});
};
The naughty but effective way would be to simply:
Function.prototype.toJSON = function() { return this.toString(); }
Though your real problem (aside from modifying the prototype of Function) would be deserialization without the use of eval.
I have come up with this solution which will take care of conversion of functions (no eval). All you have to do is put this code before you use JSON methods. Usage is exactly the same but right now it takes only one param value to convert to a JSON string, so if you pass remaning replacer and space params, they will be ignored.
void function () {
window.JSON = Object.create(JSON)
JSON.stringify = function (obj) {
return JSON.__proto__.stringify(obj, function (key, value) {
if (typeof value === 'function') {
return value.toString()
}
return value
})
}
JSON.parse = function (obj) {
return JSON.__proto__.parse(obj, function (key, value) {
if (typeof value === 'string' && value.slice(0, 8) == 'function') {
return Function('return ' + value)()
}
return value
})
}
}()
// YOUR CODE GOES BELOW HERE
x = {
"key1": "xxx",
"key2": function(){return this.key1}
}
const y = JSON.parse(JSON.stringify(x))
console.log(y.key2())
It is entirely possible to create functions from string without eval()
var obj = {a:function(a,b){
return a+b;
}};
var serialized = JSON.stringify(obj, function(k,v){
//special treatment for function types
if(typeof v === "function")
return v.toString();//we save the function as string
return v;
});
/*output:
"{"a":"function (a,b){\n return a+b;\n }"}"
*/
now some magic to turn string into function with this function
var compileFunction = function(str){
//find parameters
var pstart = str.indexOf('('), pend = str.indexOf(')');
var params = str.substring(pstart+1, pend);
params = params.trim();
//find function body
var bstart = str.indexOf('{'), bend = str.lastIndexOf('}');
var str = str.substring(bstart+1, bend);
return Function(params, str);
}
now use JSON.parse with reviver
var revivedObj = JSON.parse(serialized, function(k,v){
// there is probably a better way to determ if a value is a function string
if(typeof v === "string" && v.indexOf("function") !== -1)
return compileFunction(v);
return v;
});
//output:
revivedObj.a
function anonymous(a,b
/**/) {
return a+b;
}
revivedObj.a(1,2)
3
To my knowledge, there are no serialization libraries that persist functions - in any language. Serialization is what one does to preserve data. Compilation is what one does to preserve functions.
It seems that people landing here are dealing with structures that would be valid JSON if not for the fact that they contain functions. So how do we handle stringifying these structures?
I ran into the problem while writing a script to modify RequireJS configurations. This is how I did it. First, there's a bit of code earlier that makes sure that the placeholder used internally (">>>F<<<") does not show up as a value in the RequireJS configuration. Very unlikely to happen but better safe than sorry. The input configuration is read as a JavaScript Object, which may contain arrays, atomic values, other Objects and functions. It would be straightforwardly stringifiable as JSON if functions were not present. This configuration is the config object in the code that follows:
// Holds functions we encounter.
var functions = [];
var placeholder = ">>>F<<<";
// This handler just records a function object in `functions` and returns the
// placeholder as the value to insert into the JSON structure.
function handler(key, value) {
if (value instanceof Function) {
functions.push(value);
return placeholder;
}
return value;
}
// We stringify, using our custom handler.
var pre = JSON.stringify(config, handler, 4);
// Then we replace the placeholders in order they were encountered, with
// the functions we've recorded.
var post = pre.replace(new RegExp('"' + placeholder + '"', 'g'),
functions.shift.bind(functions));
The post variable contains the final value. This code relies on the fact that the order in which handler is called is the same as the order of the various pieces of data in the final JSON. I've checked the ECMAScript 5th edition, which defines the stringification algorithm and cannot find a case where there would be an ordering problem. If this algorithm were to change in a future edition the fix would be to use unique placholders for function and use these to refer back to the functions which would be stored in an associative array mapping unique placeholders to functions.

Resources