Scala.js for JavaScript Developers

Scala.js for JavaScript developers

Below you can see the same functionality implemented in JavaScript ES6 and Scala.js. See any differences?

ES6

const xhr = new XMLHttpRequest();

xhr.open("GET",
  "https://api.twitter.com/1.1/search/" +
  "tweets.json?q=%23scalajs"
);
xhr.onload = (e) => {
  if (xhr.status === 200) {
    const r = JSON.parse(xhr.responseText);
    $("#tweets").html(parseTweets(r));
  }
};
xhr.send();

Scala.js

val xhr = new XMLHttpRequest()

xhr.open("GET",
  "https://api.twitter.com/1.1/search/" +
  "tweets.json?q=%23scalajs"
)
xhr.onload = { (e: Event) =>
  if (xhr.status == 200) {
    val r = JSON.parse(xhr.responseText)
    $("#tweets").html(parseTweets(r))
  }
}
xhr.send()

Even though Scala language comes from a very different background than JavaScript, typical Scala code is quite understandable for JavaScript developers. This section will walk you through the differences and show you how to write basic Scala code. If you have fallen in love with the new features in ES6 like arrow functions or destructuring, you can find them all in Scala as well!

The walk-through has been split into three parts:

  • basics
  • collections
  • advanced

Each part has a lot of code examples comparing ES6 code to corresponding Scala code.


From ES6 to Scala: Basics

This is a short introduction to the Scala language for those familiar with JavaScript ES6. We are comparing to ES6 instead of earlier versions of JavaScript because ES6 contains many nice features and syntax changes that bring it closer to Scala.

The best way to experiment with Scala is to use a Scala REPL, or the worksheet functionality in the Scala IDE or IntelliJ IDEA.

The Scala language

Scala is a modern multi-paradigm programming language designed to express common programming patterns in a concise, elegant, and type-safe way. It smoothly integrates features of object-oriented and functional languages. Scala is a pure object-oriented language in the sense that every value is an object. It is also a functional language in the sense that every function is a value and that immutability is favored over mutability.

This combination of paradigms is not alien to JavaScript developers. JavaScript is also object-oriented, although primitive values are not considered as objects. It is at least partially functional as well, since functions are values and can be passed around to other functions (such as Array.prototype.map). However, although it is possible to write with an immutable mindset in JavaScript, the language does not encourage immutability.

The biggest difference to JavaScript is that Scala is statically typed. This means that it is equipped with an expressive type system that enforces statically that abstractions are used in a safe and coherent manner, meaning the compiler will catch many typical programming errors. If you have used other statically typed languages like Java or C# before you may have noticed that type definitions are all over the place. This is not true with Scala where the compiler can infer most of the types automatically.

Variables

Let’s start with something simple, variables. Both Scala and ES6 support mutable and immutable variables.

ES6

// mutable variable
let x = 5;
// immutable variable
const y = "Constant";

Scala

// mutable variable
var x = 5
// immutable variable
val y = "Constant"

Note that the Scala compiler automatically infers the types for x and y from the values that are assigned. In Scala both mutable and immutable variables must always be initialized when declared.

Primitive types

Scala defines several primitive types, of which most have corresponding types in JavaScript as well. The following table presents the most commonly used ones (there are also Byte, Short and Float).

Scala typeJavaScript typeNotes
Stringstring 
Booleanboolean 
Intnumberinteger, range (-2147483648, 2147483647)
Doublenumber64-bit floating point, fully equivalent to JS number
LongN/A64-bit integer
CharN/AUTF-16 code unit
Unitundefined 
Nullnull 

In JavaScript all numbers are represented as 64-bit floating point internally, which may give surprising results when making some calculations. In Scala calculations are always performed using the types of operands, so dividing an Int with another Int, the result is rounded to an Int.

ES6

const x = 5 / 3; // == 1.6666666666666667

Scala

val x = 5 / 3 // == 1
val y = 5.0 / 3 // == 1.6666666666666667
val z = 5 / 3.0 // == 1.6666666666666667

Because in JavaScript every number is a number there is no need to do type conversions. In Scala, however, it is an error if you try to assign a higher precision value to a lower precision variable. You must explicitly convert it using an appropriate function.

Scala

val x: Double = 3 // Ok!
val y: Int = 3.5 // Compile error
val z: Int = 3.5.toInt // Ok!
val a: Int = x // Compile error
val b: Int = x.toInt // Ok!

Functions

Defining functions is quite similar in both languages. You just replace the function keyword with def, and add types for the parameters and the result type. Speaking of which, this is about the only place you will explicitly write types in Scala. The types of local values inside functions are usually inferred by the compiler. Actually, even the result type will usually be inferred too, but it is good practice to explicitly define it, to help catch potential type errors.

Note that there is no need for a return keyword: the last expression in the function is automatically used as the return value.

ES6

function mult(x, y) {
  return x * y;
}

Scala

def mult(x: Double, y: Double): Double = x * y

Anonymous functions

In functional programming you quite often need to provide a function as a parameter, but you don’t need it elsewhere so it can be anonymous. Both languages support the nice “fat arrow” notation for defining anonymous functions conveniently.

ES6

const f = (x, y) => x + y;

const p = ["Fox", "jumped", "over", "me"];
const l = p.map(s => s.length)
  .reduce((a, b) => a + b, 0); // == 15

Scala

val f = (x: Double, y: Double) => x + y

val p = Array("Fox", "jumped", "over", "me")
val l = p.map(s => s.length)
  .foldLeft(0)((a, b) => a + b) // == 15

Default, named and rest parameters

You can also define default values for parameters if they are not supplied when the function is called. For variable number of parameters, you can access those as a Seq (see the collections part of this tour for more info). Named parameters work just as you would expect in Scala, whereas in ES6 you need to supply them with the object notation.

ES6

// default value
function mult(x, y = 42.0) {
  return x * y;
}

// variable number of parameters
function sum(...args) {
  return args.reduce((a, b) => a + b, 0);
}

const s = sum(5, 4, 3, 2, 1); // == 15

// named parameters
function vec({x = 0, y = 0, z = 0}) {
  return new Vec(x, y, z);
}

const v = vec({x: 8, z: 42}); // Vec(8, 0, 42)

Scala

// default value
def mult(x: Double, y: Double = 42.0): Double =
  x * y


// variable number of parameters
def sum(args: Double*): Double =
  args.foldLeft(0.0)((a, b) => a + b)


val s = sum(5, 4, 3, 2, 1) // == 15

// named parameters (works directly)
def vec(x: Int = 0, y: Int = 0, z: Int = 0): Vec =
  new Vec(x, y, z)


val v = vec(8, z = 42) // Vec(8, 0, 42)

Again, the Scala compiler can infer all the required types in the code above, including the parameters for the anonymous function given to the foldLeft function.

if, while, for, match control structures

As you would expect, Scala has the regular if-else and while control structures found in most programming languages. The big difference to JavaScript is that if statements are actually expressions returning a value. In JavaScript you have the special a ? b : c construct to achieve the same result.

ES6

const res = (name === "") ? 0 : 1;

Scala

val res = if (name == "") 0 else 1

The for construct in Scala is quite different from the for-loop in JavaScript and also much more powerful. You can use it to iterate over numerical ranges or collections in both languages:

ES6

let x = 0;
for (let i = 0; i < 100; i++)
  x += i * i;

const p = ["Fox", "jumped", "over", "me"];
for (let s of p) {
  console.log(`Word ${s}`);
}

Scala

var x = 0
for (i <- 0 until 100)
  x += i * i

val p = Array("Fox", "jumped", "over", "me")
for (s <- p) {
  println(s"Word $s")
}

In case you have nested for-loops, you can easily combine them into one for-comprehension in Scala. Inside the for you can even filter using if expressions. In Scala a for-comprehension is just syntactic sugar for a series of flatMap, map and withFilter calls making it very handy when dealing with Scala collections.

