Comparing Flutter code to Javascript - LLF #6
Tags: dart, flutter, tutorial, javascript
Published: 2021-10-11 13:39:19

**Hey there** 👋

I'm back with another entry to this series, so... Javascript right? We all love and hate it, yet have no choice but to use it if we want to create interactive websites (_kinda_).  As a result, many developers know Javascript or have at least used it on some occasion. 

Consider this post as a comparison between some common aspects of both JS and Dart applications (like _async code, handling lists/arrays_). 

## Table Of Contents
* [Entrypoints](#entrypoints)
* [Logging](#logging)
* [Functions](#functions)
* [Boolean checks](#boolean-checks)
* [Futures/Promises](#futurespromises)
* [Async/Await](#asyncawait)
* [Maps/Objects](#mapsobjects)
* [Running an app](#running-an-app)
* [Learning more](#learning-more)

## Entrypoints
The first step to creating an app is launching/starting it. In dart, an entry-point function is required for all applications, in contrast to Javascript where it's up to you to define such a function. Note that if you use a framework it might require you to define an entry-point of some sort. 

Let's see how Dart does it and then show some examples of how we do that in javascript and some frameworks.

### Dart
In dart, all applications are required to start with a `main()` function. 

```dart
void main() {
    // Your initial code would go here
}
```

#### Flutter
In flutter, we are also required to define a `main()` function. But to start the app we must call the `runApp()` function. This will bootstrap and start our app:

```dart
void main() {
    runApp(const MyApp());
}
```

### Javascript 
Javascript is not as strict and doesn't force us to write a `main` function or any kind of entry-point really. Some might start directly when the script loads, or maybe wait until the page is fully loaded. Others might only start when a button is clicked and so on.

**When script loads:**
```js
function startHere() {
    // Your initial code would go here
}

startHere(); // Called when script is loaded
```

**When page loads:**
```js
function startHere() {
    // Your initial code would go here
}

document.addEventListener('load', () => {
    // Called when the page fully loaded all the HTML and external resources
});
```

#### Angular
Angular does not require us to define an entry-point function, but it requires us to create a `main` file where we will bootstrap/start our application. That file would look something like this:
```ts
// imports...

platformBrowserDynamic()
    .bootstrapModule(AppModule)
    .catch(err => console.error(err));
```
> Angular uses TypeScript but it's the same drill.


#### React Native
React native somewhat forces you to create an entry-point in the form of a React Component.

```js
import React from 'react';
import { Text, View } from 'react-native';

const HelloWorldApp = () => {
  return (
    <View
      style={{
        flex: 1,
        justifyContent: "center",
        alignItems: "center"
      }}>
      <Text>Hello, world!</Text>
    </View>
  )
}
export default HelloWorldApp;
```



----

## Logging

Dart does not offer such a variety of logging possibilities as the Javascript console. We are limited to just a single method `print`, without adding external packages (like [logger](https://pub.dev/packages/logger)).

### Dart
```dart
var example = '"I will, I do, I can, I should could do, yeh"';
print('I can only log a single string, but can easily interpolate variables like this: $example');
```

### JavaScript
```js
let example = '"I will, I do, I can, I should could do, yeh"';
console.log('I can only log more than a single string, ', `but can easily interpolate variables like this: ${example}`);
```

----

## Functions

### Javascript

```js
// Regular function
function canFly(player) {
    return player.hasWings && !player.isAChicken;
}

// Arrow function
const canRespawn = (player) => player.isInmortal;
```

### Dart

```dart
canFly(Player player) {
    return player.hasWings && !player.isAChicken;
}

// or specifying the type
bool canFly(Player player) {
    return player.hasWings && !player.isAChicken;
}

// Arrow function
bool canRespawn = (Player player) => player.isInmortal;
```

----

## Boolean checks
In Javascript `0`, `null`, `undefined`, an empty string (`''`) are all evaluated as `false`. And `1` and any other `non-null` value is evaluated as `true`. 


![Just a meme image on javascript bool checks](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/lc1mx46n278uzml200p1.png)

Dart only considers the boolean value `true` as true. So let's have a close look at how to perform some common checks:

### Javascript

```js
let undefinedValue = undefined;
let nullValue = null;
let value = 0;
let emptyString = '';

if(!undefinedValue) return;
if(!nullValue) return;
if(!value) return;
if(!emptyString) return;
```
* `0`, `null`, `undefined`, and `''` are all being treated as `false`.

### Dart

```dart
var nullValue = null;
int value = 0;
String emptyString = '';

if(nullValue == null) return;
if(value == 0) return;
if(emptyString.isEmpty) return;
```

As you can see, in Dart we must implicitly check if it's a certain value. Nothing is treated as a boolean, except booleans themselves (makes sense).

* We must use the `==` equality operator to implicitly check for `null`, `0`, and other values
* For empty string we can use the built-in `isEmpty()` method

----

## Futures/Promises

Both Javascript and Dart support single-threaded execution. Javascript offers the Promise object to handle this, while in Dart we use [`Future`](https://dart.dev/codelabs/async-await) objects. These classes represent the eventual completion or failure of some operation.

We commonly use [`Futures`](https://dart.dev/codelabs/async-await) and `Promises` objects when calling remote APIs via HTTP requests, as they take a long time to complete. Synchronously doing this operation would freeze the application until the operation either fails or completes.

### Javascript
```js

function answerOfLife() {
    const url = 'https://answeroflife.ai/give-it-to-me';
    return fetch(url)
        .then(result => result.json());
}

const result = answerOfLife()
    .then(result => result.answer)
    .catch(error => console.error(error));
```

### Dart
```dart
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<Response> answerOfLife() {
    const url = 'https://answeroflife.ai/give-it-to-me';
    return http.get(url)
        .then((response) =>  jsonDecode(response.body));
}

void main() {
    var result = answerOfLife()
        .then((response) => response.answer)
        .catchError((error) => print(error));
}
```

----

> **Did you know that you can create Web Apps with Flutter?**  
> It seems it's not 100% ready for big scale applications, though it does the job with some work on our part.

----

## Async/Await
If you are familiar with Javascript async/await, Dart is almost exactly the same. We mark the function with the `async` keyword, then we can use the `await` keyword to wait for promises/futures to complete.

### Javascript
```js

function answerOfLife() {
    const url = 'https://answeroflife.ai/give-it-to-me';
    return fetch(url)
        .then(result => result.json());
}

async function main() {
    try {
        const result = await answerOfLife().then(result => result.answer);
    } catch(e) {
        console.error(error);
    }
}
```

### Dart
```dart
import 'package:http/http.dart' as http;
import 'dart:convert';

Future<Response> answerOfLife() {
    const url = 'https://answeroflife.ai/give-it-to-me';
    return http.get(url)
        .then((response) => jsonDecode(response.body));
}

void main() async {
    try {
        const result = await answerOfLife().then(result => result.answer);
    } catch(e) {
        print(error);
    }
}
```

----

## Arrays/Lists

Dart handles arrays quite similarly to javascript, with some differences. Let's take a look at some of the most common list operations.

### Creating arrays
**Dart**
```dart
// Typed list
List<int> steps = [1, 2, 4, 8, 16, 32, 64];

// Untyped list
List stepsAndBabyNames = [1, 2, 4, 'Jonathan', 8, 'Joseph', 16, 32, 'Tommy', 64];
```

**Javascript**
```js
const steps = [1, 2, 4, 8, 16, 32, 64];
const stepsAndBabyNames = [1, 2, 4, 'Jonathan', 8, 'Joseph', 16, 32, 'Tommy', 64];
```

----

### Iterating arrays

**Dart**
```dart
// Using for-in loop
for(var step in steps) {
    print('Step: $step');
}

// Clasic for 
for(int i = 0; i < steps.length; i++) {
    print('Step: ${steps[i]}');
}

// forEach
steps.forEach((step) => print('Step: $step'));
```

**Javascript**
```js
// Using for-in loop
for(let step in steps) {
    console.log(`Step: ${step}`);
}

// Clasic for 
for(let i = 0; i < steps.length; i++) {
    console.log(`Step: ${steps[i]}`);
}

// forEach
steps.forEach((step) => console.log(`Step: $step`));
```


----


### Map items 

**Dart**
```dart
steps = steps.map((step) => step * step).toList();
```
> In dart we need to call `toList` to convert back to a List, as map returns a lazy Iterable ([docs](https://api.dart.dev/stable/1.10.1/dart-core/List/map.html)))

**Javascript**
```js
steps = steps.map((step) => step * step);
```

----


### Filter items
**Dart**
```dart
steps = steps.where((step) => step > 16).toList();
```

**Javascript**
```js
steps = steps.filter((step) => step > 16);
```

----


### Get a part of the list
**Dart**
```dart
steps.sublist(2, 4);
```

**Javascript**
```js
steps.splice(2, 4);
```

----


### Item exists
**Dart**
```dart
steps.contains(16);
```

**Javascript**
```js
steps.indexOf(16) != -1;
steps.includes(16);
```

----


### Find index of item
**Dart**
```dart
steps.indexOf(16);
```

**Javascript**
```js
steps.indexOf(16);
```

----


### Find single item
**Dart**
```dart
steps.firstWhere((step) => step == 16);
```

**Javascript**
```js
steps.find((step) => step == 16).toList();
```

----


### Has items
**Dart**
```dart
steps.isNotEmpty;
```

**Javascript**
```js
steps.length > 0;
```

----

## Maps/Objects

Most languages offer some sort of data structure to create unstructured data, dart is not different and offers the Map type.

### Creating maps
**Dart**
```dart
Map<String, dynamic> info = {
    'name': 'Samuel',
    'age': 27,
};
```

**Javascript**
```js
const info = {
    name: 'Samuel',
    age: 27,
};
```

### Serializing/Deserializing JSON
**Dart**
```dart
import 'dart:convert';

Map<String, dynamic> info = {
    'name': 'Samuel',
    'age': 27,
};

var encodedString = json.encode(info);
var decodedMap = json.decode(infoString);
```

**Javascript**
```js
const info = {
    name: 'Samuel',
    age: 27,
};

const encodedString = JSON.stringify(info);
const decodedMap = JSON.parse(infoString);
```

----

## Running an app

Running apps differs from language to language, and from framework to framework. 

### Flutter
Let's first see how we do it in flutter:
* Using the run utility in the IDE
* Executing `flutter run` in the project root

### React Native
In react native we:
* use npm script `npm run`
* or yarn `npm run`

### Angular
* Run `ng serve` in the project root
* Execute `npm start`

----

## Learning more
* [Introduction to Dart for JavaScript Developers](https://flutter.dev/docs/get-started/flutter-for/react-native-devs)
* [First flutter app](https://flutter.dev/docs/get-started/codelab#step-1-create-the-starter-flutter-app)

## Summary
As seen in the post, Javascript and Dart have quite a few things in common. But differ in some aspects, such as handling booleans or working with arrays. This post just scratches the surface so let me know if you would like a follow-up!

If you found this post useful, please consider checking [my previous post](https://dev.to/nombrekeff/flutter-styling-explained-in-css-llf-5-51nm). It's a similar format to this one but comparing the theming/styling aspects of Flutter against CSS.

{% post https://dev.to/nombrekeff/flutter-styling-explained-in-css-llf-5-51nm %}

And as always, thanks for reading. And remember to comment if you have any suggestions, doubts, or something you would like me to cover in these posts.