Skip to content

A Simplified JavaScript Grammar

The many small rules in the JavaScript programming language is its grammar. These rules specify the accepted way to write JavaScript code. Unless your code follows the grammar of JavaScript, the computer won’t understand (or worse, might mis-interpret) what you’re telling it to do.

Individually, each rule in itself is not enough to produce complete working code. Instead, the rules are like building blocks, offering various ways to assemble or construct your code.

A language grammar is a set of small rules that can be combined to produce the syntax of your code.

Using This Grammar

The formal grammar for JavaScript is actually quite large and complex. In fact, the grammars for most programming languages are so complex that they require another “language” to describe the grammar. An early and fairly standard language or means to express grammars is the Bakus-Naur Form, or BNF.

For our purposes, we will present a much more simplified grammar. The following sections express the bulk of the JavaScript grammar used in this introductory JavaScript course.

Most of the grammar rules in JavaScript are quite short, defining the order of keywords, identifiers and symbols/operators. In the following grammars, highlighted portions indicate a part of the grammar where you would need to substitute some appropriate code. For example, the for statement has four items that you would replace with code specific to your application. The required portions of the grammar are the keywords (for) and symbols (parenthesis and semicolons).

for([initialization]; conditionalExpression; [incrementation])
statementOrStatementBlock

Common Grammar Elements

Program Statements and Statement blocks

Individual instructions are known as Program Statements. The instructions can be short and simple, or they can be long and complex. In either case, the program statement should end in a semicolon (;), though the grammar allows them to be omitted.

Besides individual instructions, we can group individual statements into Statement Blocks. A statement block is a set of zero or more program statements that are enclosed in a set of curly braces ({ }). Statement blocks are frequently used with Flow Control Statements (such as the if and for statements).


Literal Values

A literal value is a piece of “raw” information or data that is embedded into our code. JavaScript offers several types of literals. The more commonly used ones are as follows.

  • String literals - Any text enclosed in single or double quotes. 'Hello' and "Stewart's home!" are examples of string literals.
  • Numeric literals - One or more digits combined to make a number. 42 and 3.14159 are examples of numeric literals, where the first one is an integer literal (whole number) and the second is a floating-point literal (the value includes a decimal point).
  • Boolean literals - JavaScript has two keywords which represent literal boolean values: true and false.
  • Array literals - Any set of values enclosed withint square brackets ([]). It can be empty - [] - or include values - ['Ace', 'King', 'Queen'].
  • Object literals - Any set of zero or more pairs of property names and values enclosed within curly braces ({}). This should not be confused with the use of curly braces that represents a statement block.