ES6

function findPairs(n, sum) {
  for (let i = 0; i < n; i++) {
    for (let j = i; j < n; j++) {
      if (i + j == sum)
        console.log(`Found pair ${i}, ${j}`);
    }
  }
};
findPairs(20, 31);

Scala

def findPairs(n: Int, sum: Int): Unit = {
  for {
    i <- 0 until n
    j <- i until n if i + j == sum
  } println(s"Found pair $i, $j")
}
findPairs(20, 31)

The code above also serves as an example for string interpolation (in Scala) and template strings (in ES6). Both make it easier to construct strings using variables or function calls. In Scala you don’t need to enclose the variable in {} if it’s just a simple variable name. For more complex cases you’ll need to use the s"Length = ${data.length}" syntax.

Finally the match construct provides pattern matching capabilities in Scala. Pattern matching is a complex topic covered in more detail in the advanced section of this article, so here we just focus on the simple use cases like replacing JavaScript switch/case with it.

ES6

const animal = "Dog";
let description;
switch(animal) {
  case "Cat":
  case "Lion":
  case "Tiger":
    description = "It's feline!";
    break;
  case "Dog":
  case "Wolf":
    description = "It's canine!";
    break;
  default:
    description = "It's something else";
}
console.log(description);

Scala

val animal = "Dog"
val description = animal match {
  case "Cat" | "Lion" | "Tiger" =>
    "It's feline!"
  case "Dog" | "Wolf" =>
    "It's canine!"
  case _ =>
    "It's something else"
}
println(description)

In Scala you can use the |-operator to match multiple choices and there is no need (nor support) for break, as cases never fall through like they do in JavaScript. For the default case, use the ubiquitous _ syntax (it has many many more uses in Scala!) As with if, a match is an expression returning a value that you can directly assign to a variable.

Classes

Being an object-oriented language, Scala naturally supports classes with inheritance. In addition to basic classes Scala also has:

  • case classes for conveniently storing data
  • objects for singletons
  • traits for defining interfaces and mixins

Let us look at a simple class hierarchy in both languages.

ES6

class Shape {
  constructor(x, y) {
    this.x = x;
    this.y = y;
  }

  move(dx, dy) {
    this.x += dx;
    this.y += dy;
  }

  draw() {
    console.log(`Shape at ${this.x}, ${this.y}`);
  }
};

class Circle extends Shape {
  constructor(x, y, r) {
    super(x, y);
    this.r = r;
  }

  draw() {
    console.log(`Circle at ${this.x}, ${this.y} with radius ${this.r}`);
  }
}

const c = new Circle(5, 5, 42);
const r = c.r; // == 42

Scala

// use var to make coordinates mutable
abstract class Shape(var x: Int, var y: Int) {
  def move(dx: Int, dy: Int): Unit = {
    x += dx
    y += dy
  }

  def draw(): Unit = {
    println(s"Shape at $x, $y")
  }
}

// r is immutable but accessible outside the class
class Circle(x: Int, y: Int, val r: Int)
    extends Shape(x, y) {
  override def draw(): Unit = {
    println(s"Circle at $x, $y with radius $r")
  }
}

val c = new Circle(5, 5, 42)
val r = c.r // == 42

Note that this is typically omitted in Scala, since the compiler can tell that x, y and r are properties of the enclosing class (and not local variables).

Case classes

Case classes are a particular kind of class in Scala which have a lot of compiler-generated goodies. They are particularly suited for immutable data containers whose instances are equal if and only if their fields are pairwise equal. They also automatically receive a sensible toString() representation, and they can be instantiated without the new keyword.

JavaScript doesn’t quite have a similar construct, but whenever you would use the regular object notation, consider using a case class instead.

ES6

const person = {first: "James", last: "Bond"};

Scala

case class Person(first: String, last: String)

val person = Person("James", "Bond")

Case classes enforce type safety and prevent constructing invalid objects with missing fields.

The Scala compiler automatically generates a proper equals method for case classes, making comparing them trivial. In ES6 you would typically go for a library like lodash to avoid writing the complex comparison code yourself.

ES6

const o1 = {a: 1, x: "test"};
const o2 = {a: 1, x: "test"};

if (o1 != o2) {
  // this doesn't work as expected
  console.log("They are not equal!");
}

if (_.isEqual(o1, o2)) {
  console.log("They are equal!");
}

Scala

case class AX(a: Int, x: String)

val o1 = AX(1, "test")
val o2 = AX(1, "test")
if (o1 == o2) {
  println("They are equal!")
}

Fields in case classes are public and immutable by default (unless you define them with var modifier) so you cannot make changes to instances. Instead of modifying the instance you make a copy and modify one or more fields during the copy. Scala provides a suitable copy function for each case class automatically. In ES6 you can use Object.assign to achieve the same result.

ES6

const o1 = {a: 1, x: "test"};

// start with empty object to prevent
// modification of o1
const o2 = Object.assign({}, o1, {a: 42});

Scala

case class AX(a: Int, x: String)

val o1 = AX(1, "test")
val o2 = o1.copy(a = 42)

Finally case classes can be used nicely in pattern matching, which is covered in the advanced section.

Objects

An object is a special class with only a single instance: a singleton. JavaScript also has a singleton design pattern (or actually several) even though the language itself does not have direct support for the concept. Singletons are useful for putting stuff in a shared namespace without polluting the global scope.

ES6

const RandomGen = {
  _privateMethod() {
    console.log("I am private");
  },

  _rnd() {
    return Math.random()
  },

  publicMethod() {
    console.log("The public can see me!");
    this._privateMethod();
  },

  name: "RandomGen",

  getRandomNumber() {
    return this._rnd()
  }
}

const r = RandomGen.getRandomNumber();

Scala

import scala.util.Random

object RandomGen {
  private def privateMethod(): Unit = {
    println("I am private")
  }

  private val rnd = new Random()

  def publicMethod(): Unit = {
    println("The public can see me!")
    privateMethod()
  }

  val name = "RandomGen"

  def getRandomNumber: Double = rnd.nextDouble()
}

val r = RandomGen.getRandomNumber

As you can see, defining singleton objects in Scala is quite trivial thanks to the native support in the language.

Another common use for objects in Scala is using them as companion objects for classes to store static variables and methods shared by all instances of the class.

Traits

Scala traits are similar to the mixin design pattern in JavaScript by allowing developer to define behaviors for class composition. Because of Scala’s strict type system, traits are commonly used to describe common interfaces for a group of implementation classes. JavaScript itself has no need for interfaces, but some extensions like TypeScript support them for the same purpose as Scala.

ES6

class Circle extends Shape {
  constructor(x, y, r) {
    super(x, y);
    this.r = r;
  }

  draw() {
    console.log(`Circle at ${this.x}, ${this.y} with radius ${this.r}`);
  }
}

const Clickable = {
  onClick() {
    console.log("Clicked!");
  }
};

class ClickableCircle extends Circle {}
Object.assign(ClickableCircle.prototype, Clickable);

const cc = new ClickableCircle(0, 0, 42);
cc.onClick();

Scala

class Circle(x: Int, y: Int, val r: Int)
    extends Shape(x, y) {
  override def draw(): Unit = {
    println(s"Circle at $x, $y with radius $r")
  }
}

trait Clickable {
  def onClick(): Unit = {
    println("Clicked!")
  }
}

class ClickableCircle(x: Int, y: Int, r: Int)
    extends Circle(x, y, r) with Clickable

val cc = new ClickableCircle(0, 0, 42)
cc.onClick()

Note that there are many ways for defining mixins in JavaScript, using Object.assign is just one of them supported by ES6.

Option, the type safe undefined

