2More on JavaScript

2.1JavaScript Basics

In this summary we try to take all important points of the classical JavaScript summary30 by Douglas Crockford31 into consideration.

2.1.1Types and data literals in JavaScript

JavaScript has three primitive datatypes: string, number and boolean, and we can test if a variable v holds a value of such a type with the help of the JS operator typeof as, for instance, in typeof v === "number".

There are five reference types: Object, Array, Function, Date and RegExp. Arrays, functions, dates and regular expressions are special types of objects, but, conceptually, dates and regular expressions are primitive data values, and happen to be implemented in the form of wrapper objects.

The types of variables, array elements, function parameters and return values are not declared and are normally not checked by JavaScript engines. Type conversion (casting) is performed automatically.

The value of a variable may be

a data value: either a string, a number, or a boolean;

an object reference: either referencing an ordinary object, or an array, function, date, or regular expression;

the special data value null, which is typically used as a default value for initializing an object variable;

the special data value undefined, which is the implicit initial value of all variables that have been declared, but not initialized.

A string is a sequence of Unicode characters. String literals, like "Hello world!", 'A3F0', or the empty string "", are enclosed in single or double quotes. Two string expressions can be concatenated with the + operator, and checked for equality with the triple equality operator:

The number of characters of a string can be obtained by applying the length attribute to a string:

All numeric data values are represented in 64-bit floating point format with an optional exponent (like in the numeric data literal 3.1e10). There is no explicit type distinction between integers and floating point numbers. If a numeric expression cannot be evaluated to a number, its value is set to NaN (“not a number”), which can be tested with the built-in predicate isNaN(expr).

Unfortunately, a built-in function, Number. isInteger, for testing if a number is an integer has only been introduced in ES6, so a polyfill32 is needed for using it in browsers that do not yet support it. For making sure that a numeric value is an integer, or that a string representing a number is converted to an integer, one has to apply the predefined function parseInt. Similarly, a string representing a decimal number can be converted to this number with parseFloat. For converting a number n to a string, the best method is using String(n).

There are two predefined Boolean data literals, true and false, and the Boolean operator symbols are the exclamation mark ! for NOT, the double ampersand && for AND, and the double bar || for OR. When a non-Boolean value is used in a condition, or as an operand of a Boolean expression, it is implicitly converted into a Boolean value according to the following rules. The empty string, the (numerical) data literal 0, as well as undefined and null, are mapped to false, and all other values are mapped to true. This conversion can be performed explicitly with the help of the double negation operation, like in the equality test !!undefined === false, which evaluates to true.

In addition to strings, numbers and Boolean values, also calendar dates and times are important types of primitive data values, although they are not implemented as primitive values, but in the form of wrapper objects instantiating Date. Notice that Date objects do, in fact, not really represent dates, but rather date-time instants represented internally as the number of milliseconds since 1 January, 1970 UTC. For converting the internal value of a Date object to a human-readable string, we have several options. The two most important options are using either the standard format of ISO date/ time strings of the form “2015–01–27”, or localized formats of date/ time strings like “27.1. 2015” (for simplicity, we have omitted the time part of the date/ time strings in these examples). When x instanceof Date, then x.toISOString() provides the ISO date/time string, and x.toLocaleDateString() provides the localized date/ time string. Given any date string ds, ISO or localized, new Date(ds) creates a corresponding date object.

For testing the equality (or inequality) of two primitive data vales, always use the triple equality symbol === (and !==) instead of the double equality symbol == (and !=). Otherwise, for instance, the number 2 would be the same as the string “2”, since the condition (2 == "2") evaluates to true in JavaScript.

Assigning an empty array literal, as in var a = [] is the same as, but more concise than and therefore preferred to, invoking the Array() constructor without arguments, as in var a = new Array().

Assigning an empty object literal, as in var o = {} is the same as, but more concise than and therefore preferred to, invoking the Object() constructor without arguments, as in var o = new Object(). Notice, however, that an empty object literal {} is not really an empty object, as it contains property slots and method slots inherited from Object.prototype33. So, a truly empty object (without any slots) has to be created with null as prototype, like in var emptyObject = Object. create(null).

