What is the convention in JSON for empty vs. null? - javascript

I know that in most programming scenarios, the preference is for empty collections to null collections when there are 0 elements. However, most languages that consume JSON (like JavaScript) will treat empty lists/objects as true and null ones as false. For example this would be both true and an object in JavaScript:
{
"items_in_stock": {"widgets":10, "gadgets": 5}
}
But this is also true:
{
"items_in_stock": {}
}
And this is false:
{
"items_in_stock": null
}
Is there a convention on empty objects/lists for JSON? And what about for numbers, booleans, and strings?

It is good programming practice to return an empty array [] if the expected return type is an array. This makes sure that the receiver of the json can treat the value as an array immediately without having to first check for null. It's the same way with empty objects using open-closed braces {}.
Strings, Booleans and integers do not have an 'empty' form, so there it is okay to use null values.
This is also addressed in Joshua Blochs excellent book "Effective Java". There he describes some very good generic programming practices (often applicable to other programming langages as well). Returning empty collections instead of nulls is one of them.
Here's a link to that part of his book:
http://jtechies.blogspot.nl/2012/07/item-43-return-empty-arrays-or.html

"JSON has a special value called null which can be set on any type of data including arrays, objects, number and boolean types."
"The JSON empty concept applies for arrays and objects...Data object does not have a concept of empty lists. Hence, no action is taken on the data object for those properties."
Here is my source.

There is the question whether we want to differentiate between cases:
"phone" : "" = the value is empty
"phone" : null = the value for "phone" was not set yet
If we want differentiate I would use null for this. Otherwise we would need to add a new field like "isAssigned" or so. This is an old Database issue.

Empty array for empty collections and null for everything else.

Related

Why is the difference between this 2 typescripts objects

I am new to the typescript, and trying to learn the language
Below I have 2 objects I want to understand what is difference between them, they are definitely different as nothing is printed on console.
Code
let some = {'flag' : {copy : 'true'}};
let other = {'flag' : {"copy" : 'true'}};
if(some === other)
console.log("Same")
(Other variable have copy in quotes)
Also if I hover on to the "copy" attribute, IDE is showing string property in both cases.
let some = {'flag' : {copy : 'true'}};
let other = {'flag' : {"copy" : 'true'}};
Your two objects, some and other are basically the same, but object comparison in JS will always return false. This is because the variables are not storing the objects, it's storing a reference to the object. This means that even if the objects have the same structure and the same values for every key, any equality comparison with both == and === will be false. The exception is when you're comparing the same object to itself, ie some === some is true(as it should be).
You can read more about it here
As for your question about quotes around keys, that is the proper syntax for JSON objects. By that I mean, if you're writing something that will be parsed as JSON, then you should use double quotes around all your keys. If it's in JS, you can omit the quotes, in fact, prettier will usually remove the quotes even if you type them. In JS, both the objects above are functionally exactly the same.
One place you will need to use quotes is when your object keys have symbols like -, +, spaces, etc.
const obj = {
"key with spaces": "value",
"Jan-Dec": "123"
}

Why does JS allow property access with an array as key?

Suppose I have an object
obj = {
a : 1
}
I'm able to access property a via obj["a"] but I'm also able to access it via obj[["a"]]. How is that possible?
Object keys are always strings (or, rarely, symbols). When you do
obj[<expression>]
the interpreter will try to turn expression into a valid key, if it isn't one already. In this case, turning ["a"] into a string results in "a", so both obj["a"] and obj[["a"]] work.
(When an array is implicitly turned into a primitive, like here, it gets .joined by a comma, and ["a"].join(',') === "a")

Json length is always undefined in node js

I am trying to iterate simple json array, but it always return the length of the array is undefined.
var chatmessage = {};
...................
...................
socket.on('listmessage', function(mesg){
chatmessage={"message":"Hello", "to":"sjdfjhsdf"};
});
socket.on('private', function(mesg){
console.log(chatmessage.length+' - '+chatmessage.message +' - '+ chatmessage.to);
});
when private event get trigger it returns
undefined - Hello - sjdfjhsdf
I think it consider length key word as a json array key like {"length":40}.
I have tried Object.keys(chatmessage).length but it returns the total number key value(2) but I have only one record.
What is the right way to iterate json in node js
I am trying to iterate simple json array
Two issues there:
That's not JSON. JSON is a textual notation for data exchange. If you're dealing with JavaScript source code, and not dealing with a string, you're not dealing with JSON. It's a JavaScript object initializer.
It doesn't define an array, it defines an object.
Objects don't have a length property. If you want your chatmessage to say how many properties it has, you'll have to add a third property explicitly (which then raises the question of whether the value should be 2 or 3 :-) ). Or alternately, you could make it an array of objects with "key" and "value" properties, but that would be awkward to work with.
If you need to, you can determine how many properties an object has in a couple of ways:
Object.keys(obj).length will tell you how many own, enumerable properties the object has (ignoring any with Symbol names, if you're using ES2015). The number will not include any inherited properties or any non-enumerable properties. The answer in your example would be 2.
Object.getOwnPropertyNames(obj).length) will tell you how many own properties the object, has regardless of whether they're enumerable (but again ignoring any with Symbol names). The number will not include any inherited properties or any non-enumerable properties. The answer in your example would again be 2 as your object has no non-enumerable properties.
I have tried Object.keys(chatmessage).length but it returns the total number key value(2) but I have only one record.
As I said above, Object.keys will tell you how many own enumerable properties the object has. If you're trying to find out how many objects there are, the answer is 1.
If your goal is to send an array of chat messages, then you want to create that like this:
var chatmessages = [
{"message":"Hello", "to":"sjdfjhsdf"}
];
That defines an array with one entry: A single object representing a chat message. Multiple ones would be separated with ,:
var chatmessages = [
{"message":"Hello", "to":"sjdfjhsdf"}, // First message
{"message":"Hello again", "to":"sjdfjhsdf"} // Second message
];
Note that if you're doing that, your verb should probably be listmessages (plural), not listmessage. (I mention this in case your native language handles plurals differently from English; there are a lot of different ways plurals are handled in the various human languages around the planet. :-) )

