Introduction to JS
Always bet on JavaScript.
What is JavaScript?
A very short history
ECMAScript is the official name for JavaScript. A new name became necessary because there is a trademark on JavaScript (held originally by Sun, now by Oracle).
Created by Brendan Eich in the year 1995
It is said that Brendan Eich created the first version of the langauge in around 10 days.
JS is a dynamically-typed, interpreted (or JIT-compiled), multi-paradigm, prototype-based high level language.
Most Popular
Developer Roles
StackOverflow
2020 Dev Survey
Most Popular Technologies
Unsurprisingly, for the eighth year in a row, JavaScript has maintained it's stronghold as the most commonly used programming language.
What can you build with JS?
- Rich and Interactive Web/Mobile apps
-
maps.google.com
-
facebook.com
-
Instagram app (earlier)
-
-
Desktop apps
- Using React Proton / Electron
- Real time networking apps
-
Google Meet
-
- Command line tools
- Using Node.js
- Games
- OnOff
- anything you can imagine much more
Where can you execute JS?
-
In the browsers directly
- Using the browser's console
- Using third-party web apps such as codesandbox.io
-
In an HTML File (again using the browser)
- Using <script> tag
-
In your PC
- Using Node.js
- IOT devices
JS (or ES) versions
- Originally called LiveScript, by Netscape (December 4, 1995)
- First standardized version (ECMAScript) in 1997
- Second version, 1998
- 3rd version, 1999
- 4th version, never released
- 5th version (ES5), December 2009
- 6th version (ES6 or ES2015), 2015
- 7th version (ES7 or ES2016), 2016
- 8th version (ES8 or ES2017), 2017
- 9th version (ES9 or ES2018), 2018
- 10th version (ES10 or ES2019), 2019
- 11th version (ES11 or ES2020), 2020
- 12th version (ES12 or ES2021), 2021
JS Basics
-
Syntax
-
Printing to the console
-
Variables and Scopes
- assignment / operator
-
basic operators (JS has a lots of them 🙃)
- mathematical (-, +, *, /, %, ++, --, **)
- relational (>=, <=)
- equality (==, ===, !=, !==)
- boolean (||, &&, !)
- ternary ( ? : )
-
Looping constructs
- C-style for
- while
- do-while
-
Control flow constructs
- if/else
- switch case
Variables and Scopes
Can be declared using
var let const
Scopes
The part of the program where a name has valid meaning or value.
- Global Scope
- Functional Scope
- Block Scope
Mutable | Either be global or functional in scope
Mutable | Either global or block in scope
Immutable | Either global or block in scope
The identifier can be any text except keywords and strings starting with special chars (such as numbers)
Variables and Assignment
- Variables in JavaScript are declared before they are used using var keyword.
- You can declare a variable and assign a value at the same time
var foo = 6;
foo = 4; // change variable `foo`
x += 1;
x = x + 1; // Compound Assignment Operators
Identifiers and Variable Names
Identifiers are names that play various syntactic roles in JavaScript.
- Roughly, the first character of an identifier can be any Unicode letter, a dollar sign ($), or an underscore (_).
- Subsequent characters can additionally be any Unicode digit. (except reserved words.)
Assignment ( = )
"set" a value to a variable (after declaration)
Compound assignment
+=
-=
*=
/=
%=
JS Basics
-
Syntax
-
Printing to the console
-
Variables and Scopes
-
basic operators
- mathematical (-, +, *, /, %, ++, --, **)
- relational (>=, <=)
- equality (==, ===, !=, !==)
- boolean (||, &&, !)
- ternary ( ? : )
-
Looping constructs
- C-style for
- while
- do-while
-
Control flow constructs
- if/else
- switch case
Expressions vs Statements
Statements “do things.” A program is a sequence of statements.
var x;
Expressions produce values.
3 * 6
Example
var x;
if (y >= 0) {
x = y;
} else {
x = -y;
}
var x = y >= 0 ? y : -y;
How to create functions?
Primarily 3️⃣ ways
- Function Declaration
-
Function Expression
- Anonymous Functions
- Function Constructor
(will not be discussed today)
Function Declaraion
function NAME_OF_FUNCTION(parameters) {
// list of statements
// optional return
}
- Uses the function keyword and mandatory name
- Is not in a position of an expression
- either at the Program level or directly in the body of another function
- Is hoisted
Function Expressions
- in the source code can only be defined at the expression positions
- can have an optional name
- When name is missing, it's an anonymous function
- Not hoisted
var foo = function () {
...
};
var foo = function _foo() {
...
};
Optional name
Executing a function
Functions can be executed (or called) by using two parentheses, passing arguments.
function sum(a, b) {
return a + b;
}
sum(4, 5);
a
b
One interesting thing about JS ✨
JS won't give an error if you pass fewer or more number of arguments to a function
sum(); // ✅: a = undefined, b = undefined
sum(5); // ✅: a = 5, b = undefined
sum(5, 4) // ✅: a = 5, b = 4
sum(5, 6, 7, 8, 9)// ✅: a = 5, b = 6,
// rest can be accessed using a special object
Should I put semicolons or not? 🤔
- Semicolons are optional in JavaScript (for users).
- However, it is recommended to always include them, otherwise JavaScript can guess wrong about the end of a statement.
😱
function sum(a, b) {
return
a + b
}
> sum(4,5)
9
function sum(a, b) {
return
{
sum: a+b
}
}
Example
Expected Output
> sum(4,5)
{ sum: 9 }
- Semicolons terminate statements, but not blocks.
- There is one case where you will see a semicolon after a block 🙃 :
- a function expression is an expression that ends with a block.
- If such an expression comes last in a statement, it is followed by a semicolon:
// Pattern: var _ = ___;
var x = 3 * 7;
var f = function () { }; // function expr. inside var decl.
How JS decides where to put a ; ?
The mechanism is called ASI (Automatic Semicolon Insertion)
Types of values in JS
- null
- undefined
- numbers
- strings
- boolean
- symbols
- bigint
- objects
JS values can be classified in two categories
- Primitive types
- Reference types (or objects)
JS has these types of values
no different type for ints or floats
everything (except the primitives) is object
that means arrays and functions are also objects 🤯
available for >=ES6
available for >=ES11
Primitive Values vs Objects
- The primitive values are booleans, numbers, strings, null, undefined, symbols (ES6), and bigint.
- All other values are objects.
> var obj1 = {}; // an empty object
> var obj2 = {}; // another empty object
> obj1 === obj2
false
> obj1 === obj1
true
Differences
- Primitives values are compared by value and not reference
- Primitive values are immutable
Since JS is dynamically-typed,
How can I find the type of a value? 🙋
You can use typeof operator to find the type of a value.
typeof results
undefined and null
- Most programming languages have values denoting missing information.
- JavaScript has two such “nonvalues,” undefined and null.
- undefined means “no value.”
- Uninitialized variables are undefined:
- Missing parameters are undefined
- If you read a nonexistent property, you get undefined
> var foo;
> foo
undefined
> function f(x) { return x }
> f()
undefined
> var obj = {}; // empty object
> obj.foo
undefined
numbers (IEEE-754 “Double”)
-
Number Literal ➡️ Just type the number
-
Only one number type (apart from bigint)
-
No integers
-
-
64-bit floating point (aka double)
-
Special Numbers are
-
NaN
-
Infinity
-
-
Does not map well to common understanding of arithmetic:
-
0.1 + 0.2 = 0.30000000000000004
-
NaN (Not a Number)
It is (generally) produced by error conditions. Example:
// trying to convert to numbers
> Number('abc')
NaN
> Number(undefined)
NaN
NaN is the only value that is not equal to itself:
> NaN === NaN
false
Special numbers
⚠️ Note ⚠️
typeof NaN is 'number' 😅
> typeof NaN
"number"
Infinity and -Infinity ♾️
Bigger and (smaller) than any numeric value in JS
1 / 0 === Infinity -1 / 0 === -Infinity any + number * Infinity === Infinity any + number / Infinity === 0
Number.MAX_SAFE_INTEGER
represents the maximum safe integer. == 2 ** 53 - 1
const x = Number.MAX_SAFE_INTEGER + 1;
const y = Number.MAX_SAFE_INTEGER + 2;
console.log(x === y); // 🤦 true
Number.MIN_SAFE_INTEGER
== -Number.MAX_SAFE_INTEGER
Number.MAX_VALUE | MIN_VALUE
represents the maximum (or minimum) numeric value representable in JavaScript.
Converting (casting) to Number
Value Type | Result |
---|---|
undefined | NaN |
null | 0 |
Boolean | True -> 1, false -> 0 |
number | same number |
string | try to convert the string to number. Empty string is 0. |
object | ToPrimitive algorithm |
Strings
- No independent char type
- Literal notation ➡️ type the text in single quote / double quote / backticks (>=ES6).
- The backslash (\) escapes characters and produces a few control characters.
- Single characters are accessed via square brackets notation.
'abc'
"abc"
'Did she say "Hello"?'
"Did she say \"Hello\"?"
'That\'s nice!'
"That's nice!"
'Line 1\nLine 2' // newline
'Backlash: \\'
> var str = 'abc';
> str[1]
'b'
Some common operations
Concatenation ( + )
> var messageCount = 3;
> 'You have ' + messageCount + ' messages'
'You have 3 messages'
var str = '';
str += 'Multiple ';
str += 'pieces ';
str += 'are concatenated.';
console.log(str)
'Multiple pieces are concatenated.'
Find length (number of characters)
let name = ''
> name.length
0
let name = 'arfat'
> name.length
5
Comparison (“dictionary” or “lexicographical” order)
'a' === 'a' // true
'a' === 'b' // false
'a' > 'b' // false
'A' > 'a' // false
'1' > 'a' // false
'Bee' > 'Be' // true: longer strings are greater if all else is equal
Booleans
There are two boolean values in JS.
true
false
Truthy values: Non-boolean values which evaluate to true
Falsy values: Non-boolean values which evaluate to false
These values are falsy (or false) in JS
- 0
- -0
- null
- undefined
- false
- NaN
- ''
- 0n
Number Zero
Negative zero -- 🤔 (an artifact of IEEE 754)
Empty String
The n denotes bigint number. 0n is bigint 0.
-
Array (as Objects)
-
Difference between Java arrays
-
Arrays are maps in JS
-
JS Arrays can contain any element type simultaneously
-
No need to specify the size upfront. Can extend dynamically.
-
-
Array Methods
-
map
-
filter
-
forEach
-
...
-
-
mutating and non-mutating methods
Arrays
-
An array is a map from indices (natural numbers, starting at zero) to arbitrary values.
-
The values are called the array’s elements.
-
The most convenient way of creating an array is via an array literal. ✅
> var arr = [ 'a', 'b', 'c' ]; // array literal
> arr[0] // get element 0
'a'
> arr[0] = 'x'; // set element 0 to 'x'
> arr
[ 'x', 'b', 'c' ]
-
The ECMAScript standard specifies arrays as maps (dictionaries) from indices to values.
Arrays Can Also Have Properties
-
Those are not considered part of the actual array; that is, they are not considered array elements.
> var arr = [ 'a', 'b' ];
> arr.foo = 123;
> arr
[ 'a', 'b' ]
> arr.foo
123
Since arrays are just objects
The .length property returns the number of elements currently present in the array.
Other ways of creating an array
Array Constructor ☠️
> var arr = new Array(2);
> arr.length
2
> arr // two holes plus trailing comma (ignored!)
[ , ,]
// The same as ['a', 'b', 'c']:
var arr1 = new Array('a', 'b', 'c');
// ☠️ AVOID this.
An empty array with a given length has only holes in it!
> new Array(2) // alas, not [ 2 ]
[ , ,]
> new Array(5.7) // alas, not [ 5.7 ]
RangeError: Invalid array length
> new Array('abc') // ok
[ 'abc' ]
Array.of() ✅
Creates a new Array instance from a variable number of arguments, regardless of number or type of the arguments.
Array.of(7); // [7]
Array(7); // array of 7 empty slots
Array.of(1, 2, 3); // [1, 2, 3]
Array(1, 2, 3); // [1, 2, 3]
How to check if a value is array⁉️
You can't use typeof, since the output will be 'object'
instanceof ☠️☠️
if (arr instanceof Array) {
console.log('arr is an array')
}
Array.isArray ✅
if (Array.isArray(arr)) {
console.log('arr is an array')
}
In some rare cases, instanceof can give wrong answers.
Array Methods
- Destructive methods
-
Non-destructive methods
- Iteration methods
- for-of loops
- forEach
- Searching Methods
- Concatenation
- Transformation
- Iteration methods
Broadly two kinds of methods
💡 Pro tip 💡: It's a good programming practice to minimize the use of destructive methods.
Array#push
Red means destructive
let livestock = ["🐷", "🐮", "🐔"];
livestock.push("🐴", "🐮");
// ["🐷", "🐮", "🐔", "🐴", "🐮"]
Array#pop
let livestock = ["🐷", "🐮", "🐔"];
let lastElem = livestock.pop();
console.log(lastElem) // "🐔"
console.log(livestock) // ["🐷", "🐮"]
Array#shift
const array1 = [1, 2, 3];
const firstElement =
array1.shift();
console.log(array1); // [2, 3]
console.log(firstElement); // 1
Array#unshift
let train = ["🚃", "🚃"];
train.unshift("🚂");
// ["🚂", "🚃", "🚃"]
Array#forEach
const numbers = [1, 2, 3, 4, 5, 6];
numbers.forEach(function (el) {
console.log(el);
});
- Takes a callback as an argument
- The callback receives the elements as arguments
- The return value of callback is not used
- break and continue don't work
for of loops (Not really an Array method)
const numbers = [1, 2, 3, 4];
for (const number of numbers) {
console.log(number);
}
Finding elements
Array#indexOf ❌ ☠️
let array = ['a', 1, '2', NaN];
console.log(array.indexOf('a')); // 0
console.log(array.indexOf(NaN)); // -1
returns index of the element or -1
let array = ['a', 1, '2', NaN];
console.log(array.includes('a')); // true
console.log(array.includes(NaN)); // true
console.log(array.includes('b')); // false
console.log(array.includes('a', 2)); // false
Array#includes ✅
Array#lastIndexOf ⚠️
const animals = [
'Dodo',
'Tiger',
'Penguin',
'Dodo',
NaN
];
animals.lastIndexOf('Dodo') // 3
animals.lastIndexOf('Tiger') // 1
animals.lastIndexOf(NaN) // -1
Array#reverse
let arr = [ 'a', 'b', 'c' ];
arr.reverse()
// [ 'c', 'b', 'a' ]
arr // reversing happened in-place
// [ 'c', 'b', 'a' ]
Array#fill
[1, 2, 3].fill(4); // [4, 4, 4]
[1, 2, 3].fill(4, 1); // [1, 4, 4]
[1, 2, 3].fill(4, 1, 2); // [1, 4, 3]
[1, 2, 3].fill(4, 1, 1); // [1, 2, 3]
[1, 2, 3].fill(4, 3, 3); // [1, 2, 3]
changes all elements in an array to a static value, from a start index (default 0) to an end index (default array.length).
Array#sort ⚠️⚠️
> let arr = ['banana', 'apple', 'pear', 'orange'];
> arr.sort()
[ 'apple', 'banana', 'orange', 'pear' ]
> arr // sorting happened in place
[ 'apple', 'banana', 'orange', 'pear' ]
let array = [1, 10, 101, 2, 3, 1001];
array.sort();
console.log(array);
// [1, 10, 1001, 101, 2, 3];
-
Array#concat
- merge two or more arrays
-
Array#join
- join the elements into a string using a separator
-
Array#slice
- returns a shallow copy of a portion of an array
> [3, 4, 5].join('-')
'3-4-5'
> [3, 4, 5].join()
'3,4,5'
> [3, 4, 5].join('')
'345'
> [undefined, null].join('#')
'#'
> [ 'a', 'b', 'c', 'd' ].slice(1, 3)
[ 'b', 'c' ]
Array#map
- takes a callback as an argument
- transforms each element of the array using the callback
- returns a new array with the transformed elements
-
originalArray.length === newArray.length
const hungryMonkeys = ['🐒', '🦍', '🦧'];
const fedMonkeys = hungryMonkeys.map(function (monkey) {
return monkey + '🍌';
});
// ["🐒🍌", "🦍🍌", "🦧🍌"]
const numbers = [1, 2, 3, 4, 5, 6];
const squares = numbers.map(function (el) {
return el * el;
});
console.log(squares);
// [ 1, 4, 9, 16, 25, 36 ]
Array#filter
- takes a callback as an argument
- executes the callback on each element
- if callback returns true, the value is included in the new returned array
-
0 <= newArray.length <= originalArray.length
const numbers = [1, 2, 3, 4, 5, 6];
const evens = numbers.filter(function (el) {
return el % 2 === 0;
});
console.log(evens);
// [ 2, 4, 6 ]
Error Handling
Exceptions are anomalous or exceptional conditions that require special processing during the execution of a program.
throw statement
The throw statement throws a user-defined exception.
Important Note
- Execution of the current function will stop (the statements after throw won't be executed), and control will be passed to the first catch block in the call stack.
- If no catch block exists among caller functions, the program will terminate.
throw expression;
function a() {
b();
}
function b() {
c();
}
function c() {
d();
}
function d() {
throw 'error in d';
}
a();
- The runtime system searches the call stack for a method that contains a block of code that can handle the exception.
- This block of code is called an exception handler.
- What if no exception?
try {
try_statements
}
catch (exception_var) {
catch_statements
}
finally {
finally_statements
}
Catching an exception
function a() {
b();
}
function b() {
try {
c();
console.log('after c()')
} catch (ex) {
console.log('caught this exception -- ', ex);
}
}
function c() {
d();
}
function d() {
throw 'error in d';
}
a();
Error
It's not a good idea to throw random expressions. You should always throw an object of the Error class (or something similar).
function a() {
b();
}
function b() {
try {
c();
} catch (ex) {
console.log('caught this exception -- ');
console.log(ex);
}
}
function c() {
d();
}
function d() {
throw new Error('error in d');
}
a();
The finally Block
The finally block always executes when the try block exits.
It always executes, regardless of whether an exception was thrown or caught.
openMyFile();
try {
// tie up a resource
writeMyFile(theData);
} finally {
closeMyFile(); // always close the resource
}
JavaScript’s Type System
-
Static Versus Dynamic
-
Static Typing Versus Dynamic Typing
-
Static Type Checking Versus Dynamic Type Checking
-
JS Types
-
Coercion
-
== vs ===
Static vs Dynamic
In the context of language semantics and type systems, “static” usually means “at compile time” or “without running a program”, while “dynamic” means “at runtime”.
Static typing versus dynamic typing
- In a statically typed language, variables, parameters and members of objects (JavaScript calls them properties) have types that the compiler knows at compile time.
- The compiler can use that information to perform type checks and to optimize the compiled code.
Static type checking versus dynamic type checking
- If you have type information, you can check whether a value that is transported to another location (via a function call, an assignment, etc.) has the correct type.
- Statically type-checked languages perform this kind of check at compile time, dynamically type-checked languages at runtime.
- A language can be both statically type-checked and dynamically type-checked.
In JavaScript, the main way of dealing with a value whose type doesn’t fit is to coerce it to the correct type. Coercion means implicit type conversion. Most operands coerce:
> '3' * '4'
12
- Implicit coercion
- Explicit coercion
JS types
JS has 6 (5 primitive + 1 object in ES5) types that are dynamically typed and (mostly) dynamically typed-checked.
Coercion
== vs ===
Strict equality (===) and strict inequality (!==) consider only values that have the same type to be equal.
Normal (or “lenient”) equality (==) and inequality (!=) try to convert values of different types before comparing them as with strict (in)equality.
> undefined == null
true
> 1 == true
true
> 0 == false
true
> '' == false
true
> '1' == true
true
Coercion
true + false
1
12 / "6"
2
"number" + 15 + 3
"number153"
15 + 3 + "number"
"18number"
[1] > null
true
"foo" + + "bar"
"fooNaN"
'true' == true
false
false == 'false'
false
null == ''
false
!!"false" == !!"true"
true
"Why am I a " + typeof + "";
"Why am I a number"
Functions can act in various ways in JavaScript. Let’s look at them —
Traditional Functions (that is, outside any object)
function add1(num1, num2) { // function declaration
return num1 + num2;
}
const add2 = function(num1, num2) { // function expression
return num1 + num2;
}
Object’s methods (inside an object)
- In this case, the functions are embedded in objects. In most cases, they are supposed to act on data stored in the object itself.
- For example, in the code below, getName() method returns the name property stored in details object.
const details = {
name: 'Arfat',
getName: function () {
return this.name;
}
}
details.getName(); // 'Arfat'
Constructor Functions
- Constructor functions “construct” objects. They are equivalent to classes in other languages.
- A class is considered as a factory for the production of “instances” or “objects”.
- Since JavaScript has no concept of a class (even though it has class keyword), functions rise up to the task.
- A function, when used with the new operator, is called a constructor function. The new operator changes the behavior of the function.
function Person(name) {
this.name = name;
}
const person1 = new Person('Arfat');
console.log(person1);
// Person { name: 'Arfat' }
Factory (object-oriented programming)
In object-oriented programming (OOP), a factory is an object for creating other objects – formally a factory is a function or method that returns objects of a varying prototype or class from some method call, which is assumed to be "new".
- A factory is an abstraction of a constructor of a class, while in prototype-based programming a factory is an abstraction of a prototype object.
- A constructor is concrete in that it creates objects as instances of a single class, and by a specified process (class instantiation), while a factory can create objects by instantiating various classes, or by using other allocation schemes such as an object pool.
var e = 10;
function sum(a) {
return function(b) {
return function(c) {
return function(d) {
return a + b + c + d + e;
}
}
}
}
sum(1)(2)(3)
function a() {
let fn;
{
var x = 5;
fn = function() {
console.log(x);
}
}
return fn;
}
var x = 10;
const b = a();
b();
var a = 100;
function outer(x) {
var a = 10;
return function (y) {
return a + y;
}
}
a = 50;
var inner = outer(20);
function abc() {
var a = 30;
console.log(inner(5));
}
abc();
Executable Code and Execution Contexts
- A Lexical Environment is a specification type used to define the association of Identifiers to specific variables and functions based upon the lexical nesting structure of ECMAScript code.
- A Lexical Environment consists of an Environment Record and a possibly null reference to an outer Lexical Environment.
- Usually a Lexical Environment is associated with some specific syntactic structure of ECMAScript code such as a FunctionDeclaration, a BlockStatement, or a Catch clause of a TryStatement and a new Lexical Environment is created each time such code is evaluated.
An Environment Record records the identifier bindings that are created within the scope of its associated Lexical Environment. It is referred to as the Lexical Environment's EnvironmentRecord.
- The outer environment reference is used to model the logical nesting of Lexical Environment values.
- The outer reference of a (inner) Lexical Environment is a reference to the Lexical Environment that logically surrounds the inner Lexical Environment.
- An outer Lexical Environment may, of course, have its own outer Lexical Environment.
- A Lexical Environment may serve as the outer environment for multiple inner Lexical Environments.
For example, if a FunctionDeclaration contains two nested FunctionDeclarations then the Lexical Environments of each of the nested functions will have as their outer Lexical Environment the Lexical Environment of the current evaluation of the surrounding function.
- A global environment is a Lexical Environment which does not have an outer environment.
- The global environment's outer environment reference is null.
- A global environment's EnvironmentRecord may be prepopulated with identifier bindings and includes an associated global object whose properties provide some of the global environment's identifier bindings.
As ECMAScript code is executed, additional properties may be added to the global object and the initial properties may be modified.
- A function environment is a Lexical Environment that corresponds to the invocation of an ECMAScript function object.
- A function environment may establish a new this binding.
- A function environment also captures the state necessary to support super method invocations.
Environment Records
- A function Environment Record is a declarative Environment Record that is used to represent the top-level scope of a function and, if the function is not an ArrowFunction, provides a this binding.
- If a function is not an ArrowFunction function and references super, its function Environment Record also contains the state that is used to perform super method invocations from within the function.
- Each declarative Environment Record is associated with an ECMAScript program scope containing variable, constant, let, class, module, import, and/or function declarations. A declarative Environment Record binds the set of identifiers defined by the declarations contained within its scope.
Execution Contexts
- An execution context is a specification device that is used to track the runtime evaluation of code by an ECMAScript implementation.
- At any point in time, there is at most one execution context per agent that is actually executing code.
- This is known as the agent's running execution context.
- The execution context stack is used to track execution contexts. The running execution context is always the top element of this stack.
Execution contexts for ECMAScript code have the additional state components listed in Table.
Component | Purpose |
---|---|
LexicalEnvironment | Identifies the Lexical Environment used to resolve identifier references made by code within this execution context. |
VariableEnvironment | Identifies the Lexical Environment whose EnvironmentRecord holds bindings created by VariableStatements within this execution context. |
First-class functions
A first-class function is one that may participate as a normal data, i.e. be created literally at runtime, be passed as an argument, or be returned as a value from another function.
Free variable
A free variable is a variable which is used by a function, but is neither a parameter, nor a local variable of the function.
Closure
A closure is a pair consisting of the function code and the environment in which the function is created.
Segment 2
function f() {
this.name = 'arfat';
}
f();
function f() {
'use strict'
this.name = 'arfat';
}
f();
const obj = {
name: 'Arfat',
f: function() {
console.log(this.name);
}
};
obj.f();
const obj = {
name: 'Arfat',
f: function() {
console.log(this.name);
}
};
var g = obj.f;
g();
setTimeout(obj.f, 2000);
var obj = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
loop: function () {
this.friends.forEach(
function(friend) { // (1)
console.log(this.name+' knows '+friend); // (2)
}
);
}
};
obj.loop();
Objects
An object is a
collection of properties
A
property is a
named container for a
value
w/ some additional attributes
Definition
The
name of a property
is called
a
key
;
thus,
an object
can be considered as
a
collection of key-value pairs
.
There are similar concepts in other programming languages,
e.g.,
Map, Dictionary, Associative Array, Symbol Table, Hash Table
, ...
-
Property Accessors (Dot and square notations)
-
this in objects
-
Other gotchas when using this.
-
Functions Inside Methods Shadow this
-
Losing this When Extracting a Method
-
-
Inheritance
-
Javascript inheritance by examples
-
Setting and Deleting Affects Only Own Properties
-
Sharing Data Between Objects via a Prototype
-
Prototypal Chain
-
Review
Properties
-
all objects in JavaScript are maps (dictionaries) from strings to values.
-
A (key, value) entry in an object is called a property . The key of a property is always a text string.
-
3 Kinds of Properties
-
Properties (or named data properties)
-
Accessors (or named accessor properties)
-
Internal properties
-
Exist only in the ECMAScript language specification.
-
Accessing Properties
Dot Notation
var jane = {
name: 'Jane',
'desc.func': function () {
return 'Person named ' + this.name;
},
};
$ jane.name
// 'jane'
$ jane['desc.func']
// [Function]
Bracket Notation
this in objects
this refers to the object on which the method has been invoked
> var obj = { method: returnThisStrict };
> obj.method() === obj
true
Normal functions in sloppy mode
function returnThisSloppy() {
return this
}
> returnThisSloppy() === window
true
Normal functions in strict mode
function returnThisStrict() {
'use strict';
return this
}
> returnThisStrict() === undefined
true
Pitfalls
Losing this When Extracting a Method
var counter = {
count: 0,
inc: function () {
this.count++;
}
}
-
We have called the value of counter.inc as a function.
-
Hence, this is the global object and we have performed window.count++ .
-
window.count does not exist and is undefined . Applying the ++ operator to it sets it to NaN.
-
Use strict mode for avoiding this.
> var func = counter.inc;
> func()
> counter.count // didn’t work
0
How to properly extract a method
> var func3 = counter.inc.bind(counter);
> func3()
> counter.count // it worked!
1
Callbacks and extracted methods
function callIt(callback) {
callback();
}
> callIt(counter.inc)
❌
✓
> callIt(counter.inc.bind(counter))
Pitfall
Functions Inside Methods Shadow this
var obj = {
name: 'Jane',
friends: [ 'Tarzan', 'Cheeta' ],
loop: function () {
'use strict';
this.friends.forEach(
function (friend) { // (1)
console.log(this.name+' knows '+friend); // (2)
}
);
}
};
> obj.loop()
What to do?
Workaround 1: that = this
loop: function () {
'use strict';
var that = this;
this.friends.forEach(function (friend) {
console.log(that.name+' knows '+friend);
});
}
Workaround 2: bind()
loop: function () {
'use strict';
this.friends.forEach(function (friend) {
console.log(this.name+' knows '+friend);
}.bind(this)); // (1)
}
Workaround 3: a thisValue for forEach()
this.friends.forEach(function (friend) {
console.log(this.name+' knows '+friend);
}, this);
How this changes?
Global Context
In the global execution context (outside of any function), this refers to the global object whether in strict mode or not.
Function context
Inside a function, the value of this depends on how the function is called.
Simple Call
Since the following code is not in strict mode, and because the value of this is not set by the call, this will default to the global object, which is window in a browser.
function f1() {
return this;
}
// In a browser:
f1() === window; // true
// In Node:
f1() === global; // true
Arrow functions
In arrow functions, this retains the value of the enclosing lexical context's this. In global code, it will be set to the global object:
As an object method
When a function is called as a method of an object, it's this is set to the object the method is called on.
this on the object's prototype chain
var o = {f: function() { return this.a + this.b; }};
var p = Object.create(o);
p.a = 1;
p.b = 4;
console.log(p.f()); // 5
If the method is on an object's prototype chain, this refers to the object the method was called on, as if the method were on the object.
As a constructor
When a function is used as a constructor (with the new keyword), its this is bound to the new object being constructed.
As a DOM event handler
When a function is used as an event handler, its this is set to the element the event fired from (some browsers do not follow this convention for listeners added dynamically with methods other than addEventListener()).
In an inline event handler
When the code is called from an inline on-event handler, its this is set to the DOM element on which the listener is placed:
<button onclick="alert((function() { return this; })());">
Show inner this
</button>
Introduction to JavaScript
By Arfat Salman
Introduction to JavaScript
A Brief intro of JS.
- 1,881