JavaScript
Overview
- “JavaScript” is not really a single language. Each browser vendor implements their own JavaScript engine, and due to variations between browsers and versions, JavaScript suffers from some serious fragmentation. (CanIUse.com documents some of these inconsistencies).
- ES6, also known as ES2015 / Harmony / ECMAScript 6 / ECMAScript 2015, is the most-recent version of the JavaScript specification. (good primer on ES6).
- Transpilers
- Tools like
Babel
- process of transforming the standardized JavaScript into a version that’s compatible with older platforms is called transpiling. e.g., ES6 to ES5
- It’s not much different from compiling. By using a transpiler, you don’t need to worry as much about the headaches of whether or not a given browser will support the JavaScript feature you’re using.
- Transpiler tools don’t just convert ES6 JavaScript to ES5. There are also tools to do the same thing for JavaScript-variants (such as ClojureScript, TypeScript, and CoffeeScript) to regular JavaScript.
- ClojureScript is a version of Clojure that compiles down to JavaScript.
- TypeScript is essentially JavaScript, but with a type system.
- CoffeeScript is very similar to JavaScript, but with shinier syntax; much of the syntactic sugar promoted by CoffeeScript has been adopted by ES6 now.
- Tools like
- Build Tools
- Tools:
grunt
,gulp
,bower
,browserify
,webpack
- Basically compiling the code into a production-ready format.
- Requiring each JavaScript dependency as part of a page, script tag by script tag, is slow. Therefore, most sites use so-called JavaScript bundles. The bundling process takes all of the dependencies and “bundles” them together into a single file for inclusion on your page.
- Tools:
- Test Tools
- Tools:
Mocha
,Jasmine
,Chai
,Tape
,Karma
,PhantomJS
- Karma is a test runner that can run both Jasmine and Mocha-style tests.
- PhantomJS is a headless browser - it runs without GUI.
- Tools:
Node.js
- Node.js is a tool for writing server-side JavaScript.
- npm Node package manager. JavaScript modules are usually packaged and shared via npm.
- nvm Node version manager. Facilitates managing different version of Node.js.
Runtime Environment
- Node.js is not a language; not a framework; not a tool. It is a runtime environment for running JS-based applications like JRE for Java.
- JavaScript Virtual Machine (JsVM)
- Node.js has a virtual machine called JavaScript Virtual Machine (JsVM) which generates machine code for JS-based applications to enable it on different platforms.
- We have separate Node.js requirements for different platforms like Windows, Macintosh, and Linux and hence the JsVM.
- V8 is an open source JavaScript engine from Google. (Nashorn is the Java-based JS engine in JVM). Like the JVM, the JsVM (V8 engine) also has main components like JIT and GC for performing tasks, runtime compilation, and memory management respectively.
-
Node.js also has a set of libraries which may otherwise be known as Node API or Node Modules to help run JS applications at runtime, similar to Java Libraries within the JRE.
- How the JavaScript program is compiled and executed.
- The source code is written in JavaScript (.js). There is no intermediate code generated before giving it to JsVM, the V8 engine.
- The JsVM takes this source code directly and compiles it to machine code specific to the given target platform for execution.
Web Application Architecture
- The client requests are handled by a single thread, but asynchronously. With Java, each client request is handled by a separate thread synchronously.
- There are many frameworks/libraries available for Node.js-based web application development. E.g., Express.js, Angular.js, Mongoose.js, etc.
- Client layer: Angular.js, a client-side MVC framework.
- Presentation + Service layer: can be developed by using Express.js. This also comes with a standalone server for running Node.js applications.
- Data layer: uses an Object Data Modelling module (e.g. Mongoose.js) for communicating with NoSQL databases like MongoDB.
- This particular stack is called MEAN stack , which consists of MongoDB, Express.js, Angular.js, and Node.js (the runtime environment)
ES6 Basics
- Another name for ES6 is ES2015.
-
Since ES6, the ECMAScript specification has moved to a yearly release cadence, and versions of the language—ES2016, ES2017, ES2018, ES2019, and ES2020—are now identified by year of release.
- The core JavaScript language defines a minimal API for working with numbers, text, arrays, sets, maps, and so on, but does not include any input or output functionality. Input and output (as well as more sophisticated features, such as networking, storage, and graphics) are the responsibility of the “host environment” within which JavaScript is embedded.
- The original host environment for JavaScript was a web browser. The web browser environment allows JavaScript code to obtain input from the user’s mouse and keyboard and by making HTTP requests. And it allows JavaScript code to display output to the user with HTML and CSS.
-
Instead of constraining JavaScript to work with the APIs provided by a web browser, Node gives JavaScript access to the entire operating system, allowing JavaScript programs to read and write files, send and receive data over the network, and make and serve HTTP requests. Node is a popular choice for implementing web servers and also a convenient tool for writing simple utility scripts as an alternative to shell scripts
- Good tutorial https://babeljs.io/docs/en/learn
- MDN documentation https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/export
Types, Values, Variables
- JavaScript types can be divided into two categories: primitive types and object types.
- Primitive Types
- JavaScript’s primitive types include numbers, strings, and booleans
- The special JavaScript values
null
andundefined
are primitive values, but they are not numbers, strings, or booleans. - Primitives are immutable
Object Types
- Object: Any JavaScript value that is not a number, a string, a boolean, a symbol, null, or undefined is an object. An object (that is, a member of the type object) is a collection of properties where each property has a name and a value (either a primitive value or another object). One very special object is the global object.
- Objects are sometimes called reference types to distinguish them from JavaScript’s primitive types
- Array: The language also defines a special kind of object, known as an array, that represents an ordered collection of numbered values.
- Object types are mutable.
- Variables
- Constants are declared with
const
and variables are declared withlet
(or withvar
in older JavaScript code).
- Constants are declared with
Numbers
- Arithmetic in JavaScript does not raise errors in cases of overflow, underflow, or division by zero. When the result of a numeric operation is larger than the largest representable number (overflow), the result is a special infinity value,
Infinity
. Similarly, when the absolute value of a negative value becomes larger than the absolute value of the largest representable negative number, the result is negative infinity,-Infinity
. - Underflow occurs when the result of a numeric operation is closer to zero than the smallest representable number. In this case, JavaScript returns 0. If underflow occurs from a negative number, JavaScript returns a special value known as “negative zero.”
- Division by zero is not an error in JavaScript: it simply returns infinity or negative infinity. There is one exception, however: zero divided by zero does not have a well-defined value, and the result of this operation is the special not-a-number value, NaN. NaN also arises if you attempt to divide infinity by infinity, take the square root of a negative number, or use arithmetic operators with non-numeric operands that cannot be converted to numbers.
- BigInt literals are written as a string of digits followed by a lowercase letter
n
. e.g.,1234n
Text
- JavaScript uses the UTF-16 encoding of the Unicode character set, and JavaScript strings are sequences of unsigned 16-bit values.
- String literals - enclosed within a matched pair of single or double quotes or backticks (‘ or “ or `
- As of ES5, however, you can break a string literal across multiple lines by ending each line but the last with a backslash ()
- standard
===
equality and!==
inequality operators - The ES6 backtick syntax allows strings to be broken across multiple lines, and in this case, the line terminators are part of the string literal.
1 2 3 4 5 6 7 8 9 10 11 |
|
Template Literals
Template literals are string literals with JavaScript expressions in it.
1 2 3 4 |
|
1 2 3 4 5 6 7 |
|
Symbols
- Property names are typically (and until ES6, were exclusively) strings. But in ES6 and later, Symbols can also serve this purpose.
- To obtain a Symbol value, you call the
Symbol()
function. This function never returns the same value twice, even when called with the same argument. This means that if you callSymbol()
to obtain a Symbol value, you can safely use that value as a property name to add a new property to an object and do not need to worry that you might be overwriting an existing property with the same name. Similarly, if you use symbolic property names and do not share those symbols, you can be confident that other modules of code in your program will not accidentally overwrite your properties.
1 2 3 4 5 6 7 8 9 |
|
- The
Symbol()
function takes an optional string argument and returns a unique Symbol value. If you supply a string argument, that string will be included in the output of the Symbol’stoString()
method. Note, however, that callingSymbol()
twice with the same string produces two completely different Symbol values.- when using Symbols, you want to keep them private to your own code so you have a guarantee that your properties will never conflict with properties used by other code.
1 2 |
|
- The
Symbol.for()
function takes a string argument and returns a Symbol value that is associated with the string you pass. If no Symbol is already associated with that string, then a new one is created and returned; otherwise, the already existing Symbol is returned. That is, theSymbol.for()
function is completely different than the Symbol() function:Symbol()
never returns the same value twice, butSymbol.for()
always returns the same value when called with the same string.
1 2 3 4 5 |
|
Global Object
- The global object is a regular JavaScript object that serves a very important purpose: the properties of this object are the globally defined identifiers that are available to a JavaScript program.
- When the JavaScript interpreter starts (or whenever a web browser loads a new page), it creates a new
global
object and gives it an initial set of properties that define:- Global constants like
undefined
,Infinity
, andNaN
- Global functions like
isNaN()
,parseInt()
, andeval()
- Constructor functions like
Date()
,RegExp()
,String()
,Object()
, andArray()
- Global objects like
Math
andJSON
- Global constants like
- In Node, the global object has a property named global whose value is the global object itself, so you can always refer to the global object by the name global in Node programs.
- In web browsers, the Window object serves as the global object for all JavaScript code contained in the browser window it represents. This global Window object has a self-referential window property that can be used to refer to the global object. The Window object defines the core global properties, but it also defines quite a few other globals that are specific to web browsers and client-side JavaScript. Web worker threads have a different global object than the Window with which they are associated. Code in a worker can refer to its global object as self.
- ES2020 finally defines globalThis as the standard way to refer to the global object in any context. As of early 2020, this feature has been implemented by all modern browsers and by Node.
- Global object can be referenced as
globalThis
.
Scope
- Variables and constants declared with let and const are block scoped.
- When a declaration appears at the top level, outside of any code blocks, we say it is a global variable.
- In Node and in client-side JavaScript modules, the scope of a global variable is the file that it is defined in.
- In traditional client-side JavaScript, however, the scope of a global variable is the HTML document in which it is defined. That is: if one
<script>
declares a global variable or constant, that variable or constant is defined in all of the<script>
elements in that document (or at least all of the scripts that execute after thelet
orconst
statement executes).
- Hoisting
- One of the most unusual features of
var
declarations is known as hoisting. When a variable is declared withvar
, the declaration is lifted up (or “hoisted”) to the top of the enclosing function. The initialization of the variable remains where you wrote it, but the definition of the variable moves to the top of the function. So variables declared with var can be used, without error, anywhere in the enclosing function. If the initialization code has not run yet, then the value of the variable may be undefined, but you won’t get an error if you use the variable before it is initialized. (This can be a source of bugs and is one of the important misfeatures thatlet
corrects: if you declare a variable withlet
but attempt to use it before thelet
statement runs, you will get an actual error instead of just seeing anundefined
value.)
- One of the most unusual features of
1 2 3 4 5 6 |
|
1 2 3 4 5 6 |
|
Destructuring assignment
ES6 implements a kind of compound declaration and assignment syntax known as destructuring assignment.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
|
1 2 3 4 5 |
|
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
1 2 3 4 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
|
Expressions and Operators
Conditional Expressions
expression ?. identifier
expression ?.[ expression ]
- In JavaScript, the values
null
andundefined
are the only two values that do not have properties. In a regular property access expression using.
or[],
you get aTypeError
if the expression on the left evaluates tonull
orundefined
. You can use?.
and?.[]
syntax to guard against errors of this type. - This form of property access expression is sometimes called “optional chaining” because it also works for longer “chained” property access expressions like this one:
1 2 |
|
Conditional Invocation
- In ES2020, you can also invoke a function using
?.()
instead of()
. Normally when you invoke a function, if the expression to the left of the parentheses isnull
orundefined
or any other non-function, aTypeError
is thrown. With the new?.()
invocation syntax, if the expression to the left of the ?. evaluates tonull
orundefined
, then the entire invocation expression evaluates toundefined
and no exception is thrown. - Note, however, that
?.()
only checks whether the lefthand side isnull
orundefined
. It does not verify that the value is actually a function.
1 2 3 4 |
|
Object Creation Expression
1 2 3 4 5 6 7 |
|
eval()
eval()
expects one argument. If you pass any value other than a string, it simply returns that value.- If you pass a string, it attempts to parse the string as JavaScript code, throwing a
SyntaxError
if it fails. - If it successfully parses the string, then it evaluates the code and returns the value of the last expression or statement in the string or undefined if the last expression or statement had no value. If the evaluated string throws an exception, that exception propogates from the call to
eval()
. - The key thing about
eval()
(when invoked like this) is that it uses the variable environment of the code that calls it. That is, it looks up the values of variables and defines new variables and functions in the same way that local code does. If a function defines a local variablex
and then callseval("x")
, it will obtain the value of the local variable. If it callseval("x=1")
, it changes the value of the local variable.
First-Defined (??) operator
The first-defined operator ??
evaluates to its first defined operand: if its left operand is not null and not undefined, it returns that value. Otherwise, it returns the value of the right operand.
1 2 3 4 |
|
Statements
for/of
The for/of loop works with iterable objects
1 2 3 4 5 |
|
for/in
- A for/in loop looks a lot like a for/of loop, with the
of
keyword changed toin
. While a for/of loop requires an iterable object after theof
, a for/in loop works with any object after the in. - The for/of loop is new in ES6, but for/in has been part of JavaScript since the very beginning (which is why it has the more natural sounding syntax). Attempting to use for/of on a regular object throws a
TypeError
at runtime. - The for/in loop does not actually enumerate all properties of an object. It does not enumerate properties whose names are symbols. And of the properties whose names are strings, it only loops over the enumerable properties.
try-catch
Occasionally you may find yourself using a catch clause solely to detect and stop the propagation of an exception, even though you do not care about the type or the value of the exception. In ES2019 and later, you can omit the parentheses and the identifier and use the catch keyword bare in this case. Here is an example:
1 2 3 4 5 6 7 8 9 |
|
function
- The
function
declarations in any block of JavaScript code are processed before that code runs, and the function names are bound to the function objects throughout the block. We say that function declarations are “hoisted” because it is as if they had all been moved up to the top of whatever scope they are defined within. The upshot is that code that invokes a function can exist in your program before the code that declares the function. - Unlike functions,
class
declarations are not hoisted, and you cannot use a class declared this way in code that appears before the declaration.
import and export
- The
import
andexport
declarations are used together to make values defined in one module of JavaScript code available in another module. - A module is a file of JavaScript code with its own global namespace, completely independent of all other modules. The only way that a value (such as
function
orclass
) defined in one module can be used in another module is if the defining module exports it with export and the using module imports it with import. - The export directive has more variants than the import directive does. Here is one of them:
1 2 3 |
|
The export
keyword is sometimes used as a modifier on other declarations, resulting in a kind of compound declaration that defines a constant, variable, function, or class and exports it at the same time. And when a module exports only a single value, this is typically done with the special form export default:
1 2 3 |
|
A function is declared and exported from a file named math/addition.js
.
1 2 3 4 5 |
|
To use the above function in a different file,
1 2 3 4 5 6 |
|
We can also directly export on the function definition.
1 2 3 4 5 6 7 |
|
1 2 3 4 |
|
We can also import all the functions from the module using *
.
1 2 3 4 5 6 7 8 9 10 11 |
|
3rd party modules can be imported in the same fashion. Say, npm install --save lodash
1
|
|
Objects
- JavaScript object inherits the properties of another object, known as its “prototype.” The methods of an object are typically inherited properties, and this “prototypal inheritance” is a key feature of JavaScript.
- It is sometimes important to be able to distinguish between properties defined directly on an object and those that are inherited from a prototype object. JavaScript uses the term own property to refer to non-inherited properties.
- Property Attributes
- each property has three property attributes:
- The writable attribute specifies whether the value of the property can be set.
- The enumerable attribute specifies whether the property name is returned by a for/in loop.
- The configurable attribute specifies whether the property can be deleted and whether its attributes can be altered.
- each property has three property attributes:
- Many of JavaScript’s built-in objects have properties that are read-only, non-enumerable, or non-configurable. By default, however, all properties of the objects you create are writable, enumerable, and configurable.
Creating Objects
- Objects can be created with object literals, with the new
keyword, and with the Object.create()
function.
- Object literal: is a comma-separated list of colon-separated name:value pairs, enclosed within curly braces.
1 2 3 |
|
Prototypes
- Almost every JavaScript object has a second JavaScript object associated with it. This second object is known as a prototype, and the first object inherits properties from the prototype.
- Object.prototype
- All objects created by object literals have the same prototype object, and we can refer to this prototype object in JavaScript code as
Object.prototype
. - any object created by
{}
inherits fromObject.prototype
- any object created by
new Object()
inherits fromObject.prototype
- any object created by
new Array()
usesArray.prototype
as its prototype, - and any object created by
new Date()
usesDate.prototype
as its prototype.
- All objects created by object literals have the same prototype object, and we can refer to this prototype object in JavaScript code as
- Prototype Property
- almost all objects have a prototype, but only a relatively small number of objects have a
prototype
property. It is these objects withprototype
properties that define the prototypes for all the other objects.
- almost all objects have a prototype, but only a relatively small number of objects have a
Object.prototype
is one of the rare objects that has no prototype: it does not inherit any properties.- Other prototype objects are normal objects that do have a prototype.
- Most built-in constructors (and most user-defined constructors) have a prototype that inherits from
Object.prototype
. For example,Date.prototype
inherits properties fromObject.prototype
, so aDate
object created bynew Date()
inherits properties from bothDate.prototype
andObject.prototype
. This linked series of prototype objects is known as a prototype chain.
Object.create()
Object.create()
creates a new object, using its first argument as the prototype of that object- You can pass
null
to create a new object that does not have a prototype, but if you do this, the newly created object will not inherit anything, not even basic methods liketoString()
1 2 3 4 5 6 7 |
|
One common use for Object.create()
is for defensive copying
1 2 |
|
Inheritance
- Suppose you query the property
x
in the objecto
. - If
o
does not have an own property with that name, the prototype object ofo
is queried for the propertyx
. - If the prototype object does not have an own property by that name, but has a prototype itself, the query is performed on the prototype of the prototype.
- This continues until the property
x
is found or until an object with anull
prototype is searched. - As you can see, the prototype attribute of an object creates a chain or linked list from which properties are inherited:
1 2 3 4 5 6 7 8 |
|
The fact that inheritance occurs when querying properties but not when setting them is a key feature of JavaScript because it allows us to selectively override inherited properties.
Deleting Properties
delete
does not remove properties that have a configurable attribute offalse
.- Certain properties of built-in objects are non-configurable, as are properties of the
global
object created by variable declaration and function declaration. - In strict mode, attempting to delete a non-configurable property causes a
TypeError
. - In non-strict mode, delete simply evaluates to
false
in this case.
When deleting configurable properties of the global object in non-strict mode, you can omit the reference to the global object and simply follow the delete operator with the property name:
1 2 |
|
valueOf() method
The valueOf()
method is much like the toString()
method, but it is called when JavaScript needs to convert an object to some primitive type other than a string — typically, a number. JavaScript calls this method automatically if an object is used in a context where a primitive value is required.
1 2 3 4 5 6 7 8 9 10 11 |
|
Spread operator
In ES2018 and later, you can copy the properties of an existing object into a new object using the “spread operator” ...
inside an object literal:
1 2 3 |
|
- Not an operator
- Note that this
...
syntax is often called a spread operator but is not a true JavaScript operator in any sense. Instead, it is a special-case syntax available only within object literals. (Three dots are used for other purposes in other JavaScript contexts, but object literals are the only context where the three dots cause this kind of interpolation of one object into another one.)
- Note that this
- Performance
- Finally, it is worth noting that, although the spread operator is just three little dots in your code, it can represent a substantial amount of work to the JavaScript interpreter. If an object has n properties, the process of spreading those properties into another object is likely to be an
O(n)
operation. This means that if you find yourself using...
within a loop or recursive function as a way to accumulate data into one large object, you may be writing an inefficientO(n^2)
algorithm that will not scale well as n gets larger.
- Finally, it is worth noting that, although the spread operator is just three little dots in your code, it can represent a substantial amount of work to the JavaScript interpreter. If an object has n properties, the process of spreading those properties into another object is likely to be an
Shorthand methods
When a function is defined as a property of an object, we call that function a method.
1 2 3 4 5 |
|
1 2 3 4 5 |
|
Both forms of the code are equivalent: both add a property named area to the object literal, and both set the value of that property to the specified function. The shorthand syntax makes it clearer that area()
is a method and not a data property like side.
Getters and Setters
1 2 3 4 5 6 7 8 |
|
Other reasons to use accessor properties include sanity checking of property writes and returning different values on each property read:
Arrays
- Arrays inherit properties from
Array.prototype
, which defines a rich set of array manipulation methods - ES6 introduces a set of new array classes known collectively as “typed arrays.” Unlike regular JavaScript arrays, typed arrays have a fixed length and a fixed numeric element type. They offer high performance and byte-level access to binary data.
1
|
|
- Spread operator
- In ES6 and later, you can use the “spread operator,”
...
, to include the elements of one array within an array literal:
- In ES6 and later, you can use the “spread operator,”
1 2 |
|
Strings are iterable, so you can use a spread operator to turn any string into an array of single-character strings:
1 2 |
|
1 2 3 |
|
- With an iterable argument,
Array.from(iterable)
works like the spread operator[...iterable]
does. Array.from()
is also important because it defines a way to make a true-array copy of an array-like object.
1
|
|
Sparse Arrays
- A sparse array is one in which the elements do not have contiguous indexes starting at 0.
- Normally, the
length
property of an array specifies the number of elements in the array. - If the array is sparse, the value of the
length
property is greater than the number of elements. - Sparse arrays can be created with the
Array()
constructor or simply by assigning to an array index larger than the current array length. - Arrays that are sufficiently sparse are typically implemented in a slower, more memory-efficient way than dense arrays are, and looking up elements in such an array will take about as much time as regular object property lookup.
Note that when you omit a value in an array literal (using repeated commas as in [1,,3]), the resulting array is sparse, and the omitted elements simply do not exist:
1 2 3 |
|
Array length
if you set the length
property to a non-negative integer n
smaller than its current value, any array elements whose index is greater than or equal to n
are deleted from the array:
1 2 3 4 |
|
Adding/Deleting Array Elements
1 2 3 |
|
slice, splice
The slice()
method returns a slice, or subarray, of the specified array.
1 2 3 4 5 |
|
splice()
is a general-purpose method for inserting or removing elements from an array. Unlike slice()
and concat()
, splice()
modifies the array on which it is invoked.
1 2 3 4 |
|
Array-like Objects
JavaScript arrays have some special features that other objects do not have:
- The
length
property is automatically updated as new elements are added to the list. - Setting
length
to a smaller value truncates the array. - Arrays inherit useful methods from
Array.prototype
. Array.isArray()
returnstrue
for arrays.
Functions
- Function vs. Method: If a function is assigned to a property of an object, it is known as a method of that object. When a function is invoked on or through an object, that object is the invocation context or
this
value for the function. - Closures: JavaScript function definitions can be nested within other functions, and they have access to any variables that are in scope where they are defined. This means that JavaScript functions are closures, and it enables important and powerful programming techniques.
- Generators:
function*
defines generator functions -
async function: defines asynchronous functions
-
Declaring a Function
- Using
Function()
constructor.
- Using
- Hoisting: Function declaration statements are “hoisted” to the top of the enclosing script, function, or block so that functions defined in this way may be invoked from code that appears before the definition. Another way to say this is that all of the functions declared in a block of JavaScript code will be defined throughout that block, and they will be defined before the JavaScript interpreter begins to execute any of the code in that block.
Arrow Functions
- Arrow functions are most commonly used when you want to pass an unnamed function as an argument to another function.
- Diff b/w Arrow functions and other functions
- they inherit the value of the
this
keyword from the environment in which they are defined rather than defining their own invocation context as functions defined in other ways do. - they do not have a
prototype
property, which means that they cannot be used as constructor functions for new classes.
- they inherit the value of the
1 2 3 4 5 |
|
Default values in function parameters
1 2 3 4 5 |
|
1 2 3 |
|
or even better
1
|
|
Invoking Functions
- JS functions can be invoked in 5 ways:
- As functions e.g.,
factorial(3)
- As methods e.g.,
obj.method()
- As constructors e.g. ,
new Object()
ornew Object
- If a constructor explicitly uses thereturn
statement to return an object, then that object becomes the value of the invocation expression. - If the constructor usesreturn
with no value, or if it returns a primitive value, that return value is ignored and the new object is used as the value of the invocation. - Indirectly through their
call()
andapply()
methods - Both methods allow you to explicitly specify thethis
value for the invocation, which means you can invoke any function as a method of any object, even if it is not actually a method of that object. - Implicitly, via JavaScript language features that do not appear like normal function invocations
- When an object is used in a string context (such as when it is concatenated with a string), its
toString()
method is called. - Similarly, when an object is used in a numeric context, itsvalueOf()
method is invoked.
- As functions e.g.,
- Invocation Context
- in non-strict mode, the invocation context (the
this
value) is the global object. - in strict mode, however, the invocation context is
undefined
. Note that functions defined using the arrow syntax behave differently: they always inherit thethis
value that is in effect where they are defined.
- in non-strict mode, the invocation context (the
Note that
this
is a keyword, not a variable or property name. JavaScript syntax does not allow you to assign a value tothis
.
Function Arguments and Parameters
Parameter defaults enable us to write functions that can be invoked with fewer arguments than parameters.
1 2 3 4 |
|
Rest parameters enable the opposite of Parameter defaults: they allow us to write functions that can be invoked with arbitrarily more arguments than parameters.
1 2 3 4 |
|
Functions like the previous example that can accept any number of arguments are called variadic functions, variable arity functions, or vararg functions. This book uses the most colloquial term, varargs, which dates to the early days of the C programming language.
...
here is not the spread operator- Don’t confuse the
...
that defines a rest parameter in a function definition with the...
spread operator - The spread operator
...
is used to unpack, or “spread out,” the elements of an array (or any other iterable object, such as strings) in a context where individual values are expected. - When we use the same
...
syntax in a function definition rather than a function invocation, it has the opposite effect to the spread operator.
- Don’t confuse the
1 2 3 4 5 |
|
1 2 |
|
Shorthand properties
1 2 3 4 5 6 |
|
1 2 3 4 5 6 7 8 9 |
|
1 2 3 4 5 6 7 |
|
1 2 3 4 5 6 7 8 9 10 11 |
|
Spread operator
The spread operator allows you to “explode” an array into its individual elements.
1 2 |
|
1 2 3 4 5 6 |
|
1 2 3 |
|
1 2 3 4 5 6 |
|
Promises
- Promises in ES6 are very similar to those of Angular’s $q service.
- The callback inside of a promise takes two arguments,
resolve
andreject
. - Promises can either be resolved or rejected. When you resolve a promise, the
.then()
will fire, and when you reject a promise, the.catch()
will fire instead. Usually, inside of your promise, you have some sort of logic that decides whether you’re going to reject or resolve the promise. - The
.then()
method callback also takes an argument. This one we’ll calldata
. The value fordata
is the argument that is passed into theresolve
method. - Alternatively, in the
.catch()
method, we also have a callback function as the argument, but here, what will be passed back is the information that’s supplied into thereject
method of our promise.
1 2 3 4 5 6 7 8 9 10 11 |
|
- Promises are useful for a lot of things. Most importantly, they allow you to perform asynchronous operations in a synchronous-like manner
- For example, let’s add a 2 seconds timeout in the above code
1 2 3 4 5 6 7 8 9 |
|
There is a variation of .then()
method which takes error function as a 2nd parameter. But from readability perspective, it is better to keep them separate.
1 2 3 |
|
Several .then
methods can be chained together and have them called in succession. In this case, once the resolve
is called, both .thens will fire one after another.
1 2 3 |
|
As you notice, the 2nd then
input parameter data
is undefined
. This is because the data
that’s available in the callback of the second then
is not what is originally passed into the resolve
but rather what is returned from the 1st .then
method.
1 2 3 4 5 6 |
|
References
- Websites
- Book
- OReilly JavaScript - The Definitive Guide - David Flanagan