Is null a regular primitive in JavaScript?

There are plenty of discussions about what null in JavaScript actually is. For example, Why is null an object and what's the difference between null and undefined?.
MDN lists null among primitive values and states that it is:
a special keyword denoting a null value; null is also a primitive
value
(The above emphasis is mine)
My last reference will be to Programming JavaScript Applications book by Eric Elliott, which in its Chapter 3. Objects says the following:
In JavaScript, ... even primitive types
get the object treatment when you refer to them with the property
access notations. They get automatically wrapped with an object so
that you can call their prototype methods.
Primitive types behave like objects when you use the property access notations, but you can't assign new properties to them. Primitives
get wrapped with an object temporarily, and then that object is
immediately thrown away. Any attempt to assign values to properties
will seem to succeed, but subsequent attempts to access that new
property will fail.
And indeed the following statements will execute without a problem:
"1".value = 1;
(1).value = "1";
false.value = "FALSE";
while his one
null.value = "Cannot set property of null";
throws Uncaught TypeError. See JS Fiddle.
So at least in this regard, null behaves differently than other primitives.
Is null considered a regular primitive in JavaScript?
Yes it's an actual primitive.
The exceptions for property access are null and undefined, because they have no wrapper type like strings, booleans and numbers do.
ECMAScript 5, Section 4.3.2 primitive
value
member of one of the types Undefined, Null, Boolean, Number, or String
as defined in Clause 8.
NOTE A primitive value is a datum that is represented directly at the
lowest level of the language implementation.

Conventions for querystring parameters

When I have a url like this:
http://server/site?firstname=Jack&lastname=Daniels
I understand that in my JavaScript a query for firstname should return "Jack".
But what should the query for firstname return in the following cases:
http://server/site?lastname=Daniels
http://server/site?firstname&lastname=Daniels
http://server/site?firstname=&lastname=Daniels
[Edit] To answer some of the comments: all of the above are legal querystrings, my question is not about how to retrieve the parameters but how to interpret them.
For the record, I parse querystrings with the following regular expression that covers all cases:
/([^?=&;]+)(?:=([^&;]*))?/g
Apparently there's a very popular question on how to retrieve querystring parameters, but the answer is incorrect (or at least not addressing edge cases).
[Update] My choice based on the answers from #Bergi and #zzzzBov:
http://server/site?lastname=Daniels => firstname: undefined
http://server/site?firstname&lastname=Daniels => firstname: true
http://server/site?firstname=&lastname=Daniels => firstname: ""
http://server/site?firstname=Jack&lastname=Daniels => firstname: "Jack"
A side effect is that I had to slightly modify my regex, as with the above rules the = sign needs to be captured:
/([^?=&;]+)(=[^&;]*)?/g
But what should the query for firstname return in the following cases:
http://server/site?lastname=Daniels
http://server/site?firstname&lastname=Daniels
http://server/site?firstname=&lastname=Daniels
Query strings can easily be represented by object notation in JavaScript. Simply set only the keys that are present in the query string on the object.
This means that for ?lastname=Daniels the object produced should be:
{
lastname: 'Daniels'
}
In cases where the key is present, but no value is given (no equals sign), the key should be set with a value of null which represents "no value".
This means that for ?firstname&lastname=Daniels the object produced should be:
{
firstname: null,
lastname: 'Daniels'
}
In cases where the key is present, and the value provided is empty (equals sign), the value is actually the empty string.
This means that for ?firstname=&lastname=Daniels the object produced should be:
{
firstname: '',
lastname: 'Daniels'
}
There is also an often overlooked case of where the same key is used multiple times. In the traditional query-string syntax (not PHP), keys can be used multiple times, as-is, to represent an array.
This means that for ?foo=bar&foo=baz the object produced should be:
{
foo: [
'bar',
'baz'
]
}
<aside>
In PHP land, keys used for arrays are suffixed with []:
`?foo[]=bar&foo[]=baz`
PHP will automatically convert the query-string server side such that:
$_GET['foo'] = array('bar', 'baz')
</aside>
Going back to the original question, what this implies is the following:
?lastname=Daniels has a value of undefined for the firstname key.
?firstname&lastname=Daniels has a value of null for the firstname key.
?firstname=&lastname=Daniels has a value of '' for the firstname key.
For cases where a key is used as a boolean based on its presence, you should be checking whether the object has the key set (and completely ignore the value, as it doesn't matter).
Typically this is done with obj.hasOwnProperty('key'), however as the object is really more of a hash, Object.prototype.hasOwnProperty.call(obj, 'key') is preferrable, which could be abstracted into a has function:
has(obj, key) {
return Object.prototype.hasOwnProperty.call(obj, key);
}
If you're using underscore.js, then you could use _.has(obj, key)
But what should the query return
That's your decision, what do you need? There are several querystring-evaluating functions of different complexity. Some of them can deal with repeated, nested, bracket-syntax values, others not. Famous ones can be found in How can I get query string values in JavaScript? and its duplicate questions.
However, you asked for conventions:
http://server/site?lastname=Daniels
The result should be something falsy to represent the absence of firstName. You might choose null or undefined.
http://server/site?firstname&lastname=Daniels
This often represents some boolean parameter, so returning true would be legitimate. Yet I'm sure there are libs that completely ignore this format.
http://server/site?firstname=&lastname=Daniels
That's quite obviously the empty string "".

Categories