let
inside a block is valid only within the block: block-scope local variablelet
declaration has global scope
let a = "a"; // global vs local?
b = "b"; // global vs local?
function f()
{
c = "c"; // global vs local?
let d = "d"; // global vs local?
}
let
vs var
let
was introduced in ES6let
, var
was used with the following difference
var
has function scope (as opposed to block scope)var
is hoisted (vs no hoisting)
let
produces cleaner code. Use it!var
Examplevar a = 10; // global vs local?
function f() {
b = 10; // global vs local?
console.log(b);
var b;
}
f();
console.log(b);
typeof
returns function
not object
function square(x) { return x*x; };
function myfunc(x, func) {
return func(x);
}
myfunc(10, square);
myfunc(10, function (x) { return x * 2; }); // anonymous function
myfunc.a = 20;
function outer_function() {
console.log("a")
function inner_function() {
console.log(1);
}
console.log("b");
inner_function();
}
outer_function(); // what will be printed?
function f() {
let a = 1;
let b = 2;
function g() {
console.log(b); // b = ?
b = 3;
}
if (a > 0) {
let b = 4;
g();
console.log(b); // b = ?
}
console.log(b); // b = ?
}
f(); // what will be printed?
function getFunc() {
function printUCLA() { console.log("UCLA"); }
return printUCLA;
}
let func = getFunc();
func();
Closure: When a nested function references non-local variables and is returned, it is “bundled together” with the referenced variables
function getFunc() {
let age = 10;
function printAge() { console.log(++age); }
return printAge;
}
let func = getFunc();
func(); func(); // what will be printed?
printAge()
does not have its own local variable, but the returned printAge
carries the age
variable from its surrounding context!
function getFunc() {
let age = 10;
function printAge() { console.log(++age); }
return printAge;
}
let myFunc1 = getFunc();
myFunc1(); myFunc1();
let myFunc2 = getFunc();
myFunc2(); myFunc2();
(function() {
var count = 0;
function helper() {
console.log(`Help called ${++count} times!`);
}
helper();
// ...
helper();
})() // create an anonymous function and call it immediately
count
and helper()
In JavaScript, we often have to pass a function as a parameter
function ChangeColor(event) {
document.body.style.color = "red";
}
document.body.addEventListener("click", ChangeColor);
Polluting namespace can be avoided using anonymous functions
document.body.addEventListener("click", function(event) {
document.body.style.color = "red";
});
document.body.addEventListener("click", (event) => {
document.body.style.color = "red";
});
(param1, ...) => expression
(param1, ...) => { statements; }
() => expression
returns the value of expression
() => { statements; }
should return a value explicitlylet o = { x: 10 };
o.multiply = function (v) { this.x *= v; }
o.multiply(5);
console.log(o.x);
this
points to the object itselfclass Shape {
constructor(color) { // constructor() is class constructor
this.color = color;
}
info() { return "color: " + this.color; }
whoami() {
console.log("I am a Shape with " + this.info());
}
};
s = new Shape('blue');
s.whoami();
class Rectangle extends Shape {
constructor(color, x, y) {
super(color); // super refers to the parent class
this.x = x;
this.y = y;
}
info() {
return `${super.info()}, x: ${this.x}, y: ${this.y}`;
}
};
let r = new Rectangle("red", 2, 3);
r.whoami();
prototype
object
If a vaiable is undefined
or null
, we get an error
let obj;
console.log(obj.name); // Error: obj is undefined!
Checking for the error is ugly
let obj;
console.log(obj ? obj.name : undefined);
Instead of throwing an error, optional chaining operator returns undefined
:
let obj;
console.log(obj?.name); // returns undefined
this
this
is a source of great confusion and bug in JavaScriptthis
this
= called object/classthis
= DOM element to which event handler was setthis
= the global objectthis
in Event Handling Callthis
binds to the DOM element where the handler is set<body id="body_id">
...
</body>
<script>
document.body.addEventListener("click", function (event) {
console.log(this.id); // what does this bind to?
});
</script>
this
in Other Placesthis
is used in other than class method or event handler, this
binds to the global objectglobalThis
in ES2020)
window
objectglobal
objectthis
Binding() => {}
) does not provide its own this
binding
this
binding of the enclosing lexical context<body id="body_id">
...
</body>
<script>
document.body.addEventListener("click", (event) => {
console.log(this.id); // what does this bind to?
});
</script>
this
x = 10;
function_printx = function() { console.log(this.x); };
arrow_printx = () => { console.log(this.x); };
o = { x: 20 };
o.printx_f = function_printx;
o.printx_a = arrow_printx;
// What will be printed?
console.log(this.x);
function_printx();
arrow_printx();
o.printx_f();
o.printx_a();
this
this
changes dynamically depending on how a function is called
this
confusing and hard to understand, leading to many bugsthis
only in object/class methodreverse
, sort
, push
, pop
, shift
, unshift
, splice
concat
, slice
, filter
, map
let a = [1, 2, 3, 4];
let b = a;
console.log(b);
a[1] = 5;
console.log(b);
a = [1, 2, 3];
console.log(b);
let a = [1, 2, 3];
let b = a.reverse(); // reverse is a mutator
console.log(b);
a[1] = 6;
console.log(b);
a = [1, 2, 3];
b = a.concat([4, 5]); // concat is an accessor
console.log(b);
a[1] = 6;
console.log(b);
let o = { userid: 10, password: "secret" };
const { userid, password, email = "default_email" } = o;
// userid = 10, password = "secret", email = "default_email"
let a = [1, 2, 3, 4];
let [a1, a2, ...rest] = a;
// a1 = 1, a2 = 2, rest = [3, 4]
export
export
ed entities can be import
ed and used by other JavaScript code//------ lib.js ------
export function square(x) {
return x * x;
}
export function dist(x, y) {
return Math.sqrt(square(x) + square(y));
}
//------ main.js ------
import { square } from './lib.js';
square(11);
//----- main2.js ------
import * as mylib from './lib.js';
mylib.dist(4, 3);
//------ lib.js ------
export default function () { ... }
//------ main1.js ------
import myFunc from './lib.js';
myFunc();
{ }
to import default
export{ }
to import named export (even if we import just one)