A summary of type testing is provided in the following table:

Type Example values Test if x of type
string “Hello world!”, ’A3F0’ typeof x === "string"
boolean true, false typeof x === "boolean"
(floating point) number -2.75, 0, 1, 1.0, 3.1e10 typeof x === "number"
integer -2, 0, 1, 250 Number.isInteger(x)*)
Object {}, {num:3, denom:4}, {isbn:”006251587X,” title:”Weaving the Web“}, {”one”:1, “two”:2, “three”:3} excluding null: x instanceof Object including null: typeof x === "object"
Array34 [], [“one”], [1,2,3], [1,”one”, {}] Array.isArray(x)
Function35 function () { return "one"+1;} typeof x === "function"
Date36 new Date("20150127") x instanceof Date
RegExp37 /(w+)s(w+)/ x instanceof RegExp

A summary of type conversions is provided in the following table:

Type Convert to string Convert string to type
boolean String(x) Boolean(y)
(floating point) number String(x) parseFloat(y)
integer String(x) parseInt(y)
Object x.toString() or JSON.stringify(x) JSON.parse(y)
Array Function x.toString() or JSON.stringify(x) x.toString() y.split() or JSON.parse(y) new Function(y)
Date RegExp x.toISOString() x.toString() new Date(y) new RegExp(y)

2.1.2Variable scope

In the current version of JavaScript, ES5, there are only two kinds of scope for variables: the global scope (with window as the context object) and function scope, but no block scope. Consequently, declaring a variable within a code block is confusing and should be avoided. For instance, although this is a frequently used pattern, even by experienced JavaScript programmers, it is a pitfall to declare the counter variable of a for loop in the loop, as in

Instead, and this is exactly how JavaScript is interpreting this code (by means of “hoisting” variable declarations), we should write:

All variables should be declared at the beginning of a function. Only in the next version of JavaScript, ES6, block scope will be supported by means of a new form of variable declaration with the keyword let.

2.1.3Strict Mode

Starting from ES5, we can use strict mode38 for getting more runtime error checking. For instance, in strict mode, all variables must be declared. An assignment to an undeclared variable throws an exception.

We can turn strict mode on by typing the following statement as the first line in a JavaScript file or inside a <script> element:

It is generally recommended that you use strict mode, except your code depends on libraries that are incompatible with strict mode.

2.1.4Different kinds of objects

JS objects are different from classical OO/UML objects. In particular, they need not instantiate a class. And they can have their own (instance-level) methods in the form of method slots, so they do not only have (ordinary) property slots, but also method slots. In addition they may also have key-value slots. So, they may have three different kinds of slots, while classical objects (called “instance specifications” in UML) only have property slots.

A JS object is essentially a set of name-value-pairs, also called slots, where names can be property names, function names or keys of a map. Objects can be created in an ad-hoc manner, using JavaScript’s object literal notation (JSON), without instantiating a class:

An empty object with no slots is created in the following way:

Whenever the name in a slot is an admissible JavaScript identifier39, the slot may be either a property slot, a method slot or a key-value slot. Otherwise, if the name is some other type of string (in particular when it contains any blank space), then the slot represents a key-value slot, which is a map element, as explained below.

The name in a property slot may denote either

  1. a data-valued property, in which case the value is a data value or, more generally, a data-valued expression; or
  2. an object-valued property, in which case the value is an object reference or, more generally, an object expression.

The name in a method slot denotes a JS function (better called method), and its value is a JS function definition expression.

Object properties can be accessed in two ways:

1.Using the dot notation (like in C++/Java):
person1.lastName = "Smith"

2.Using a map notation:
person1["lastName"] = "Smith"

JS objects can be used in many different ways for different purposes. Here are five different use cases for, or possible meanings of, JS objects:

1.A record is a set of property slots like, for instance,
var myRecord = {firstName:"Tom", lastName:"Smith", age:26}

2.A map (also called ’associative array’, ’dictionary’, ’hash map’ or ’hash table’ in other languages) supports look-ups of values based on keys like, for instance, var numeral2number = {"one":"1", "two":"2", "three":"3"} which associates the value “1” with the key “one”, “2” with “two”, etc. A key need not be a valid JavaScript identifier, but can be any kind of string (e. g. it may contain blank spaces).