The notorious undefined type in JavaScript can be a blessing or a curse. On the other hand it makes life easy by allowing you to drop function parameters or leave variables undefined. But then it also masks many errors and makes you write extra code to check for undefined. Quite often undefined is used to make a distinction between an existing value (of any type) and a missing value.

Scala doesn’t have undefined (it does have null but its use is discouraged), but instead it has an Option trait for representing optional values. In Scala.js the undefined type exists to support interoperability with JS libraries, but even there it is recommended to use Option whenever possible.

Option[A] is a container for an optional value of type A (note that Option[A] is Scala’s notation for type parameters, which most programming languages, including TypeScript, write as Option<A>). If the value of type A is present, the Option[A] is an instance of Some[A], containing the present value of type A. If the value is absent, the Option[A] is the object None.

ES6

function log(msg, context) {
  let s;
  if (context !== undefined)
    s = `[${context}] ${msg}`;
  else
    s = msg;
  console.log(s);
};

// produces: First message
log("First message");
// produces: [debug] Second message
log("Second message", "debug");

Scala

def log(msg: String,
    context: Option[String] = None): Unit = {
  val s = context match {
    case Some(c) => s"[$c] $msg"
    case None => msg
  }
  println(s)
}

log("First message")
log("Second message", Some("debug"))

Pattern matching works nicely with Option, but there are more powerful ways to use it. Let’s rewrite the previous function another way giving us the same result.

Scala

def log(msg: String, context: Option[String] = None): Unit = {
  val s = context.map(c => s"[$c] $msg").getOrElse(msg)
  println(s)
}

Whoa, quite a reduction in code size! Next let’s see how we can process a sequence of option values.

ES6

const data = [1, 2, 3, undefined, 5, undefined, 7];
const res = data.filter((x) => x !== undefined);

Scala

val data = Array(Some(1), Some(2), Some(3),
  None, Some(5), None, Some(7))
val res = data.filter(x => x.isDefined)

Option provides many collection like methods like map, filter and flatMap


From ES6 to Scala: Collections

In JavaScript there are basically two kinds of collections you have used to store your data: the Array for sequential data and Object (aka dictionary or hash map) for storing key-value pairs. Furthermore both of these are mutable by default, so if you pass them to a function, that function might go and modify them without your knowledge.

ES6 extends your options with four new collection types Map, Set, WeakMap and WeakSet. Of these the WeakMap and WeakSet are for special purposes only, so in your application you would typically use only Map and Set.

Scala collection hierarchy

Unlike JavaScript, the Scala standard library has a huge variety of different collection types to choose from. Furthermore the collections are organized in a type hierarchy, meaning they share a lot of common functionality and interfaces. The high-level hierarchy for the abstract base classes and traits is shown in the image below.

Scala collection hierarchy

Scala provides immutable and mutable implementations for all these collection types.

Common immutable collections
SeqList, Vector, Stream, Range
MapHashMap, TreeMap
SetHashSet, TreeSet
Common mutable collections
SeqBuffer, ListBuffer, Queue, Stack
MapHashMap, LinkedHashMap
SetHashSet

Comparing to JavaScript

Let’s start with familiar things and see how Scala collections compare with the JavaScript Array and Object (or Map). The closest match for Array would be the mutable Buffer since arrays in Scala cannot change size after initialization. For Object (or Map) the best match is the mutable HashMap.

A simple example of array manipulation.

ES6

const a = ["Fox", "jumped", "over"];
a.push("me"); // Fox jumped over me
a.unshift("Red"); // Red Fox jumped over me
const fox = a[1];
a[a.length - 1] = "you"; // Red Fox jumped over you
console.log(a.join(" "));

Scala

import scala.collection.mutable
val a = mutable.Buffer("Fox", "jumped", "over")
a.append("me") // Fox jumped over me
a.prepend("Red") // Red Fox jumped over me
val fox = a(1)
a(a.length - 1) = "you" // Red Fox jumped over you
println(a.mkString(" "))

Working with a hash map (or Object).

ES6

const p = {first: "James", last: "Bond"};
p["profession"] = "Spy";
const name = `${p.first} ${p.last}`

Scala

import scala.collection.mutable
val p = mutable.HashMap("first" -> "James",
  "last" -> "Bond")
p("profession") = "Spy"
val name = s"${p("first")} ${p("last")}"

Even though you can use Scala collections like you would use arrays and objects in JavaScript, you really shouldn’t, because you are missing a lot of great functionality.

Common collections Seq, Map, Set and Tuple

For 99% of the time you will be working with those four common collection types in your code. You will instantiate implementation collections like Vector or HashMap, but in your code you don’t really care what the implementation is, as long as it behaves like a Seq or a Map.

Tuple

You may have noticed that Tuple is not shown in the collection hierarchy above, because it’s a very specific collection type of its own. Scala tuple combines a fixed number of items together so that they can be passed around as a whole. A tuple is immutable and can hold different types, so it’s quite close to an anonymous case class in that sense. Tuples are used in situations where you need to group items together, like key and value in a map, or to return multiple values. In JavaScript you can use a fixed size array to represent a tuple.

ES6

const t = ["James", "Bond", 42];
const kv = ["key", 42];

function sumProduct(s) {
  let sum = 0;
  let product = 1;
  for(let i of s) {
    sum += i;
    product *= i;
  }
  return [sum, product];
}

Scala

val t = ("James", "Bond", 42)
val kv = "key" -> 42 // same as ("key", 42)

def sumProduct(s: Seq[Int]): (Int, Int) = {
  var sum = 0
  var product = 1
  for(i <- s) {
    sum += i
    product *= i
  }
  (sum, product)
}

To access values inside a tuple, use the tuple._1 syntax, where the number indicates position within the tuple (starting from 1, not 0). Quite often you can also use destructuring to extract the values.

ES6

const sc = sumProduct([1, 2, 3]);
const sum = sc[0];
const product = sc[1];

// with destructuring
const [sum, product] = sumProduct([1, 2, 3]);

Scala

val sc = sumProduct(Seq(1, 2, 3))
val sum = sc._1
val product = sc._2

// with destructuring
val (sum, product) = sumProduct(Seq(1, 2, 3))

Seq

Seq is an ordered sequence. Typical implementations include List, Vector, Buffer and Range. Although Scala Array is not a Seq, it can be wrapped into a WrappedArray to enable all Seq operations on arrays. In Scala this is done automatically through an implicit conversion, allowing you to write code like following.

Scala

val ar = Array(1, 2, 3, 4)
val product = ar.foldLeft(1)((a, x) => a * x) // foldLeft comes from WrappedArray

The Seq trait exposes many methods familiar to the users of JavaScript arrays, including foreach, map, filter, slice and reverse. In addition to these, there are several more useful methods shown with examples in the code block below.

Scala

val seq = Seq(1, 2, 3, 4, 5)
seq.isEmpty == false
seq.contains(6) == false // JS Array.includes()
seq.forall(x => x > 0) == true // JS Array.every()
seq.exists(x => x % 3 == 0) == true // JS Array.some()
seq.find(x => x > 3) == Some(4) // JS Array.find()
seq.head == 1
seq.tail == Seq(2, 3, 4, 5)
seq.last == 5
seq.init == Seq(1, 2, 3, 4)
seq.drop(2) == Seq(3, 4, 5) // JS Array.slice()
seq.dropRight(2) == Seq(1, 2, 3)
seq.count(x => x < 3) == 2
seq.groupBy(x => x % 2) == Map(1 -> Seq(1, 3, 5), 0 -> Seq(2, 4))
seq.sortBy(x => -x) == Seq(5, 4, 3, 2, 1)
seq.partition(x => x > 3) == (Seq(4, 5), Seq(1, 2, 3))
seq :+ 6 == Seq(1, 2, 3, 4, 5, 6)
seq ++ Seq(6, 7) == Seq(1, 2, 3, 4, 5, 6, 7) // JS Array.concat()

