The Ultimate Javascript vs Dart Syntax Guide
Let’s compare these two puppies!
Variables and constants
Unlike Javascript, const
in Dart lives up to its meaning. The whole object is checked at compile time to ensure it's completely immutable.
Therefore any element inside femaleDogs
has to be a const
too. Not the case for the elements inside maleDogs
, which are not necessarily final
.
Dart doesn’t need let
because lexical scope works correctly.
Trailing semicolons are required in Dart. In Javascript you can omit the ;
(you have to be careful, though!)
Default assignment
Let’s set a default value of 1 if bones
is falsey (in Javascript) or null
(in Dart).
Destructuring assignment
This is a great Javascript-only feature.
Not possible in Dart yet.
Falsey vs null
Let’s go ahead and have a look at falsey values that only exist in Javascript.
In Dart, undefined values are null
. Expressions in conditionals may only be boolean.
In Dart, 'Rocky' - 2
is an error – not NaN
🤔 Fortunately Dart didn't pick up Javascript's 💩
Function literals
Exactly the same! In JS parenthesis are optional.
Function defaults
Dart requires curly braces for optional arguments. String interpolation is practically the same.
Spreading arguments
Not supported because a Dart function can’t have a variable amount of positional arguments. The alternative is simply:
Safe navigation
name
should be returned unless address
or street
are null
, in that case the whole expression should return null
.
In Dart we have the safe navigation operator:
Interested in Dart’s amazing capabilities to deal with nulls? Read Checking Nulls and Null-Aware Operators in Dart.
Collection literals
An Array
in Javascript is a List
in Dart. An Object
in Javascript is a Map
in Dart.
Cascade operator
The value of the array.push(element)
expression is always the value of push(element)
. This is standard behavior.
In Javascript, the array push
function returns the length of the array (go figure!). So we can't possibly have console.log([1, 2, 3].push(4, 5))
result in [1, 2, 3, 4, 5]
.
In Dart we have the cascade operator list..add()
, which allows us to return the list.
A fluent API is one that allows chaining. jQuery is a great example: $('a').css("underline", "none").html("link!");
as every jQuery function call returns this
.
This approach greatly reduces intermediate variables. However, not all APIs are designed this way. The cascade operator allows us to take a regular API and turn it into a fluid API, like what we did above with the list.
Array concatenation
To push or concatenate other arrays we can use addAll
in the same fashion:
But there’s a cleaner way! Using spreads…
Same same. Also for objects/maps:
(Notice that we have to use let
or const
in Javascript.)
But what if P2
has a value sometimes?
The optional spread operator ...?
will only insert the array if it's not null.
Let’s consider now this example:
There is yet another way in Dart of including logic inside arrays:
It’s called a “collection-if”. There’s also “collection-for”:
Extremely elegant! I can’t really think of a Javascript equivalent 🤔
Accessing properties in objects/maps
The Great Dane in the Room
Dart is a statically-typed language with strong type inference.
A comparison with Typescript would probably be fairer, but I’ll leave that for next time. 😄
As we’ve seen so far, we almost never need to declare type annotations:
This means we leverage the power of types without stuffing our code with declarations! But of course we may:
Specifying types can bring clarity to code. In our example above declarations are redundant (especially pets3
).
Imagine a walk
method with no typed arguments, assuming callers will pass an argument of type Distance
:
Gives all kind of weird behavior. The analyzer doesn’t have enough information to infer a specific type for distance
so it uses the dynamic
type. It's equivalent to:
In short: argument types are very important!
Type checking can be turned off at a variable-level by declaring it as dynamic
.
Object oriented breeds 🐩
Classes are relatively new in Javascript:
In Dart:
A few things to note!
- We can avoid using
new
when calling constructors – that is why I usedDog()
(vsnew Dog()
) - No need to use
this
to reference fields: it is only used to define constructors
Wanna know EVERYTHING about Dart constructors? Check out Deconstructing Dart Constructors.
Checking types
We use instanceof
in Javascript:
And is
in Dart:
Class & prototype extensions
These are methods that extend existing types. In Javascript a function can be added to a prototype:
In Dart:
Static extension members are available since Dart 2.6 and open up very interesting possibilities for API design, like the fantastic time.dart ⏰. Now we can do stuff like:
Parsing JSON 🐶 style
Javascript is a dynamic language. Misspelling length
just returns undefined
.
Checking for an empty list is easy in Dart:
list.isEmpty
, in Javascript we must use the length for this:!array.length
.
In Dart:
It is known that keys of a JSON object are strings, but values can be of many different types. Hence the resulting map is of type <String, dynamic>
.
When we misspell length
on a dynamic
variable there is no type checking, so the error we get is at runtime.
Equality to the bone 🦴
Another gigantic chaos in the world of Javascript. We won’t get into it — just say that for equality we only use ===
to tell if both objects are strictly the same.
If we need to verify equivalence of two different objects, we’d use a deep comparison like _.isEqual
in Lodash.
In Dart, ===
is identical
and isEqual
is ==
. You can override the ==
operator to check for equality between two objects 🙌
Doggy privates
While a solution is being worked on for ESNext, there is currently no proper way of defining private properties in Javascript.
Dart uses a _
prefix which makes the variable private. And we can use a standard getter to expose it to the outside world:
Makes sense?
Uhhmmm… we are setting the private variable and it actually works? 🤔
Private in Dart means library-private. If we placed the Dog
class in models.dart
:
Setters work in a similar way.
Futuristic hounds 🐕
The Promise
API in Javascript is analogous to the Future
API in Dart.
Both languages support then()
and async/await
.
Let’s appreciate the differences through a food dispenser that will pour out dog chow in 4 seconds.
Very similar in Dart:
Is this really the definitive syntax guide?
Well… maybe 🤪 Pending for a next revision:
- Imports and tree-shaking
- Enums
- Annotations
- Sync/async generators
- Workers vs Isolates
- and more!
As you may have noticed we simply highlighted differences between syntaxes. Not comparing their merits, popularity, available libraries, and many other considerations. There will be another opinionated article discussing which is the best tool for which job.
Original article published at Flutter Igniter: The Ultimate Javascript vs Dart Syntax Guide.