3.An untyped object does not instantiate a class. It may have property slots and method slots like, for instance,

Within the body of a method slot of an object, the special variable this refers to the object.

4.A namespace may be defined in the form of an untyped object referenced by a global object variable, the name of which represents a namespace prefix. For instance, the following object variable provides the main namespace of an application based on the Model-View-Controller (MVC) architecture paradigm where we have three subnamespaces corresponding to the three parts of an MVC application: var myApp = { model:{}, view:{}, ctrl:{} }; A more advanced namespace mechanism can be obtained by using an immediately invoked JS function expression, as explained below.

5.A typed object instantiates a class that is defined either by a JavaScript constructor function or by a factory object. See Section 1.9, “Defining and using classes”

2.1.5Array lists

A JS array represents, in fact, the logical data structure of an array list, which is a list where each list item can be accessed via an index number (like the elements of an array). Using the term ’array’ without saying ’JS array’ creates a terminological ambiguity. But for simplicity, we will sometimes just say ’array’ instead of ’JS array’.

A variable may be initialized with a JS array literal:

Because they are array lists, JS arrays can grow dynamically: it is possible to use indexes that are greater than the length of the array. For instance, after the array variable initialization above, the array held by the variable a has the length 3, but still we can assign a fifth array element like in

The contents of an array a are processed with the help of a standard for loop with a counter variable counting from the first array index 0 to the last array index, which is a.length-1:

Since arrays are special types of objects, we sometimes need a method for finding out if a variable represents an array. We can test, if a variable a represents an array by applying the predefined datatype predicate isArray as in Array. isArray( a).

For adding a new element to an array, we append it to the array using the push operation as in:

For deleting an element at position i from an array a, we use the predefined array method splice as in:

For searching a value v in an array a, we can use the predefined array method indexOf, which returns the position, if found, or -1, otherwise, as in:

For looping over an array a, we have two options: either use a for loop, or the array looping method forEach. In any case, we can use a for loop:

If performance doesn’t matter, that is, if a is sufficiently small (say, it does not contain more than a few hundred elements), we can use the array looping method forEach, as in the following example, where the parameter elem iteratively assumes each element of the array a as its value:

For cloning an array a, we can use the array function slice in the following way:

2.1.6Maps

A map(also called ’hash map’ or ’associative array’) provides a mapping from keys to their associated values. The keys of a JS map are string literals that may include blank spaces like in:

A map is processed with the help of a special loop where we loop over all keys of the map using the predefined function Object.keys(m), which returns an array of all keys of a map m. For instance,

For adding a new entry to a map, we simply associate the new value with its key as in:

For deleting an entry from a map, we can use the predefined delete operator as in:

For searching in a map if it contains an entry for a certain key value, such as for testing if the translation map contains an entry for “my bike” we can check the following:

For looping over a map m,we first convert it to an array of its keys with the help of the predefined Object.keys method, and then we can use either a for loop or the forEach method. The following example shows how to loop with for:

Again, if m is sufficiently small, we can use the forEach method, as in the following example:

Notice that using the forEach method is more concise.

For cloning a map m, we can use the composition of JSON.stringify and JSON. parse. We first serialize m to a string representation with JSON.stringify, and then de-serialize the string representation to a map object with JSON.parse:

Notice that this method works well if the map contains only simple data values or (possibly nested) arrays/maps containing simple data values. In other cases, e. g. if the map contains Date objects, we have to write our own clone method.

2.1.7JavaScript supports four types of basic data structures

In summary, the four types of basic data structures supported are:

  1. array lists, such as ["one","two","three"], which are special JS objects called ’arrays’, but since they are dynamic, they are rather array lists as defined in the Java programming language.
  2. records, which are special JS objects, such as { firstName:"Tom", lastName:"Smith"}, as discussed above,
  3. maps, which are also special JS objects, such as {"one":1, "two":2, "three":3}, as discussed above,
  4. entity tables, like for instance the table shown below, which are special maps where the values are entity records with a standard ID (or primary key) slot, such that the keys of the map are the standard IDs of these entity records.