The functionality offered by Array.reduce in JavaScript is covered by two distinct methods in Scala: reduceLeft and foldLeft. The difference is that in foldLeft you provide an initial (“zero”) value (which is an optional parameter to Array.reduce) while in reduceLeft you don’t. Also note that in foldLeft, the type of the accumulator can be something else, for example a tuple, but in reduceLeft it must always be a supertype of the value. Since reduceLeft cannot deal with an empty collection, it is rarely useful.

ES6

function sumProduct(s) {
  // destructuring works in the function argument
  return s.reduce(([sum, product], x) =>
    [sum + x, product * x],
    [0, 1] // use an array to represent a tuple
  );
}

Scala

def sumProduct(s: Seq[Int]): (Int, Int) = {
  // use a tuple accumulator to hold sum and product
  s.foldLeft((0, 1)) { case ((sum, product), x) =>
    (sum + x, product * x)
  }
}

Map

A Map consists of pairs of keys and values. Both keys and values can be of any valid Scala type, unlike in JavaScript where an Object may only contain string or symbol keys (the new ES6 Map allows using other types as keys, but supports only referential equality for comparing keys).

JavaScript Object doesn’t really have methods for using it as a map, although you can iterate over the keys with Object.keys. When using Object as a map, most developers use utility libraries like lodash to get access to suitable functionality. The ES6 Map object contains keys, values and forEach methods for accessing its contents, but all transformation methods are missing.

You can build a map directly or from a sequence of key-value pairs.

ES6

// object style map
const m = {first: "James", last: "Bond"};
// ES6 Map
const data = [["first", "James"], ["last", "Bond"]];
const m2 = new Map(data);

Scala

val m = Map("first" -> "James", "last" -> "Bond")
val data = Seq("first" -> "James", "last" -> "Bond")
val m2 = Map(data:_*)

In Scala when a function expects a variable number of parameters (like the Map constructor), you can destructure a sequence with the seq:_* syntax, which is the equivalent of ES6’s spread operator ...seq.

Accessing Map contents can be done in many ways.

ES6

// object syntax
const name = `${m.last}, ${m.first} ${m.last}`
// ES6 Map syntax
const name2 = `${m2.get("last")}, ${m2.get("first")} ${m2.get("last")}`
// use default value when missing
const age = m.age === undefined ? "42" : m.age;
// check all fields are present
const person = m.first !== undefined &&
  m.last !== undefined &&
  m.age !== undefined ? `${m.last}, ${m.first}: ${m.age}` :
  "missing";

Scala

val name = s"${m("last")}, ${m("first")} ${m("last")}"
// use default value when missing
val age = m.getOrElse("age", "42")
// check all fields are present
val person = (for {
  first <- m.get("first")
  last <- m.get("last")
  age <- m.get("age")
} yield {
  s"$last, $first: $age"
}).getOrElse("missing")

In the previous example m.get("first") returns an Option[String] indicating whether the key is present in the map or not. By using a for comprehension, we can easily extract three separate values from the map and use them to build the result. The result from for {} yield is also an Option[String] so we can use getOrElse to provide a default value.

Let’s try something more complicated. Say we need to maintain a collection of players and all their game scores. This could be represented by a Map[String, Seq[Int]]

ES6

const scores = {};

function addScore(player, score) {
  if (scores[player] === undefined)
    scores[player] = [];
  scores[player].push(score);
}

function bestScore() {
  let bestScore = 0;
  let bestPlayer = "";
  for (let player in scores) {
    const max = scores[player].reduce((a, score) =>
      Math.max(score, a)
    );
    if (max > bestScore) {
      bestScore = max;
      bestPlayer = player;
    }
  }
  return [bestPlayer, bestScore];
}

function averageScore() {
  let sum = 0;
  let count = 0;
  for (let player in scores) {
    for (let score of scores[player]) {
      sum += score;
      count++;
    }
  }
  if (count == 0)
    return 0;
  else
    return Math.round(sum / count);
}

Scala

import scala.collection.mutable

val scores =
  mutable.Map.empty[String, mutable.Buffer[Int]]

def addScore(player: String, score: Int): Unit = {
  scores.getOrElseUpdate(player, mutable.Buffer())
    .append(score)
}

def bestScore: (String, Int) = {
  val all = scores.toList.flatMap {
    case (player, pScores) =>
      pScores.map(s => (player, s))
  }
  if (all.isEmpty)
    ("", 0)
  else
    all.maxBy(_._2)
}

def averageScore: Int = {
  val allScores = scores.flatMap(_._2)
  if (allScores.isEmpty)
    0
  else
    allScores.sum / allScores.size
}

In the example above the both versions are using mutable collections. Coming from JavaScript it’s good to start with the more familiar mutable collections, but over time Scala developers tend to favor immutable versions. Immutable collections in Scala use structural sharing to minimize copying and to provide good performance. Sharing is ok, because the data is immutable!

The best score is found by first flattening the whole structure into a sequence of (player, score) pairs. Then we use the maxBy method to find the maximum score by looking at the second value in the tuple.

The average is calculated simply by flattening all scores into a single sequence and then calculating its average.

Set

A Set is like a Map without values, just the distinct keys. In JavaScript it’s typical to emulate a Set by storing the values as keys into an Object. This of course means that the values must be converted to strings. In ES6 there is a new Set type that works with all kinds of value types, but like with Map, it’s based on reference equality, making it less useful when dealing with complex value types.

As their name implies, sets have no duplicate elements. Adding values to a set automatically guarantees that all duplicate values are eliminated.

Set operations like diff, intersect and union allow you to build new sets out of other sets to check, for example, what has changed.

Scala

val set1 = Set(1, 2, 3, 4, 5)
val set2 = Set(2, 3, 5, 1, 6)
val addedValues = set2 diff set1 // Set(6)
val removedValues = set1 diff set2 // Set(4)

Note how in Scala you can also omit the . and parentheses in method calls.

Sets are also a convenient way to check for multiple values in methods like filter.

ES6

const common = {"a": true, "the": true,
  "an": true, "and": true};
const text = "The sun is a star and an energy source"
const words = text.split(" ")
  .map(s => s.toLowerCase())
  .filter(s => !common[s]);

Scala

val common = Set("a", "the", "an", "and")
val text = "The sun is a star and an energy source"
val words = text.split(" ")
  .map(_.toLowerCase)
  .filterNot(common)
// Array(sun, is, star, energy, source)

From ES6 to Scala: Advanced