There are additional types of literals in JavaScript that are used for specific purposes. These include the following.

  • Template literals - A variation of the string literal, but where the text is enclosed with backticks (`).
  • RegExp literals - A pattern for matching string values, enslosed between a pair of slashes (/).

For links to more detailed descriptions, see the MDN article on Literals.

Template Strings

The difference between template and string literals is that all of the text inside a string is considered a literal value whereas template literals can include variables or expressions through the use of placeholders. For example, in the following code, everything between the backticks are the literal parts of the string while the ${firstName} is not.

`Welcome to ${firstName}'s world!`

If the value of firstName is "Wayne", then the resulting text would be Welcome to Wayne's world!.

Template strings work across multiple lines as well. Consider this example.

welcome = `<h1>
Welcome ${firstName}!
<span class="badge">${rating}</span>
</h1>`;

Regular strings have to be entirely on the same physical line in JavaScript. If you want to built your string literal using line breaks, use template strings instead.


Expressions

An Expression is any combination of literal values, identifiers, operators (such as the arithmetic operators), and/or method calls (where the method returns a value). When an expression is processed, a single value is produced. This value can then be used in whatever operation the expressions occurs. For example, the value might be passed into a method as part of a method call, or it might be placed in a variable as part of an assignment statement.


Variable Declarations

Before a variable can be used, it must be declared. How you declare a variable will affect its scope and whether its value can be changed. There are three keywords in JavaScript for declaring variables: var, let and const.

let keyword MDN var keyword MDN const keyword MDN

let and var

The let statement declares a variable with block-level scope. The var statement declares a variable with function-scope or global scope.

let Statement
let variableName [= expression];
var Statement
var variableName [= expression];

In both cases, variablename is a programmer-defined identifier (name) to represent a value. An optional initial value may be assigned, as denoted by [= expression], where expression is any valid JavaScript expression. If no value is assigned to the variable, it’s initial value is undefined. The datatype of the variable is always determined by the value stored in that variable.

const

The const statement declares a variable whose value cannot be changed. The value must be assigned when the variable is declared.

const Statement
const variableName = expression;

Again, variablename is a programmer-defined identifier (name) while expression is any valid JavaScript expression.


Assignment Operation

Varible Assignment
variableName assignmentOperator expression

Assignment Operations are operations where a value is assigned or stored in a variable. The parts of the grammar are the

  • variableName - the name of the variable that will receive/store the value.
  • assignmentOperator - one of the following:
    • = Equals
    • += Plus-Equals
    • -= Minus-Equals
    • *= Multiply-Equals
    • /= Divide-Equals
    • %= Modulus-Equals
  • expression - any valid JavaScript expression

An assignment operation is made into an assignment statement by adding a semicolon to the end of the operation. For example,

Assignment Statement
total = price * quantity;

Flow-Control Statements

Flow-Control Statements are a crucial part of the procedural characteristics within the JavaScript language. They provide the capabilities of alternative paths of logic (if-else and switch) and repetition (for, while and their variants). They also provide the ability to “jump into” functions through function calls.

All flow-control statement grammars include a reference to statementOrStatementBlock. When using a Statement Block, the opening curly brace must be on the same line as the initial statement (as per accepted JavaScript style guides). The provided samples are shown with the use of statement blocks.

  • statementOrStatementBlock is either a single statement or a single statement block (zero or more statements inside curly braces - { }).
    • A single statement can be on its own line.
    • A statement block should have the opening curly brace at then end of the same line as the initial statement and the closing curly brace on its own line.

The following is an example of a statement block with properly positioned curly braces.

Sample Code
if(quantity === 0) {
// zero or more lines of code
}

Conditional Expressions

Conditional expressions are ones that are ultimately evaluated as being equivalent to true or false. In flow-control statements, they often include the use of relational operators and/or boolean operators.

”Truthy” and “Falsy” Values

While JavaScript has a built-in Boolean data type, the evaluation of conditional expressions is not strictly confined to true or false values. A conditional expression, in JavaScript, can also be something that is truthy or falsy.

JavaScript regards all of the following as being equivalent to a false value (and refers to these as falsy values).

  • undefined - No value has been assigned
  • null - The absense of any value
  • NaN - Not-a-Number
  • 0 - The numeric value zero
  • "" - An empty string
  • {} - An empty object

Anything that is not false (or falsy) is regarded as equivalent to true. Besides the true keyword, some samples of truthy values include the following: 42, 'bob', '\n', { key: 'value' }.

Relational Operators

JavaScript has the following relational operators. These are all binary operators, meaning that there must be some identifier or expression on both sides of the operator

  • == - “Is equal to”
  • === - Strict equality
  • != - “Not equal to”
  • !== - Strict inequality
  • > - Greater Than
  • >= - Greater Than or Equal To
  • < - Less Than
  • <= - Less Than or Equal To

Boolean Operators

JavaScript has the following boolean operators.

  • && - Logical “And”
  • || - Logical “Or”
  • ! - Logical “Not”

The logical “And” (&&) and “Or” (||) operators are binary operators, meaning that some identifier or expression is required on both sides of the operator. The logical “Not” (!) operator is a unary operator where an identifier or expression is expected to be on the right-hand side of the operator.

Two “Not” operators can be used to coerce or force an identifier into a strict true or false value. For example, in the following code the value of !!myObject will be forced to true if myObject is truthy or false otherwise.

Boolean Coercion
let myObject;
// some intervening code that sets the value
let success = !!myObject;
if(success) {
// do something
}

To understand the effects of boolean operations, consider the following truth table. It illustrates the resulting value from performing “And” and “Or” operations.

abLogical AND
a && b
Logical OR
a || b
Logical NOT
!a
truetruetruetruefalse
truefalsefalsetruefalse
falsetruefalsetruetrue
falsefalsefalsefalsetrue

If-Else ⁉️

if(conditionalExpression)
statementOrStatementBlock // true side
else
statementOrStatementBlock // false side

The if-else provides alternate paths of logic, where

  • conditionalExpression is an expression whose ultimate data type is a bool.
  • the else portion is optional.

For example:

Sample Code

Switch-Case ⁉️

switch(cardinalExpression)
{
case matchingExpression1:
statementOrStatementBlock
break;
case matchingExpression2:
statementOrStatementBlock
break;
// ...additional case statements...
default:
statementOrStatementBlock
break;
}

The switch provides alternate paths of logic, where : cardinalExpression is an expression that produces a single value of any primitive data type (int, double, char, string or an enum). : Each matchingExpression is a constant value whose data type matches the data type of the cardinalExpression. A match is determined by the value of the cardinalExpression being equal to the matchingExpression. The break indicates the end of the path of logic for the matching expression. : statementOrStatementBlock is either a single statement or a single statement block (zero or more statements inside curly braces - { }). : The default block will execute if cardinalExpression did not match any of the listed matching expressions.

For example:

Sample Code

For ⁉️

The for keyword is a flow control structure to provide looping capabilities. It comes in four variations:

  • for - The traditional variation of the while statement, where factors affecting the repetition are contained in the parenthesis.
  • for...in -
  • for...of -
  • for await...of -

for Statement

for Statement
for([initialization]; conditionalExpression; [incrementation])
statementOrStatementBlock

The for provides repetitive execution of code, where

  • initialization is a variable declaration typically including an assignment; the variables identified here should be ones used in the conditionalExpression. This portion is optional, but when declaring the variable you should use the let or var keywords.
  • conditionalExpression is an expression whose ultimate data type is a bool. The conditionalExpression is evaluated at the beginning of the loop and may be any “truthy” expression.
  • incrementation is a modifications to the variable controlling the loop; the variables identified here should be ones used in the conditionalExpression. This portion is optional.

For example:

Sample Code
for(let count = 0; count < options.length; count++) {
// code that you want to repeat
}
for Keyword on MDN

for...of Statement

for...of Statement
for(variable of iterable)
statementOrStatementBlock

The for...of provides repetitive execution of code, where the repetition occurs for each item in the iterable.

  • iterable is any object that represents a collection of values, such as Arrays, strings, NodeList and similar collections.
  • variable is an identifier to represent each item in the collection as it loops through the collection’s items/elements; the variable should be declared with a let, const or var.

For example:

Sample Code
for(let )

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for…of

for...in Statement

for await...of Statement


While and Do-While ⁉️

while(conditionalExpression)
statementOrStatementBlock

The while provides repetitive execution of code, where : conditionalExpression is an expression whose ultimate data type is a bool. The conditionalExpression is evaluated at the beginning of the loop. : statementOrStatementBlock is either a single statement or a single statement block (zero or more statements inside curly braces - { }).

  • The statementOrStatementBlock will only execute as long as the contitionalExpression results in a true value.
  • The loop exits when the conditionalStatement results in a false value.
do
statementOrStatementBlock
while (conditionalExpression);

The do-while provides repetitive execution of code, where : conditionalExpression is an expression whose ultimate data type is a bool. The conditionalExpression is evaluated at the end of the loop. : statementOrStatementBlock is either a single statement or a single statement block (zero or more statements inside curly braces - { }).

  • The statementOrStatementBlock will execute at least once and will keep on executing as long as the contitionalExpression results in a true value.
  • The loop exits when the conditionalStatement results in a false value.

Function Calls ⁉️

While the Method Declaration defines a set of instructions, those instructions only run when the method is called from somewhere. The operating system is responsible to call the Main() method, but after that, all method calls are the responsibility of our program. The grammar of a method call is as follows.

[[ClassName | ObjectName].]MethodName(argumentList)

A Method Call is an expression where : MethodName is the programmer-defined name of the method, : argumentList is a comma-separated list of values that correspond to the parameters of the method declaration, : The method is preceded by either a ClassName (for static methods) or an ObjectName (aka: a variable name) that identifies where the method can be “found”; the Member Access Operator (aka: “dot” operator .) comes right after the ClassName or ObjectName. If the method declaration is in the same class as the method call, then the ClassName/ObjectName can be omitted.

When a method is an instance method (non-static) and is called without an ObjectName, the this keyword is implied. In other words, if the method call looks like

Display("Some Text")

it is interpreted as

this.Display("Some Text")

The this keyword simply means that the method declaration is in the same class as the method call and that it should be applied to the same instance (this instance) of the class.


Classes and Class Members ⁉️

As an object-oriented language, classes play a very prominent part of the code we write in JavaScript. It is within classes, for example, that we place variables (also called fields) and methods (which are “named sets of instructions”). One of the first things that classes give us developers is a context or scope for the code that we write. Classes are also building blocks, acting as blueprints for new and complex data types that we as programmers can create as we develop richer and more complex computer programs. Classes permeate all the code that we write in JavaScript and are so fundamental that you can’t even write a “Hello World” program without them.


Class Definition ⁉️

[accessModifier] class ClassName
{
// FieldDeclarations
// PropertyDeclarations
// Constructors
// MethodDeclarations
}

A Class Definition describes a new data type where : [accessModifier] is either public or internal. If no access modifier is provided, then the default modifier is internal. : ClassName is the programmer-supplied name for the class (in TitleCase format) : FieldDeclarations, PropertyDeclarations, Constructors and MethodDeclarations are all optional and can appear in any order. See the related grammars below to see how they are defined.


Field Declarations ⁉️

[accessModifier] [static] dataType _FieldName [= constantExpression];

A Field Declaration identifies a static or instance member variable of the class where : [accessModifier] is either public, private, protected, or internal. If no access modifier is provided, then the default modifier is private. : [static] is an optional keyword. If present, the field is shared among all instances of the class. If absent (which is the common case) then the field is an instance member and one is created every time an object based on the class is created. : dataType is any built-in data type or the name of a programmer-defined data type. : _FieldName is a the name you give to the member variable. By convention, private fields are given an underscore as a prefix to the name. : constantExpression is an optional expression that generates data whose value can be determined at compile time. Being a constant expression does not mean that the field is a constant, only that the initial value stored in the field is a constant and can be known at compile time before the program runs.


Property Declarations ⁉️

Properties are a kind of cross between methods and fields. On one hand, they are used in the same way that fields are. When you want to assign (or set) a value to a property, you place the property on the left side of the assignment operator. When you want to use (or get) the properties value, you simply reference the property name just as you would a field name.

Internally, however, the get and set operations are like the bodies of a method, where you can place instructions to retrieve or change the data in the class or object. The technical term for the get and set portions of a property is accessor.1

Explicitly Implemented Property ⁉️

Explicitly implemented properties are properties where the programmer supplies the getter and setter implementations. The bodies of the getter and setter may reference a field (known as a backing store) that holds the actual information. In these cases, the property is working to provide a controlled access to the underlying field’s data.

In other situations, a property may merely have a getter where the body of the getter derives or calculates a value to return from some other source, such as a calculation.

[accessModifier] [static] dataType PropertyName
{
get
{
// Body of getter
}
set
{
// Body of setter
}
}

A Property Declaration identifies a static or instance member of the class where : [accessModifier] is either public, private, protected, or internal. If no access modifier is provided, then the default modifier is private. : [static] is an optional keyword. If present, the Property is shared among all instances of the class. If absent (which is the common case) then the Property is an instance member. : dataType is any built-in data type or the name of a programmer-defined data type. : PropertyName is a the name you give to the member property. : Body of getter is a set of instructions that must ultimately return a value of the same data type as the property. : Body of the setter is a set of instructions that can process incoming data that is in the value keyword. A typical implementation will store that data into the property’s backing store.

Auto-Implemented Property ⁉️

Auto-Implemented properties are properties where the compiler takes care of the getter and setter implementations and also supplies a hidden field as the backing store for the property. The default get implementation is to retrieve the value from the backing store while the default set implementation is to place a value into the backing store.

[accessModifier] [static] dataType PropertyName { get; set; }

A Property Declaration identifies a static or instance member of the class where : [accessModifier] is either public, private, protected, or internal. If no access modifier is provided, then the default modifier is private. : [static] is an optional keyword. If present, the Property is shared among all instances of the class. If absent (which is the common case) then the Property is an instance member. : dataType is any built-in data type or the name of a programmer-defined data type. : PropertyName is a the name you give to the member property.


Method Declarations ⁉️

[accessModifier] [static] returnType MethodName(ParameterList)
{
// body of method
}

A Method Declaration defines a named set of instructions. : [accessModifier] is either public, private, protected, or internal. If no access modifier is provided, then the default modifier is private. : [static] is an optional keyword. If present, the method is shared among all instances of the class. If absent (which is the common case) then the method is an instance member. : returnType is any built-in data type or the name of a programmer-defined data type. The return type signifies the kind of information that the method will return. If the method does not return any information, then the keyword void is used as the return type. : MethodName is a the name you give to the method. : ParameterList is a comma-separated list of individual variable declarations.


Constructors ⁉️

[accessModifier] ClassName(ParameterList)
{
// body of constructor
}

A Constructor is a set of instructions used when instantiating (creating) an object. : [accessModifier] is either public, private, protected, or internal. If no access modifier is provided, then the default modifier is private. : ClassName - All constructors use the name of the class to which they belong as the name of the constructor. : ParameterList is a comma-separated list of individual variable declarations. : Classes never return any information - they are simply blocks of instructions used to set up the initial state of the object.

Objects, Classes and More

Object Instantiation ⁉️

new ClassName(argList)

Initializer Lists ⁉️

new ClassName
{
initializerList
}

Classes and Inheritance ⁉️

[accessModifier] class ClassName : BaseClassOrInterface[, InterfaceList]
{
// ClassMembers
}

This grammar offers additional details over the earlier Class Definition, where : BaseClassOrInterface is the name of either another class or an interface : InterfaceList is a comma-separated list of interface names

Footnotes

  1. See the Microsoft docs for Restricting Accessor Accessibility