Table 2.1 An example of an entity table representing a collection of books

Key Value
006251587X { isbn:”006251587X,” title:”Weaving the Web”, year:2000}
0465026567 { isbn:”0465026567,” title:”Gödel, Escher, Bach”, year:1999}
0465030793 { isbn:”0465030793,” title:”I Am A Strange Loop”, year:2008}

Notice that our distinction between maps, records and entity tables is a purely conceptual distinction, and not a syntactical one. For a JavaScript engine, both {firstName:"Tom", lastName:"Smith"} and {"one":1,"two":2,"three":3} are just objects. But conceptually, {firstName:"Tom", lastName:"Smith"} is a record because firstName and lastName are intended to denote properties (or fields), while {"one":1,"two":2,"three":3} is a map because "one" and "two" are not intended to denote properties/fields, but are just arbitrary string values used as keys for a map.

Making such conceptual distinctions helps in the logical design of a program, and mapping them to syntactic distinctions, even if they are not interpreted differently, helps to better understand the intended computational meaning of the code and therefore improves its readability.

2.1.8Procedures, methods and functions

Generally, a (parametrized) procedure is like a sub-program that can be called (with a certain number of arguments) any number of times from within a program. Whenever a procedure returns a value, it is called a function. In OOP, procedures are called methods, if they are defined in the context of a class or of an object.

In JavaScript, methods are called “functions”, no matter if they return a value or not. As shown below in Figure 2.1, JS functions are special JS objects, having an optional name property and a length property providing their number of parameters. If a variable v references a function can be tested with

Being JS objects implies that JS functions can be stored in variables, passed as arguments to functions, returned by functions, have properties and can be changed dynamically. Therefore, JS functions are first-class citizens, and JavaScript can be viewed as a functional programming language.

The general form of a JS function definition is an assignment of a JS function expression to a variable:

where params is a comma-separated list of parameters (or a parameter record), and theNameOfMyMethod is optional. When it is omitted, the method/ function is anonymous. In any case, JS functions are normally invoked via a variable that references the function. In the above case, this means that the JS function is invoked with myMethod(), and not with theNameOfMyMethod(). However, a named JS function can be invoked by name from within the function (for recursion). Consequently, a recursive JS function must be named.

Anonymous function expressions are called lambda expressions (or shorter lambdas) in other programming languages.

As an example of an anonymous function expression being passed as an argument in the invocation of another (higher-order) function, we can take a comparison function being passed to the predefined function sort for sorting the elements of an array list. Such a comparison function must return a negative number if its first argument is smaller than its second argument, it must return 0 if both arguments are of the same rank, and it must return a positive number if the second argument is smaller than the first one. In the following example, we sort a list of lists of 2 numbers in lexicographic order:

A JS function declaration has the following form:

It is equivalent to the following named function definition:

that is, it creates both a function with name theNameOfMyMethod and a variable theNameOfMyMethod referencing this function.

JS functions can have inner functions. The closure mechanism allows a JS function using variables (except this) from its outer scope, and a function created in a closure remembers the environment in which it was created. In the following example, there is no need to pass the outer scope variable result to the inner function via a parameter, as it is readily available:

When a method/function is executed, we can access its arguments within its body by using the built-in arguments object, which is “array-like” in the sense that it has indexed elements and a length property, and we can iterate over it with a normal for loop, but since it’s not an instance of Array, the JS array methods (such as the forEach looping method) cannot be applied to it. The arguments object contains an element for each argument passed to the method. This allows defining a method without parameters and invoking it with any number of arguments, like so:

A method defined on the prototype of a constructor function, which can be invoked on all objects created with that constructor, such as Array. prototype.forEach, where Array represents the constructor, has to be invoked with an instance of the class as context object referenced by the this variable (see also the next section on classes). In the following example, the array numbers is the context object in the invocation of forEach:

Whenever such a prototype method is to be invoked not with a context object, but with an object as an ordinary argument, we can do this with the help of the JS function call method that takes an object, on which the method is invoked, as its first parameter, followed by the parameters of the method to be invoked. For instance, we can apply the forEach looping method to the array-like object arguments in the following way:

A two-argument variant of the Function.prototype.call method, collecting all arguments of the method to be invoked in an array-like object, is Function.prototype.apply. The first argument to both call and apply becomes this inside the function, and the rest are passed through. So, f.call( x, y, z) is the same as f.apply( x, [y, z]).

Whenever a method defined for a prototype is to be invoked without a context object, or when a method defined in a method slot (in the context) of an object is to be invoked without its context object, we can bind its this variable to a given object with the help of the JS function bind method (Function.prototype.bind). This allows creating a shortcut for invoking a method, as in var querySel = document.querySelector.bind( document),which allows to use querySel instead of document.querySelector.

The option of immediately invoked JS function expressions can be used for obtaining a namespace mechanism that is superior to using a plain namespace object, since it can be controlled which variables and methods are globally exposed and which are not. This mechanism is also the basis for JS module concepts. In the following example, we define a namespace for the model code part of an app, which exposes some variables and the model classes in the form of constructor functions:

2.1.9Defining and using classes

The concept of a class is fundamental in object-oriented programming. Objects instantiate (or are classified by) a class. A class defines the properties and methods (as a blueprint) for the objects created with it.

Having a class concept is essential for being able to implement a data model in the form of model classes in a Model-View-Controller (MVC) architecture. However, classes and their inheritance/extension mechanism are over-used in classical OO languages, such as in Java, where all variables and procedures have to be defined in the context of a class and, consequently, classes are not only used for implementing object types (or model classes), but also as containers for many other purposes in these languages. This is not the case in JavaScript where we have the freedom to use classes for implementing object types only, while keeping method libraries in namespace objects.

Any code pattern for defining classes in JavaScript should satisfy five requirements. First of all, (1) it should allow to define a class name, a set of (instance-level) properties, preferably with the option to keep them ’private’, a set of (instance-level) methods, and a set of class-level properties and methods. It’s desirable that properties can be defined with a range/ type, and with other meta-data, such as constraints. There should also be two introspection features: (2) an is-instance-of predicate that can be used for checking if an object is a direct or indirect instance of a class, and (3) an instance-level property for retrieving the direct type of an object. In addition, it is desirable to have a third introspection feature for retrieving the direct supertype of a class. And finally, there should be two inheritance mechanisms: (4) property inheritance and (5) method inheritance. In addition, it is desirable to have support for multiple inheritance and multiple classifications, for allowing objects to play several roles at the same time by instantiating several role classes.

There was no explicit class definition syntax in JavaScript before ES6. Different code patterns for defining classes in JavaScript have been proposed and are being used in different frameworks. But they do often not satisfy the five requirements listed above. The two most important approaches for defining classes are:

  1. In the form of a constructor function that achieves method inheritance via the prototype chain and allows to create new instances of a class with the help of the new operator. This is the classical approach recommended by Mozilla in their JavaScript Guide40. This is also the approach implemented in ES6 with the new class definition syntax.
  2. In the form of a factory object that uses the predefined Object. create method for creating new instances of a class. In this approach, the prototype chain method inheritance mechanism is replaced by a “copy & append” mechanism. Eric Elliott41 has argued that factory-based classes are a viable alternative to constructor-based classes in JavaScript (in fact, he even condemns the use of classical inheritance with constructor-based classes, throwing out the baby with the bath water).

When building an app, we can use both kinds of classes, depending on the requirements of the app. Since we often need to define class hierarchies, and not just single classes, we have to make sure, however, that we don’t mix these two alternative approaches within the same class hierarchy. While the factory-based approach, as exemplified by mODELcLASSjs42, has many advantages, which are summarized in Table 2.2, the constructor-based approach enjoys the advantage of higher performance object creation.

Table 2.2 Required and desirable features of JS code patterns for classes

2.1.9.1Constructor-based classes

Only in ES6, a user-friendly syntax for constructor-based classes has been introduced. In Step 1.a), a base class Person is defined with two properties, firstName and lastName, as well as with an (instance-level) method toString and a static (class-level) method checkLastName:

In Step 1.b), class-level (“static”) properties are defined:

Finally, in Step 2, a subclass is defined with additional properties and methods that possibly override the corresponding superclass methods:

In ES5, we can define a base class with a subclass in the form of constructor functions, following a code pattern recommended by Mozilla in their JavaScript Guide44, as shown in the following steps.

Step 1.a) First define the constructor function that implicitly defines the properties of the class by assigning them the values of the constructor parameters when a new object is created:

Notice that within a constructor, the special variable this refers to the new object that is created when the constructor is invoked.

Step 1.b) Next, define the instance-level methods of the class as method slots of the object referenced by the constructor’s prototype property:

Step 1.c) Class-level (“static”) methods can be defined as method slots of the constructor function itself (recall that, since JS functions are objects, they can have slots), as in

Step 1.d) Finally, define class-level (“static”) properties as property slots of the constructor function:

Step 2.a) Define a subclass with additional properties:

By invoking the supertype constructor with Person.call( this, ) for any new object created as an instance of the subtype Student, and referenced by this, we achieve that the property slots created in the supertype constructor (firstName and lastName) are also created for the subtype instance, along the entire chain of supertypes within a given class hierarchy. In this way we set up a property inheritance mechanism that makes sure that the own properties defined for an object on creation include the own properties defined by the supertype constructors.

In Step 2b), we set up a mechanism for method inheritance via the constructor’s prototype property. We assign a new object created from the supertype’s prototype object to the prototype property of the subtype constructor and adjust the prototype’s constructor property:

With Object.create( Person.prototype) we create a new object with Person.prototype as its prototype and without any own property slots. By assigning this object to the prototype property of the subclass constructor, we achieve that the methods defined in, and inherited from, the superclass are also available for objects instantiating the subclass. This mechanism of chaining the prototypes takes care of method inheritance. Notice that setting Student.prototype to Object.create( Person.prototype) is preferable over setting it to new Person(), which was the way to achieve the same in the time before ES5.

Step 2c) Define a subclass method that overrides a superclass method:

An instance of a constructor-based class is created by applying the new operator to the constructor and providing suitable arguments for the constructor parameters:

The method toString is invoked on the object pers1 by using the ’dot notation’:

When an object o is created with o = new C(), where C references a named function with name “C”, the type (or class) name of o can be retrieved with the introspective expression o.constructor.name, which returns “C”. The Function::name property used in this expression is supported by all browsers, except Internet Explorer versions before version 11.

In JavaScript, a prototype object is an object with method slots (and sometimes also property slots) that can be inherited by other objects via JavaScript’s method/ property slot look-up mechanism. This mechanism follows the prototype chain defined by the (in ES5 still unofficial) built-in reference property __proto__ (with a double underscore prefix and suffix) for finding methods or properties. As shown below in Figure 2.1, every constructor function has a reference to a prototype object as the value of its reference property prototype. When a new object is created with the help of new, its __proto__ property is set to the constructor’s prototype property.

For instance, after creating a new object with f = new Foo(), it holds that Object.getPrototypeOf(f), which is the same as f.__proto__, is equal to Foo. prototype. Consequently, changes to the slots of Foo.prototype affect all objects that were created with new Foo().While every object has a __proto__ property slot (except Object), only objects constructed with new have a constructor property slot.

Figure 2.1 The built-in JavaScript classes Object and Function.

Notice that we can retrieve the prototype of an object with Object. getPrototypeOf(o), which is an official ES5 alternative to o.__proto__.

2.1.9.2Factory-based classes

In this approach we define a JS object Person (actually representing a class) with a special create method that invokes the predefined Object. create method for creating objects of type Person:

Notice that the JS object Person actually represents a factory-based class. An instance of such a factory-based class is created by invoking its create method:

The method getFullName is invoked on the object pers1 of type Person by using the ’dot notation’, like in the constructor-based approach:

Notice that each property declaration for an object created with Object. create has to include the ’descriptors’ writable: true and enumerable: true, as in lines 5 and 7 of the Person object definition above.

In a general approach, like in the mODELcLASSjs45 library for model-based development, we would not repeatedly define the create method in each class definition, but rather have a generic constructor function for defining factory-based classes. Such a factory-based class constructor, like mODELcLASS, would also provide an inheritance mechanism by merging the own properties and methods with the properties and methods of the superclass. This mechanism is also called Inheritance by Concatenation46.