Scala is a feature rich language that is easy to learn but takes time to master. Depending on your programming background, typically you start by writing Scala as you would’ve written the language you know best (JavaScript, Java or C# for example) and gradually learn more and more idiomatic Scala paradigms to use. In this section we cover some of the more useful design patterns and features, to get you started quickly.

Pattern matching

In the Basics part we already saw simple examples of pattern matching as a replacement for JavaScript’s switch statement. However, it can be used for much more, for example checking the type of input.

ES6

function printType(o) {
  switch (typeof o) {
    case "string":
      console.log(`It's a string: ${o}`);
      break;
    case "number":
      console.log(`It's a number: ${o}`);
      break;
    case "boolean":
      console.log(`It's a boolean: ${o}`);
      break;
    default:
      console.log(`It's something else`);
  }
}

Scala

def printType(o: Any): Unit = {
  o match {
    case s: String =>
      println(s"It's a string: $s")
    case i: Int =>
      println(s"It's an int: $i")
    case b: Boolean =>
      println(s"It's a boolean: $b")
    case _ =>
      println("It's something else")
}

Pattern matching uses something called partial functions which means it can be used in place of regular functions, for example in a call to filter or map. You can also add a guard clause in the form of an if, to limit the match. If you need to match to a variable, use backticks to indicate that.

ES6

function parse(str, magicKey) {
  let res = [];
  for(let c of str) {
    if (c === magicKey)
      res.push("magic");
    else if (c.match(/\d/))
      res.push("digit");
    else if (c.match(/\w/))
      res.push("letter");
    else if (c.match(/\s/))
      res.push(" ");
    else
      res.push("char");
  }
  return res;
}
const r = parse("JB/007", '/');
// [letter, letter, magic, digit, digit, digit]

Scala

def parse(str: String, magicKey: Char): Seq[String] = {
  str.map {
    case c if c == magicKey =>
      "magic"
    case c if c.isDigit =>
      "digit"
    case c if c.isLetter =>
      "letter"
    case c if c.isWhitespace =>
      " "
    case c =>
      "char"
  }
}
val r = parse("JB/007", '/')
// Seq(letter, letter, magic, digit, digit, digit)

Destructuring

Where pattern matching really shines is at destructuring. This means matching to a more complex pattern and extracting values inside that structure. ES6 also supports destructuring (yay!) in assignments and function parameters, but not in matching.

ES6

const person = {first: "James", last: "Bond", age: 42};
const {first, last, age: years} = person;
// first = "James", last = "Bond", years = 42
const seq = [1, 2, 3, 4, 5];
const [a, b, , ...c] = seq;
// a = 1, b = 2, c = [4, 5]

const seq2 = [a, b].concat(c); // [1, 2, 4, 5]

Scala

case class Person(first: String, last: String, age: Int)
val person = Person("James", "Bond", 42)
val Person(first, last, years) = person
// first = "James", last = "Bond", years = 42
val seq = Seq(1, 2, 3, 4, 5)
val Seq(a, b, _, c @ _*) = seq
// a = 1, b = 2, c = Seq(4, 5)

val seq2 = Seq(a, b) ++ c // Seq(1, 2, 4, 5)

In Scala the destructuring and rebuilding have nice symmetry making it easy to remember how to do it. Use _ to skip values in destructuring.

In pattern matching the use of destructuring results in clean, simple and understandable code.

ES6

function ageSum(persons, family) {
  return persons.filter(p => p.last === family)
    .reduce((a, p) => a + p.age, 0);
}
const persons = [
  {first: "James", last: "Bond", age: 42},
  {first: "Hillary", last: "Bond", age: 35},
  {first: "James", last: "Smith", age: 55}
];

ageSum(persons, "Bond") == 77;

Scala

def ageSum(persons: Seq[Person],
    family: String): Int = {
  persons.collect {
    case Person(_, last, age) if last == family =>
      age
  }.sum
}
val persons = Seq(
  Person("James", "Bond", 42),
  Person("Hillary", "Bond", 35),
  Person("James", "Smith", 55)
)

ageSum(persons, "Bond") == 77

We could’ve implemented the Scala function using a filter and foldLeft, but it is more understandable using collect and pattern matching. It would be read as “Collect every person with a last name equaling family and extract the age of those persons. Then sum up the ages.”

Another good use case for pattern matching is regular expressions (also in ES6!). Let’s extract a date in different formats.

ES6

function convertToDate(d) {
  const YMD = /(\d{4})-(\d{1,2})-(\d{1,2})/
  const MDY = /(\d{1,2})\/(\d{1,2})\/(\d{4})/
  const DMY = /(\d{1,2})\.(\d{1,2})\.(\d{4})/

  const [, year, month, day] = YMD.exec(d) || [];
  if (year !== undefined) {
    return {
      year: parseInt(year),
      month: parseInt(month),
      day: parseInt(day)
    };
  } else {
    const [, month, day, year] = MDY.exec(d) || [];
    if (year !== undefined) {
      return {
        year: parseInt(year),
        month: parseInt(month),
        day: parseInt(day)
      };
    } else {
      const [, day, month, year] = DMY.exec(d) || [];
      if (year !== undefined) {
        return {
          year: parseInt(year),
          month: parseInt(month),
          day: parseInt(day)
        };
      }
    }
  }
  throw new Error("Invalid date!");
}
convertToDate("2015-10-9"); //{year:2015,month:10,day:9}
convertToDate("10/9/2015"); //{year:2015,month:10,day:9}
convertToDate("9.10.2015"); //{year:2015,month:10,day:9}
convertToDate("10 Nov 2015"); // exception

Scala

case class Date(year: Int, month: Int, day: Int)

def convertToDate(d: String): Date = {
  val YMD = """(\d{4})-(\d{1,2})-(\d{1,2})""".r
  val MDY = """(\d{1,2})/(\d{1,2})/(\d{4})""".r
  val DMY = """(\d{1,2})\.(\d{1,2})\.(\d{4})""".r
  d match {
    case YMD(year, month, day) =>
      Date(year.toInt, month.toInt, day.toInt)
    case MDY(month, day, year) =>
      Date(year.toInt, month.toInt, day.toInt)
    case DMY(day, month, year) =>
      Date(year.toInt, month.toInt, day.toInt)
    case _ =>
      throw new Exception("Invalid date!")
  }
}

convertToDate("2015-10-9") // = Date(2015,10,9)
convertToDate("10/9/2015") // = Date(2015,10,9)
convertToDate("9.10.2015") // = Date(2015,10,9)
convertToDate("10 Nov 2015") // exception

Here we use triple-quoted strings that allow us to write regex without escaping special characters. The string is converted into a Regex object with the .r method. Because regexes extract strings, we need to convert matched groups to integers ourselves.

Functions revisited

We covered the basic use functions in Part 1, but Scala, being a functional programming language, provides much more when it comes to functions. Let’s explore some of the more advanced features and how they compare to JavaScript.

Higher-order functions

Scala, as JavaScript, allows the definition of higher-order functions. These are functions that take other functions as parameters, or whose result is a function. Higher-order functions should be familiar to JavaScript developers, because they often appear in form of functions that take callbacks as parameters.

Typically higher-order functions are used to pass specific functionality to a general function, like in the case of Array.prototype.filter in ES6 or Seq.filter in Scala. We can use this to build a function to calculate a minimum and maximum from a sequence of values, using a function to extract the target value.

ES6

function minmaxBy(arr, f) {
  return arr.reduce(
    ([min, max], e) => {
      const v = f(e);
      return [Math.min(min, v), Math.max(max, v)]
    }, 
    [Number.MAX_VALUE, Number.MIN_VALUE]
  )
}
const [youngest, oldest] = minmaxBy(persons, e => e.age);

Scala

def minmaxBy[T](seq: Seq[T], f: T => Int): (Int, Int) = {
  seq.foldLeft((Int.MaxValue, Int.MinValue)) {
    case ((min, max), e) =>
      val v = f(e)
      (math.min(min, v), math.max(max, v))
  }
}
val (youngest, oldest) = minmaxBy[Person](persons, _.age)

Call-by-Name

In some cases you want to defer the evaluation of a parameter value until when it’s actually used in the function. For this purpose Scala offers call-by-name parameters. This can be useful when dealing with an expensive computation that is only optionally used by the function. In JavaScript the closest thing to this is to wrap a value in an anonymous function with no arguments and pass that as a parameter, but that’s more verbose and error-prone. You need to remember to both wrap the value and call the function.

ES6

function compute(value, cPos, cNeg) {
  if (value >= 0)
    return cPos();
  else
    return cNeg();
}

compute(x, () => expCalc(), () => expCalc2());

Scala

def compute(value: Int, cPos: => Int, cNeg: => Int) = {
  if (value >= 0)
    cPos
  else
    cNeg
}

compute(x, expCalc, expCalc2)

Recursive functions

Recursive functions can be very expressive, but they may also cause spurious stack overflows if the recursion gets too deep. Scala automatically optimizes recursive functions that are tail recursive, allowing you to use them without fear of overflowing the stack. To make sure your function is actually tail recursive, use the @tailrec annotation, which will cause the Scala compiler to report an error if your function is not tail recursive.

Before ES6, JavaScript did not support tail call optimization, nor optimizing tail recursive functions. If you use a smart ES6 transpiler, it can actually convert a tail recursive function into a while loop, but there are no checks available to help you to verify the validity of tail recursion.

ES6

function fib(n) {
  function fibIter(n, next, prev) {
    if (n === 0) {
      return prev;
    } else {
      return fibIter(n - 1, next + prev, next);
    }
  };
  return fibIter(n, 1, 0);
}

Scala

def fib(n: Int): Int = {
  @tailrec 
  def fibIter(n: Int, next: Int, prev: Int): Int = {
    if (n == 0)
      prev
    else
      fibIter(n - 1, next + prev, next)
  }
  fibIter(n, 1, 0)
}

Partially applied functions

In Scala you can call a function with only some of its arguments and get back a function taking those missing arguments. You do this by using _ in place of the actual parameter. In JavaScript you can achieve the same by using the Function.prototype.bind function (although it limits you to providing parameters from left to right). For example we can define a function to create HTML tags by wrapping content within start and end tags.

ES6

function tag(name, content) {
  return `<${name}>${content}</${name}>` 
}

const div = tag.bind(null, "div");
const p = tag.bind(null, "p");
const html = div(p("test")); // <div><p>test</p></div>

Scala

def tag(name: String, content: String) = {
  s"<$name>$content</$name>"
}

val div = tag("div", _: String)
val p = tag("p", _: String)
val html = div(p("test")) // <div><p>test</p></div>

Multiple parameter lists

Scala allows a function to be defined with multiple parameter lists. In Scala this is quite common as it provides some powerful secondary benefits besides the usual currying functionality. JavaScript does not directly support multiple parameter lists in its syntax, but you can emulate it by returning a chain of functions, or by using libraries like lodash that do it for you.

Let’s use currying to define the tag function from previous example.

ES6

function tag(name) {
  return (content) => `<${name}>${content}</${name}>`; 
}

const div = tag("div");
const p = tag("p");
const html = div(p("test")); // <div><p>test</p></div>

Scala

def tag(name: String)(content: String): String = {
  s"<$name>$content</$name>"
}

val div = tag("div") _
val p = tag("p") _
val html = div(p("test")) // <div><p>test</p></div>

Multiple parameter lists also helps with type inference, meaning we don’t need to tell the compiler the types explicitly. For example we can rewrite the minmaxBy function as curried, which allows us to leave the Person type out when calling it, as it is automatically inferred from the first parameter. This is why methods like foldLeft are defined with multiple parameter lists.

Scala

def minmaxBy[T](seq: Seq[T])(f: T => Int): (Int, Int) = {
  seq.foldLeft((Int.MaxValue, Int.MinValue)) {
    case ((min, max), e) =>
      val v = f(e)
      (math.min(min, v), math.max(max, v))
  }
}
val (youngest, oldest) = minmaxBy(persons)(_.age)

Implicits

Being type safe is great in Scala, but sometimes the type system can be a bit prohibitive when you want to do something else, like add methods to existing classes. To allow you to do this in a type safe manner, Scala provides implicits. You can think of implicits as something that’s available in the scope when you need it, and the compiler can automatically provide it. For example we can provide a function to automatically convert a JavaScript Date into a Scala/Java Date.

Scala

import scalajs.js

implicit def convertFromJSDate(d: js.Date): java.util.Date = {
  new java.util.Date(d.getMilliseconds())
}

implicit def convertToJSDate(d: java.util.Date): js.Date = {
  new js.Date(d.getTime)
}

case class Person(name: String, joined: js.Date)

val p = Person("James Bond", new java.util.Date)

When these implicit conversion functions are in lexical scope, you can use JS and Scala dates interchangeably. Outside the scope they are not visible and you must use correct types or explicitly convert between each other.

Implicit conversions for “monkey patching”

The monkey patching term became famous among Ruby developers and it has been adopted into JavaScript to describe a way of extending existing classes with new methods. It has several pitfalls in dynamic languages and is generally not a recommended practice. Especially dangerous is to patch JavaScript’s host objects like String or DOM.Node. This technique is, however, commonly used to provide support for new JavaScript functionality missing from older JS engines. The practice is known as polyfilling or shimming.

In Scala providing extension methods via implicits is perfectly safe and even a recommended practice. The Scala standard library does it all the time. For example did you notice the .r or .toInt functions that were used on strings in the regex example? Both are extension methods coming from implicit classes.

Let’s use the convertToDate we defined before and add a toDate extension method to String by defining an implicit class.

ES6

String.prototype.toDate = function() {
  return convertToDate(this);
}
"2015-10-09".toDate(); // = {year:2015,month:10,day:9}

Scala

implicit class StrToDate(val s: String) {
  def toDate = convertToDate(s)
}
"2015-10-09".toDate // = Date(2015,10,9)

Note that the JavaScript version modifies the global String class (dangerous!), whereas the Scala version only introduces a conversion from String to a custom StrToDate class providing an additional method. Implicit classes are safe because they are lexically scoped, meaning the StrToDate is not available in other parts of the program unless explicitly imported. The toDate method is not added to the String class in any way, instead the compiler generates appropriate code to call it when required. Basically "2010-10-09".toDate is converted into new StrToDate("2010-10-09").toDate.

Scala IDEs are also smart enough to know what implicit extension methods are in scope and will show them to you next to the other methods.

Implicit extension methods are safe and easy to refactor. If you, say, rename or remove a method, the compiler will immediately give errors in places where you use that method. IDEs provide great tools for automatically renaming all instances when you make the change, keeping your code base operational. You can even do complex changes like add new method parameters or reorder them and the IDE can take care of the refactoring for you, safely and automatically, thanks to strict typing.

Finally we’ll make DOM’s NodeList behave like a regular Scala collection to make it easier to work with them. Or to be more accurate, we are extending DOMList[T] which provides a type for the nodes. NodeList is actually just a DOMList[Node].

Scala

implicit class NodeListSeq[T <: Node](nodes: DOMList[T]) extends IndexedSeq[T] {
  override def foreach[U](f: T => U): Unit = {
    for (i <- 0 until nodes.length) {
      f(nodes(i))
    }
  }

  override def length: Int = nodes.length

  override def apply(idx: Int): T = nodes(idx)
}

Defining just those three functions, we now have access to all the usual collection functionality like map, filter, find, slice, foldLeft, etc. This makes working with NodeLists a lot easier and safer. The implicit class makes use of Scala generics, providing implementation for all types that extend Node. Note that NodeListSeq is available as PimpedNodeList in the scala-js-dom library; just import org.scalajs.dom.ext._ to use it.

Scala

// cast to correct element type
val images = dom.document.querySelectorAll("img").asInstanceOf[NodeListOf[HTMLImageElement]]
// get all image source URLs
val urls = images.map(i => i.src)
// filter images that have "class" attribute set
val withClass = images.filter(i => i.className.nonEmpty)
// set an event listener to 10 widest images
images.sortBy(i => -i.width).take(10).foreach { i =>
  i.onclick = (e: MouseEvent) => println("Image clicked!")
}

Futures

Writing asynchronous JavaScript code used to be painful due to the number of callbacks required to handle chained asynchronous calls. This is affectionately known as callback hell. Then came the various Promise libraries that alleviated this issue a lot, but were not fully compatible with each other. ES6 standardizes the Promise interface so that all implementations (ES6’s own included) can happily coexist.

In Scala a similar concept is the Future. On the JVM, futures can be used for both parallel and asynchronous processing, but under Scala.js only the latter is possible. Like a JavaScript Promise, a Future is a placeholder object for a value that may not yet exist. Both Promise and Future can complete successfully, providing a value, or fail with an error/exception. Let’s look at a typical use case of fetching data from server using AJAX.

ES6

// using jQuery

$.ajax("http://api.openweathermap.org/" +
    "data/2.5/weather?q=Tampere").then(
   (data, textStatus, jqXHR) =>
      console.log(data)
);

Scala

import org.scalajs.dom
import dom.ext.Ajax

Ajax.get("http://api.openweathermap.org/" +
    "data/2.5/weather?q=Tampere").foreach {
  xhr =>
    println(xhr.responseText)
}

The JavaScript code above is using jQuery to provide similar helper for making Ajax calls returning promises as is available in the Scala.js DOM library.

Here is a comparison between Scala’s Future and JavaScript’s Promise for the most commonly used methods.

FuturePromiseNotes
foreach(func)then(func)Executes func for its side-effects when the future completes.
map(func)then(func)The result of func is wrapped in a new future.
flatMap(func)then(func)func must return a future.
recover(func)catch(func)Handles an error. The result of func is wrapped in a new future.
recoverWith(func)catch(func)Handles an error. func must return a future.
filter(predicate)N/ACreates a new future by filtering the value of the current future with a predicate.
zip(that)N/AZips the values of this and that future, and creates a new future holding the tuple of their results.
Future.successful(value)Promise.resolve(value)Returns a successful future containing value
Future.failed(exception)Promise.reject(value)Returns a failed future containing exception
Future.sequence(iterable)Promise.all(iterable)Returns a future that completes when all of the futures in the iterable argument have been completed.
Future.firstCompletedOf(iterable)Promise.race(iterable)Returns a future that completes as soon as one of the futures in the iterable completes.

Note that Scala has different functions corresponding to JavaScript’s then, mainly map and flatMap. then is not type-safe, because it will flatten promises “all the way down”, even if that was not your intention. In contrast, map never flattens, and flatMap always flattens once, tracking the appropriate static result type.

foreach is a slight variation of map that does not return a new future. It is typically used instead of map to communicate the intent that the callback is executed for its side-effects rather than its result value.

Futures from callbacks

Even though ES6 brought the standard promise API to browsers, all asynchronous functions still require the use of callbacks. To convert a callback into a Future in Scala you need to use a Promise. Wait, what? Yes, in addition to Future, Scala also has a Promise class which actually implements the Future trait.

As an example, let’s convert the onload event of an img tag into a Future.

ES6

function onLoadPromise(img) {
  if (img.complete) {
    return Promise.resolve(img.src);
  } else {
    const p = new Promise((success) => {
      img.onload = (e) => {
        success(img.src);
      };
    });
    return p;
  }
}

const img = document.querySelector("#mapimage");
onLoadPromise(img).then(url =>
  console.log(`Image ${url} loaded`)
);

Scala

def onLoadFuture(img: HTMLImageElement) = {
  if (img.complete) {
    Future.successful(img.src)
  } else {
    val p = Promise[String]()
    img.onload = { (e: Event) =>
      p.success(img.src)
    }
    p.future
  }
}

val img = dom.document.querySelector("#mapimage")
  .asInstanceOf[HTMLImageElement]
onLoadFuture(img).foreach { url =>
  println(s"Image $url loaded")
}

Because the image might have already loaded when we create the promise, we must check for that separately and just return a completed future in that case.

Next we’ll add an onloadF extension method to the HTMLImageElement class, to make it really easy to use the futurized version.

Scala

implicit class HTMLImageElementOps(val img: HTMLImageElement) extends AnyVal {
  def onloadF = onLoadFuture(img)
}

val img = dom.document.querySelector("#mapimage").asInstanceOf[HTMLImageElement]
img.onloadF.foreach { url =>
  println(s"Image $url loaded")
}

While we are playing with DOM images, let’s create a future that completes once all the images on the page have finished loading. Here we’ll take advantage of the NodeListSeq extension class to provide us with the map method on the NodeList returned from querySelectorAll.

Scala

val images = dom.document.querySelectorAll("img").asInstanceOf[NodeListOf[HTMLImageElement]]
val loaders = images.map(i => i.onloadF)

Future.sequence(loaders).foreach { urls =>
  println(s"All ${urls.size} images loaded!")
}

 

Original article source at https://www.scala-js.org

#javascript #scala

What is GEEK

Buddha Community

Scala.js for JavaScript Developers

Ajay Kapoor

1626321063

JS Development Company India | JavaScript Development Services

PixelCrayons: Our JavaScript web development service offers you a feature-packed & dynamic web application that effectively caters to your business challenges and provide you the best RoI. Our JavaScript web development company works on all major frameworks & libraries like Angular, React, Nodejs, Vue.js, to name a few.

With 15+ years of domain expertise, we have successfully delivered 13800+ projects and have successfully garnered 6800+ happy customers with 97%+ client retention rate.

Looking for professional JavaScript web app development services? We provide custom JavaScript development services applying latest version frameworks and libraries to propel businesses to the next level. Our well-defined and manageable JS development processes are balanced between cost, time and quality along with clear communication.

Our JavaScript development companies offers you strict NDA, 100% money back guarantee and agile/DevOps approach.

#javascript development company #javascript development services #javascript web development #javascript development #javascript web development services #javascript web development company

Hire Dedicated JavaScript Developers -Hire JavaScript Developers

It is said that a digital resource a business has must be interactive in nature, so the website or the business app should be interactive. How do you make the app interactive? With the use of JavaScript.

Does your business need an interactive website or app?

Hire Dedicated JavaScript Developer from WebClues Infotech as the developer we offer is highly skilled and expert in what they do. Our developers are collaborative in nature and work with complete transparency with the customers.

The technology used to develop the overall app by the developers from WebClues Infotech is at par with the latest available technology.

Get your business app with JavaScript

For more inquiry click here https://bit.ly/31eZyDZ

Book Free Interview: https://bit.ly/3dDShFg

#hire dedicated javascript developers #hire javascript developers #top javascript developers for hire #hire javascript developer #hire a freelancer for javascript developer #hire the best javascript developers

NBB: Ad-hoc CLJS Scripting on Node.js

Nbb

Not babashka. Node.js babashka!?

Ad-hoc CLJS scripting on Node.js.

Status

Experimental. Please report issues here.

Goals and features

Nbb's main goal is to make it easy to get started with ad hoc CLJS scripting on Node.js.

Additional goals and features are:

  • Fast startup without relying on a custom version of Node.js.
  • Small artifact (current size is around 1.2MB).
  • First class macros.
  • Support building small TUI apps using Reagent.
  • Complement babashka with libraries from the Node.js ecosystem.

Requirements

Nbb requires Node.js v12 or newer.

How does this tool work?

CLJS code is evaluated through SCI, the same interpreter that powers babashka. Because SCI works with advanced compilation, the bundle size, especially when combined with other dependencies, is smaller than what you get with self-hosted CLJS. That makes startup faster. The trade-off is that execution is less performant and that only a subset of CLJS is available (e.g. no deftype, yet).

Usage

Install nbb from NPM:

$ npm install nbb -g

Omit -g for a local install.

Try out an expression:

$ nbb -e '(+ 1 2 3)'
6

And then install some other NPM libraries to use in the script. E.g.:

$ npm install csv-parse shelljs zx

Create a script which uses the NPM libraries:

(ns script
  (:require ["csv-parse/lib/sync$default" :as csv-parse]
            ["fs" :as fs]
            ["path" :as path]
            ["shelljs$default" :as sh]
            ["term-size$default" :as term-size]
            ["zx$default" :as zx]
            ["zx$fs" :as zxfs]
            [nbb.core :refer [*file*]]))

(prn (path/resolve "."))

(prn (term-size))

(println (count (str (fs/readFileSync *file*))))

(prn (sh/ls "."))

(prn (csv-parse "foo,bar"))

(prn (zxfs/existsSync *file*))

(zx/$ #js ["ls"])

Call the script:

$ nbb script.cljs
"/private/tmp/test-script"
#js {:columns 216, :rows 47}
510
#js ["node_modules" "package-lock.json" "package.json" "script.cljs"]
#js [#js ["foo" "bar"]]
true
$ ls
node_modules
package-lock.json
package.json
script.cljs

Macros

Nbb has first class support for macros: you can define them right inside your .cljs file, like you are used to from JVM Clojure. Consider the plet macro to make working with promises more palatable:

(defmacro plet
  [bindings & body]
  (let [binding-pairs (reverse (partition 2 bindings))
        body (cons 'do body)]
    (reduce (fn [body [sym expr]]
              (let [expr (list '.resolve 'js/Promise expr)]
                (list '.then expr (list 'clojure.core/fn (vector sym)
                                        body))))
            body
            binding-pairs)))

Using this macro we can look async code more like sync code. Consider this puppeteer example:

(-> (.launch puppeteer)
      (.then (fn [browser]
               (-> (.newPage browser)
                   (.then (fn [page]
                            (-> (.goto page "https://clojure.org")
                                (.then #(.screenshot page #js{:path "screenshot.png"}))
                                (.catch #(js/console.log %))
                                (.then #(.close browser)))))))))

Using plet this becomes:

(plet [browser (.launch puppeteer)
       page (.newPage browser)
       _ (.goto page "https://clojure.org")
       _ (-> (.screenshot page #js{:path "screenshot.png"})
             (.catch #(js/console.log %)))]
      (.close browser))

See the puppeteer example for the full code.

Since v0.0.36, nbb includes promesa which is a library to deal with promises. The above plet macro is similar to promesa.core/let.

Startup time

$ time nbb -e '(+ 1 2 3)'
6
nbb -e '(+ 1 2 3)'   0.17s  user 0.02s system 109% cpu 0.168 total

The baseline startup time for a script is about 170ms seconds on my laptop. When invoked via npx this adds another 300ms or so, so for faster startup, either use a globally installed nbb or use $(npm bin)/nbb script.cljs to bypass npx.

Dependencies

NPM dependencies

Nbb does not depend on any NPM dependencies. All NPM libraries loaded by a script are resolved relative to that script. When using the Reagent module, React is resolved in the same way as any other NPM library.

Classpath

To load .cljs files from local paths or dependencies, you can use the --classpath argument. The current dir is added to the classpath automatically. So if there is a file foo/bar.cljs relative to your current dir, then you can load it via (:require [foo.bar :as fb]). Note that nbb uses the same naming conventions for namespaces and directories as other Clojure tools: foo-bar in the namespace name becomes foo_bar in the directory name.

To load dependencies from the Clojure ecosystem, you can use the Clojure CLI or babashka to download them and produce a classpath:

$ classpath="$(clojure -A:nbb -Spath -Sdeps '{:aliases {:nbb {:replace-deps {com.github.seancorfield/honeysql {:git/tag "v2.0.0-rc5" :git/sha "01c3a55"}}}}}')"

and then feed it to the --classpath argument:

$ nbb --classpath "$classpath" -e "(require '[honey.sql :as sql]) (sql/format {:select :foo :from :bar :where [:= :baz 2]})"
["SELECT foo FROM bar WHERE baz = ?" 2]

Currently nbb only reads from directories, not jar files, so you are encouraged to use git libs. Support for .jar files will be added later.

Current file

The name of the file that is currently being executed is available via nbb.core/*file* or on the metadata of vars:

(ns foo
  (:require [nbb.core :refer [*file*]]))

(prn *file*) ;; "/private/tmp/foo.cljs"

(defn f [])
(prn (:file (meta #'f))) ;; "/private/tmp/foo.cljs"

Reagent

Nbb includes reagent.core which will be lazily loaded when required. You can use this together with ink to create a TUI application:

$ npm install ink

ink-demo.cljs:

(ns ink-demo
  (:require ["ink" :refer [render Text]]
            [reagent.core :as r]))

(defonce state (r/atom 0))

(doseq [n (range 1 11)]
  (js/setTimeout #(swap! state inc) (* n 500)))

(defn hello []
  [:> Text {:color "green"} "Hello, world! " @state])

(render (r/as-element [hello]))

Promesa

Working with callbacks and promises can become tedious. Since nbb v0.0.36 the promesa.core namespace is included with the let and do! macros. An example:

(ns prom
  (:require [promesa.core :as p]))

(defn sleep [ms]
  (js/Promise.
   (fn [resolve _]
     (js/setTimeout resolve ms))))

(defn do-stuff
  []
  (p/do!
   (println "Doing stuff which takes a while")
   (sleep 1000)
   1))

(p/let [a (do-stuff)
        b (inc a)
        c (do-stuff)
        d (+ b c)]
  (prn d))
$ nbb prom.cljs
Doing stuff which takes a while
Doing stuff which takes a while
3

Also see API docs.

Js-interop

Since nbb v0.0.75 applied-science/js-interop is available:

(ns example
  (:require [applied-science.js-interop :as j]))

(def o (j/lit {:a 1 :b 2 :c {:d 1}}))

(prn (j/select-keys o [:a :b])) ;; #js {:a 1, :b 2}
(prn (j/get-in o [:c :d])) ;; 1

Most of this library is supported in nbb, except the following:

  • destructuring using :syms
  • property access using .-x notation. In nbb, you must use keywords.

See the example of what is currently supported.

Examples

See the examples directory for small examples.

Also check out these projects built with nbb:

API

See API documentation.

Migrating to shadow-cljs

See this gist on how to convert an nbb script or project to shadow-cljs.

Build

Prequisites:

  • babashka >= 0.4.0
  • Clojure CLI >= 1.10.3.933
  • Node.js 16.5.0 (lower version may work, but this is the one I used to build)

To build:

  • Clone and cd into this repo
  • bb release

Run bb tasks for more project-related tasks.

Download Details:
Author: borkdude
Download Link: Download The Source Code
Official Website: https://github.com/borkdude/nbb 
License: EPL-1.0

#node #javascript

Hire Dedicated Node.js Developers - Hire Node.js Developers

If you look at the backend technology used by today’s most popular apps there is one thing you would find common among them and that is the use of NodeJS Framework. Yes, the NodeJS framework is that effective and successful.

If you wish to have a strong backend for efficient app performance then have NodeJS at the backend.

WebClues Infotech offers different levels of experienced and expert professionals for your app development needs. So hire a dedicated NodeJS developer from WebClues Infotech with your experience requirement and expertise.

So what are you waiting for? Get your app developed with strong performance parameters from WebClues Infotech

For inquiry click here: https://www.webcluesinfotech.com/hire-nodejs-developer/

Book Free Interview: https://bit.ly/3dDShFg

#hire dedicated node.js developers #hire node.js developers #hire top dedicated node.js developers #hire node.js developers in usa & india #hire node js development company #hire the best node.js developers & programmers

sophia tondon

sophia tondon

1621250665

Top React JS Development Company | React JS Development Services

Looking to hire dedicated top Reactjs developers at affordable prices? Our 5+ years of average experienced Reactjs developers comprise proficiency in delivering the most complex and challenging web apps.

Hire ReactJS developers online on a monthly, hourly, or full-time basis who are highly skilled & efficient in implementing new technologies and turn into business-driven applications while saving your cost up to 60%.

Planning to** outsource React web Development services from India** using Reactjs? Or would you like to hire a team of Reactjs developers? Get in touch for a free quote!

#hire react js developer #react.js developer #react.js developers #hire reactjs development company #react js development india #react js developer