- Function declarations
- Arrow functions
- Function expressions
- Default parameters
- Rest parameters
- arguments Object
- Tagged template literals
- Closures
- Recursion
- Higher-order functions
- Hoisting
- Classes
- Next steps
Part of the Scripting Language reference.
Function declarations
function greet(name) {
return "Hello, " + name + "!"
}
log(greet("Alice")) // => Hello, Alice!
Arrow functions
let double = (x) => x * 2
log(double(5)) // => 10
let add = (a, b) => a + b
log(add(3, 4)) // => 7
// Multi-line arrow with block body
let factorial = (n) => {
if (n <= 1) return 1
return n * factorial(n - 1)
}
log(factorial(5)) // => 120
Single-parameter arrows do not require parentheses:
let square = x => x * x
log(square(4)) // => 16
No-parameter arrows require empty parentheses:
let greet = () => "Hello!"
log(greet()) // => Hello!
Function expressions
Functions can be used as expressions - assigned to variables, passed as arguments, or used inline.
Anonymous function expression:
const double = function(x) { return x * 2 }
log(double(5)) // => 10
Named function expression - the name is only visible inside the function body (useful for recursion):
const f = function fact(n) {
return n <= 1 ? 1 : n * fact(n - 1)
}
log(f(5)) // => 120
log(typeof fact) // => undefined (name not visible outside)
Async function expression:
const fetchVal = async function(x) { return await Promise.resolve(x) }
log(await fetchVal(42)) // => 42
IIFE (Immediately Invoked Function Expression):
const result = (function(x) { return x + x })(10)
log(result) // => 20
Function expressions can be used in any expression context:
const obj = { calc: function(x) { return x * 2 } }
log(obj.calc(5)) // => 10
Default parameters
function greet(name = "world") {
return `Hello, ${name}!`
}
log(greet()) // => Hello, world!
log(greet("Alice")) // => Hello, Alice!
Rest parameters
Collects remaining arguments into an array.
function sum(...nums) {
return nums.reduce((a, b) => a + b, 0)
}
log(sum(1, 2, 3)) // => 6
log(sum(10, 20, 30, 40)) // => 100
Rest parameter must be the last parameter:
function first(head, ...tail) {
log("head:", head)
log("tail:", tail)
}
first(1, 2, 3, 4)
// => head: 1
// => tail: [2, 3, 4]
arguments Object
Every function receives an implicit arguments array containing all passed arguments.
function showArgs() {
log(arguments)
}
showArgs(1, "two", true) // => [1, two, true]
Note: In the engine, arrow functions also have their own
argumentsobject (unlike standard JavaScript). See Differences from JavaScript.
Tagged template literals
A function can be called with a template literal as its argument:
function tag(strings, ...values) {
let result = ""
for (let i = 0; i < strings.length; i++) {
result += strings[i]
if (i < values.length) result += String(values[i]).toUpperCase()
}
return result
}
let name = "world"
log(tag`hello ${name}!`) // => hello WORLD!
Closures
Functions capture variables from their enclosing scope.
function makeCounter() {
let count = 0
return () => {
count++
return count
}
}
let counter = makeCounter()
log(counter()) // => 1
log(counter()) // => 2
log(counter()) // => 3
Recursion
function fib(n) {
if (n <= 1) return n
return fib(n - 1) + fib(n - 2)
}
log(fib(10)) // => 55
Higher-order functions
Functions can be passed as arguments and returned from other functions.
function apply(fn, value) {
return fn(value)
}
log(apply(x => x * 3, 7)) // => 21
function multiplier(factor) {
return (x) => x * factor
}
let triple = multiplier(3)
log(triple(5)) // => 15
Hoisting
Function declarations are fully hoisted - they can be called before their definition:
log(greet("Alice")) // => Hello, Alice!
function greet(name) {
return "Hello, " + name + "!"
}
var declarations are hoisted as undefined:
log(x) // => undefined
var x = 5
log(x) // => 5
let / const are NOT hoisted:
// log(y) // ReferenceError: 'y' is not defined
let y = 10
Classes
Class declarations
class Dog {
constructor(name) {
this.name = name
}
bark() {
return this.name + " says woof"
}
}
const d = new Dog("Rex")
log(d.bark()) // => Rex says woof
A class without an explicit constructor gets a default empty one.
The new operator
new creates instances of user-defined classes, built-in types, and error constructors.
const p = new Point(3, 4) // User-defined class
const d = new Date(2024, 0, 15) // Built-in type
const re = new RegExp("^hello", "i")
const s = new Set([1, 2, 3])
const err = new TypeError("bad type") // Error constructor
The this keyword
this refers to the current instance inside constructors and methods.
Method chaining - methods that return this enable fluent APIs:
class Builder {
constructor() { this.parts = [] }
add(p) { this.parts.push(p); return this }
build() { return this.parts.join("-") }
}
log(new Builder().add("a").add("b").add("c").build()) // => a-b-c
Inheritance (extends)
class Animal {
speak() { return "generic sound" }
}
class Dog extends Animal {
speak() { return "woof" }
}
log(new Dog().speak()) // => woof
Multi-level inheritance:
class A { base() { return "base" } }
class B extends A { whoAmI() { return "B" } }
class C extends B {}
const c = new C()
log(c.whoAmI() + "," + c.base()) // => B,base
super
super() calls the parent constructor. super.method() calls a parent method.
class Animal {
constructor(name) { this.name = name }
}
class Dog extends Animal {
constructor(name, breed) {
super(name)
this.breed = breed
}
}
const d = new Dog("Rex", "Lab")
log(d.name + " is a " + d.breed) // => Rex is a Lab
Static methods
Static methods belong to the class itself, not to instances.
class MathHelper {
static add(a, b) { return a + b }
}
log(MathHelper.add(3, 4)) // => 7
Getters and setters
class Circle {
constructor(radius) { this.radius = radius }
get area() { return 3.14 * this.radius * this.radius }
}
log(new Circle(10).area) // => 314
class Person {
constructor(name) { this._name = name }
get name() { return this._name }
set name(val) { this._name = val.toUpperCase() }
}
const p = new Person("alice")
p.name = "bob"
log(p.name) // => BOB
Class fields
class Counter {
count = 0
increment() { this.count++ }
}
const c = new Counter()
log(c.count) // => 0
c.increment()
log(c.count) // => 1
Static fields:
class Config {
static defaultTimeout = 5000
}
log(Config.defaultTimeout) // => 5000
Private fields (# prefix) - not accessible outside the class:
class Secret {
#value = 42
getValue() { return this.#value }
}
const s = new Secret()
log(s.getValue()) // => 42
log(s.value) // => undefined (private field not exposed)
Class expressions
const Foo = class {
getValue() { return 42 }
}
log(new Foo().getValue()) // => 42
instanceof with Classes
class Animal {}
class Dog extends Animal {}
const d = new Dog()
log(d instanceof Dog) // => true
log(d instanceof Animal) // => true (inheritance chain)
Async methods
class Fetcher {
async getData() {
return await Promise.resolve(42)
}
}
const result = await new Fetcher().getData()
log(result) // => 42
Next steps
- JS: Language Basics - Variables, operators, control flow
- JS: Async/Await - Async functions and Promise API
- JS: Differences from Standard JS - What works differently
- Scripting Language - Overview and sandbox details
