Can someone explain to me what is happening in the following code? Thanks.
let myObject = {
myFunction() {
console.log('HELLO WORLD');
}
};
console.log(JSON.stringify(myObject.myFunction));
if (myObject.myFunction) {
console.log('myFunction exists');
}
As described over in MDN, JSON.stringify returns undefined when a function is passed as an argument:
undefined, Functions, and Symbols are not valid JSON values. If any
such values are encountered during conversion they are either omitted
(when found in an object) or changed to null (when found in an array).
JSON.stringify() can return undefined when passing in "pure" values
like JSON.stringify(function(){}) or JSON.stringify(undefined).
Because JSON.stringify() cannot be used on functions, they are treated as undefined. See the explanation here.
Related
I found a really great use case for optional chaining in my react project. I have used it slightly before but this line of code has made me a bit confused.
I have a table that is sortable.
One of the columns shows success or failure depending on if failed_date is null or a date.
sortedRows = sortedRows.sort((a, b) => a?.failed_date?.localeCompare(b?.failed_date));
But What confuses me is which value does the '?.' check is nullish?
Does a.failed_date?.localeCompare() check if failed_date?. is null/undefined or does it check if ?.localeCompare() is null/undefined?
Same with b?.failed_date is it checking b to be nullish? or failed_date.
I think My confusion comes from looking at the Documentation
Because arr?.[50] checks if element 50 is nullish but obj.method?.() checks if the method is not nullish?
Looking at this second block of code (which I believe is now correct) a.failed_date may be nullish and won't do localeCompare if a.failed_date is null?
But what if a.failed_date is not null but b.failed_date is null?
Does localeCompare not care? I haven't gotten an error but I was using localeComapre(b?.failed_date)
sortedRows = sortedRows.sort((a, b) => a.failed_date?.localeCompare(b.failed_date));
Let's say you define variable like below
const variable = { value: 'test' };
then you want to access variable?.value it equals variable === null || variable === undefined ? undefined : variable.value.
Same with array.
Check typescript playground and see js output https://www.typescriptlang.org/play?#code/MYewdgzgLgBAhgJwXAnjAvDA2gXQNwBQBiyKA-AHRYCsADDkA
Basically, the ? in that context means optional chaining.
How it works is, for example, if you define an object like below, and you want to try and access the views property, it will throw an error.
const obj = { website: "stackoverflow.com", };
console.log(obj.views.toFixed(0)); // Error!
This is because you are trying to access a method off of undefined, which doesn't have anything.
To avoid this error, we can use optional chaining, like below.
const obj = { website: "stackoverflow.com", };
console.log(obj?.views?.toFixed(0)); // undefined
Optional chaining tells JavaScript to complete the method/read the key, but if it doesn't exist, instead of throwing an error, just return undefined.
It also works with arrays; the same way! If, say, index 78 doesn't exist, instead of throwing an error, it will just return undefined.
const arr = [1, 2, 3];
console.log(arr?.[78]?.toString());
To elaborate here, it is possible to stack multiple optional chaining operators as seen in OP's code a?.failed_date?.localeCompare(b?.failed_date)
In these cases, it is not a question of which object key value will be checked. The code will be evaluated from left to right and if any of the object values are nullish then undefined will be returned.
Refer to the documentation for further understanding
MDN Optional Chaining
I am making a function in the Data-Type "Object",
Code:
Object.exists = function(obj){
if(typeof(obj)==="object"){
return true;
}else{
return false;
}
}
Its purpose is to check whether an object exists or not. Everything works fine if the object entered exists, but if I try to check an object which does not exist(I am trying to develop a function and am currently checking it), it throws an error. The code to check and the error msg:
Object.exists(demo); //Note: demo is not an object
//Error:
Uncaught ReferenceError: demo is not defined
at <anonymous>:1:15
and if I try to add demo in quotes, then it does not work and shows false even if I try to add an existing object. If I try
if(typeof(obj)==="object"){
return true;
}else{
return false;
}
}
the code above without the function and the object doesn't exist, no error is thrown.
So I tried to work out my dumb brain and thought that can I use eval(), but I don't think so. Is there any other way I can convert the parameter(even if it is a string) into an object for the if statement?
I just found out the answer,
used eval() and it worked!
The code:
Object.exists = function(obj){
var type = eval("typeof("+obj+")");
console.log(type);
}
When you try an object which exists, it logs object, but if you try anything other, it logs it's type.
I am going to test if 'session' property exists:
console.log(queryData)
console.log(typeof queryData)
if ('session' in queryData) {
console.log('in')
}
else {
console.log('not in')
}
if (queryData.hasOwnProperty('session')) {
console.log('has own propety')
}
Its result is:
[Object: null prototype] { session: '0geBdiCsfczLQiT47dd45kWVN2Yp' }
object
in
/home/ubuntu/22.enmsg/cli/main.js:72
if (queryData.hasOwnProperty('session')) {
^
TypeError: queryData.hasOwnProperty is not a function
Why does the hasOwnProperty NOT work?
Most objects in javascript inherit from Object; it's possible to intentionally create objects that inherit from nothing (i.e., null), and therefore they won't have any of the typical methods you'd expect to live on the object.
You would normally know if your code was doing this, so the object might be something passed to you from another library.
A way around the error is to call hasOwnProperty on Object explicitly, and bind it to the object, like so:
// Calls "hasOwnProperty" on queryData, even if queryData has
// no prototype:
console.log(Object.hasOwnProperty.bind(queryData)('session'));
EDIT: Just editing to add an opinion, which is that a much better line for your purposes is the simple truthy check if (queryData.session) {. The vagueness of this check is a strength when what you're asking is "did a session get passed?" - if session is null, undefined, false, empty string, or the key is missing altogether, the answer is clearly "no".
The easiest solution is to convert your null-prototype object to a standard javascript Object. You can do so by:
OBJjavascript = JSON.parse(JSON.stringify(objNullPrototype));
Parsing the object as in https://stackoverflow.com/a/56488323/3121906 would technically work but would be expensive for large objects.
https://stackoverflow.com/a/53978289/3121906 is good, but why not just use call?
Object.prototype.hasOwnProperty.call(queryData, 'session')
This is a fairly simple question, but I can't seem to find an example online. I've read up on objects and functions (i.e. here), but can't seem to find an example of a function within an object that accepts parameters.
In JavaScript, we can create an object, a nested object, and a method defined by a function:
var testObject = {
nestedObject : {
isNumber : function(number) { return !isNaN(number) };
}
}
How can I call my function with a specific parameter? Is the following correct?
testObject["nestedObject"].isNumber(number)
Thanks!
You kind of have the right idea but you need to refactor your object. This is how it would be written and called.
var testObject = {
nestedObject: {
isNumber :function(number) { return isNaN(number) }
}
}
then
testObject.nestedObject.isNumber(3);
Looks like there were just a few syntax errors in your code. Functions defined within an object behave the same way as regular functions defined outside of an object. The only difference is that you will have to use dot notation to access the functions on objects. So, try this code out:
testObject = {
nestedObject: {
isNumber: function(number) { return !isNaN(number) }
}
}
Now, you can call isNumber like this:
testObject.nestedObject.isNumber(4) // returns true
Note: Assuming you want your function isNumber to return true if the input is a number, we have to negate ( using ! ) the result of isNaN, as it returns true for values that are NaN.
Edit: When accessing properties (functions or otherwise) of an object, you can use dot notation as above, or you could use bracket notation, or some combination of the two. Here are a few examples:
testObject.nestedObject.isNumber(4) // dot notation
testObject['nestedObject']['isNumber'](4) // bracket notation
testObject['nestedObject'].isNumber(4) // combination of both
testObject.nestedObject['isNumber'](4) // alternative combination of both
There is not necessarily a right way to use bracket vs dot notation, but I think dot notation looks a little cleaner. I guess the only advice is to try to be consistent in however you decide to write it.
In this line:
testObject[nestedObject].isNumber(number)
nestedObject will be evaluated and its value will be passed as key of the property of testObject. What you need is to make it literal, to tell JavaScript that that is the property key.
Just to expand the information given by Tyler, these two are equivalents:
testObject["nestedObject"].isNumber(number)
And:
testObject.nestedObject.isNumber(number)
Why doesn't this produce anything?
console.log(JSON.stringify(function(){console.log('foobar');}));
JSON can't stringify functions at all, it handles them just like undefined or null values. You can check the exact algorithm at EcmaScript 5.1 §15.12.3, see also the description at MDN.
However you of course can stringify function expression by casting them to a string, try
console.log("" + function(){console.log('foobar');})
yourFunctionName.toString(); will also stringify a function
JSON has no means to represent a function. It is a data format designed for simplicity and compatibility across languages (and a function is the last thing that will be cross-language compatible).
From the docs for JSON.stringify:
If undefined, a function, or an XML value is encountered during conversion it is either omitted (when it is found in an object) or censored to null (when it is found in an array).
If you want to use JSON.stringify to also convert functions and native objects you can pass a converter function as the second argument:
const data = {
fn: function(){}
}
function converter(key, val) {
if (typeof val === 'function' || val && val.constructor === RegExp) {
return String(val)
}
return val
}
console.log(JSON.stringify(data, converter, 2))
Return undefined from the converter function if you want to omit the result.
The third parameter is how many spaces you want the output to indent (optional).
You cannot do that, but there are some third party libraries can help you do that, like: https://www.npmjs.com/package/json-fn
There are couple of ways to do this.
Let's say you have function foo
> function (foo) { return foo}
if you console log it it returns function name with type
> console.log(foo)
[Function: foo]
when it comes to get access to stringified version of it, you can use one of the ways listed below.
> console.log(`${foo}`)
function (bar) { return bar}
undefined
> console.log(foo.toString())
function (bar) { return bar}
undefined
> console.log("" + foo)
function (bar) { return bar}
undefined
Well there are two ways I know of doing this, first is just String(function) and you can just do eval() on what that returns. There's also a way to run the code in the function directly with regex, it would look something like this:
String(function).replace(/\w+\s{1}\w+\(\)\s?\{(\n\s+)?|\(\)\s?=>\s?{(\n\s+)?/, '').replace(/\n?\}/, '')
with the regex example when you do eval() it runs the code from the function. For both examples where it says "function" put in the name of your function with no () at the end.