2.1.10Quiz Questions

If you would like to look up the answers for the following quiz questions, you can check our discussion forum47. If you don’t find an answer in the forum, you may create a post asking for an answer to a particular question.

2.1.10.1 Question 1: Deleting a map entry

Which JavaScript statement can be used for deleting a map entry with key "k" from a map m?

Answer: ________________________________

2.1.10.2Question 2: Evaluating a Boolean expression

What is the value of the Boolean expression null || !0 ? Select one:

○ true ○ false (select one)

2.1.10.3Question 3: JavaScript datatypes

Which of the following denote primitive datatypes in JavaScript? Select one or many:

☐ double ☐ string ☐ float ☐ int ☐ boolean ☐ byte ☐ number

2.1.10.4Question 4: Constructor-based class definition

Which of the following JavaScript fragments correctly defines the constructor-based class City shown in the class diagram? Hint: notice that setName is an instance-level method while checkName is a class-level (“static”) method.

Select one or many:

2.1.10.5Question 5: Variable scope

What is the output of the following program?

Answer: _____

2.2Storing Database Tables with JavaScripts localStorage API

In most apps, we have some form of data management where data is represented in tables such that table rows correspond to objects, and the table schema corresponds to the objects’ type. When building a front-end web app with JavaScript, the simplest approach for persistent data storage is using JavaScript’s localStorage API, which provides a simple key-value database, but does not support database tables. So, the question is: how can we store and retrieve tables with Local Storage?

We show how to represent database tables in JavaScript in the form of (what we call) entity tables, and how to store these tables in Local Storage.

2.2.1Entity Tables

The JavaScript Object Notation (JSON)48 defines a concise syntax for JavaScript array literals (lists) and JavaScript object literals (maps):

Lists are expressed as comma-separated lists of data literals enclosed in brackets:

Maps are expressed as comma-separated lists of key-value slots enclosed in curly braces:

A record is a special type of map where the keys are admissible JavaScript identifiers49 denoting properties, so they need not be enclosed in quotation marks in JavaScript code. For example, {id: 2901465, phone:”0049.30.227109“} is a record. The value of a property in a record, or the value associated with a key in a map, may be a simple data literal, or an array literal, or another object literal as in:

An entity table contains a set of records (or table rows) such that each record represents an object with a standard identifier property slot. Consequently, an entity table can be represented as a mapof records such that the keys of the map are the values of the standard identifier property, and their associated values are the corresponding records, as illustrated by the following example:

Key Value
006251587X 0465026567 0465030793 { isbn:”006251587X,” title:”Weaving the Web”, year:2000} { isbn:”0465026567,” title:”Gödel, Escher, Bach”, year:1999} { isbn:”0465030793,” title:”I Am A Strange Loop”, year:2008}

2.2.2JavaScripts LocalStorage API

For a front-end app, we need to be able to store data persistently on the front-end device. Modern web browsers provide two technologies for this purpose: the simpler one is called Local Storage, and the more powerful one is called IndexedDB50. For simplicity, we use the Local Storage API in our example app.

A Local Storage database is created per browser and per origin, which is defined by the combination of protocol and domain name. For instance, http://example.com and http://www.example.com are different origins because they have different domain names, while http://www.example.com and https://www.example.com are different origins because of their different protocols (HTTP versus HTTPS).

The Local Storage database managed by the browser and associated with an app (via its origin) is exposed as the built-in JavaScript object localStorage with the methods getItem, setItem, removeItem and clear. However, instead of invoking getItem and setItem, it is more convenient to handle localStorage as a map, writing to it by assigning a value to a key as in localStorage["id"] = 2901465, and retrieving data by reading the map as in var id = localStorage["id"]. The following example shows how to create an entity table and save its serialization to Local Storage:

Notice that we have used the predefined method JSON.stringify for serializing the entity table persons into a string that is assigned as the value of the localStorage key “personTable”. We can retrieve the table with the help of the predefined de-serialization method JSON.parse in the following way:

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset