Level up your JavaScript
Wipe out confusion and become confident
Agenda
-
→ Function in depth
Scope, hoisting, closure -
bind, call, apply
explicitly set value of this. -
How JS works
Stack, Heap, Event loop. -
Promise
blocking, non-blocking... -
this
De-mystify notorious this -
Inheritance
Prototype chain.
Who is this dude?
-
- @jsdude005
- Organize Chicago JavaScript meetup
- Sr. Web Developer, Nielsen
- Enjoy Learning, talking about JavaScript
Why Core JavaScript?
You are still coding JavaScript and your friendly framework will not be around forever.
-
You need JavaScript to use the Framework.
Just only a framework will not a build an application. To put logic, functionalities, you have to use javascript.
-
Magic will through you in trouble.
Magic is good to do simple things. For large application, magic in frameworks will through you under the bus.
-
Feel why it works not how it works.
Making things working and understanding .
Function
Create a function
Declaration
function foo(a, b){
return a * b;
}
Expression - anonymous
var foo = function(a, b){
return a * b;
}
Expression - named
var foo = function boo(a, b){
console.log(boo);
return a * b;
}
var foo = new Function("a", "b", "return a * b;");
function in JS
function add(a,b){
return a + b;
}
console.log(add.length); //2
function like an object
could have property
have a length property
length is number of parameters
function in JS
function add(a,b){
return a+b;
}
console.log(add(2,3));//5
function noFunc(){
}
console.log(noFunc());//undefined
Always return
Default return is
undefined
"new" for constructor returns this
function add(a,b){
return a+b;
}
var b = add(2,3);
console.log(b); //5
function add(a,b){
return a+b;
}
var b = new add(2,3);
console.log(b); //add{}
function add(a,b){
this.a = a;
this.b = b;
return a+b;
}
var b = new add(2,3);
console.log(b);
//add{a:2, b:3}
arguments
- all the arguments passed to the function
function add(a,b){
console.log(arguments);
return a+b;
}
add(2,3);
//[2,3]
function add(a,b){
console.log(arguments);
return a+b;
}
add(2,3,5,7);
//[2,3,5,7]
function add(a,b){
console.log(arguments);
return a+b;
}
add();
//[]
Function Execution
function foo(a, b){
return a * b;
}
foo(2,3);
-
Creation Stage.
-
Execution Stage.
Creation Stage
Each function call creates own ExectuionContext
Roughly an 'environment' where function executes
inner variable, inner function
function foo(a, b){
function inner(){
console.log(a);
}
inner();
var c = a * b;
return c;
}
inner variable, inner function
function foo(a, b){
function inner(){
console.log(c);
}
inner();
var c = a * b;
return c;
}
scanning and adding to the variable object
ExecutionContext: {
scopeChain : { ... },
variableObject: {
arguments:{
0 : 2,
1 : 3,
length : 2
},
a : 2,
b : 3,
inner : pointer to function inner,
c : undefined
}
}
Execution Context and Scope
A concept in the language spec
Roughly an 'environment' where function executes
It holds: scope, scope chain, arguments, variables
Each function call creates own ExectuionContext
Scope is static
Set when function is created and never changes
Scope is a property of the function
Execution stage
Start reading the code from first line
Assign values
If need to access variable, it read from ExecutionContext
Until hits first return or body ends
Summary
Two stages of function: creation, execution
Creates execution context (before running any code)
First thing created is the scope chain
Then it creates variableObject
Create arguments, variable, determine
this
Execute function
Scope chain
A collection of
Current execution context
All parent execution context
JavaScript Scope
Global scope
Local scope
Block scope
- Lexical scope
Global...Globe
Global scope
var a = 2;
function b(){
console.log(a);
}
Local Scope
Local/function scope
-
function call creates execution context (before running any code)
-
First thing created is the scope chain
-
Create arguments, variable, determine
this
-
variables and inner functions are available inside only
function usa(){
var kim = 21;
console.log(kim);
}
usa(); // 21
console.log(kim);
//Uncaught ReferenceError: kim is not defined
JS scope chain
Multi execution context
var a = 2;
function b(){
console.log(a);
}
function c(){
console.log(a);
}
b();
c();
local events
Block Scope
-
Block: Anything inside curly braces
-
Javascript Block statements do not introduce a scope
-
JavaScript(up to ES5) does not have block scope.
-
Variables introduced within a block are scoped to the containing function or script
for(var i = 0; i<5; i++){
var twice = i*2;
}
console.log(i);// 5
console.log(twice);//8
ES6: let and const
-
let: declares a block scope local variable
-
Current block and contained sub-blocks
-
const: can not be reassigned.
-
const can be recreated inside a loop
for(let i = 0; i<5; i++){
const twice = i*2;
}
console.log(i);
//Uncaught ReferenceError: i is not defined
console.log(twice);
//Uncaught ReferenceError: twice is not defined
Closure
function in a function
function counter(){
var i = 0;
return function(){
return i++;
}
}
var a = counter();
a;
//function (){
// return i++;
//}
a(); //0
a(); //1
a(); //2
Lexical scope/Scope Chain
function counter(){
var i = 0;
return function(){
return i++;
}
}
const a = counter();
a(); // 0
Lexical Scoping defines how variable names are resolved in nested functions: inner functions contain the scope of parent functions even if the parent function has returned.
Multiple Closure
-
Every assignment of counter function creates new closure
-
Private variable
-
Save state
-
Create encapsulation
Who cares?
Garbage collector: can not claim the variable you are holding.
How many closure are you creating?
Variable reference: Don't use excessively large private variable
Unnecessary closure affect processing speed and memory consumption
Closure in Summary
function inside another function
Doesn't have to return function
Refer to variables, parameters outside of current scope
Read and write outer scope variable
Each closure has separate private variable
Closure for dummies
so far...
function could have properties
Two stages of function call: Creation, Execution
ExecutionContext: Scope chain, variableObj, this
Jackie Chan, Kim Kardashian, super bowl
Scope chain: collection of current + all parent Execution context
Closure: save states and create encapsulation
Hoist a variable
function foo(a, b){
function inner(){
console.log(a);
}
inner();
var c = a * b;
return c;
}
ExecutionContext: {
scopeChain : { ... },
variableObject: {
arguments:{
0 : 2,
1 : 3,
length : 2
},
a : 2,
b : 3,
inner : pointer to function inner,
c : undefined
}
}
Just Looping
function justLooping() {
for (var i = 0; i < 5; i++) {
var twice = i*2;
}
console.log(i);
console.log(twice);
}
justLooping();// 5 8
function justLooping() {
var i;
var twice;
for (i = 0; i < 5; i++) {
twice = i*2;
}
console.log(i);
console.log(twice);
}
justLooping(); // 5 8
Hoist function declaration with definition
function outer(){
inner();
function inner(){
console.log('inside inner function');
}
}
outer();
function outer(){
function inner(){
console.log('inside inner');
}
inner();
}
outer();
Hoist function name only for function expression
function outer(){
inner();
var inner = function(){
console.log('inside inner');
}
}
outer();
//Uncaught TypeError: inner is not a function
function outer(){
var inner;
inner();
inner = function(){
console.log('inside inner');
}
}
outer();
//Uncaught TypeError: inner is not a function
Million dollar question
var a = 1;
function bar(){
a = 10;
return;
var a = 7;
}
bar();
console.log(a);//?
function foo(){
var f = function() {
console.log("original");
}
function f() {
console.log("duplicate");
}
f();
}
foo(); //?
Class
Inheritance: in JavaScript
-
JavaScript only has one construct: objects
-
Each object has a private property (referred to as [[Prototype]] )
-
Holds a link to another object called its prototype
-
That prototype object has a prototype of its own
-
Until an object is reached with null as its prototype
-
By definition, null has no prototype, and acts as the final link in this prototype chain
Prototype Chain
var o = object.create(null);
var o = {
id: 42,
name: 'john'
}
function Entity(id, name){
this.id = id;
this.name = name;
}
Using Object (without constructor)
var person = {
hours: 5,
getHours: function() {
return this.hours + 3;
}
};
person.getHours(); // 8
var manager = Object.create(person);
// manager is an object that inherits from person
manager.getHours(); //8
// creates an own property 'hours' on manager
manager.hours = 1;
manager.getHours(); //4
Using constructor
function Person (id, hours) {
this.id = id;
this.hours = hours;
this.getHours = function() {
return this.id + ' works:' + this.hours +'hr';
};
}
function Person (id, hours) {
this.id = id;
this.hours = hours;
}
Person.prototype.getHours = function() {
return this.id + ' works:' + this.hours +'hr';
};
Get what is in prototype
var dad = {
fathersName:'big Dad'
}
var child = Object.create(dad);
child.whoIsYourFather = function(){
return this.fathersName;
}
child.whoIsYourFather(); //big Dad
child.hasOwnProperty('fathersName'); //false
Object.getPrototypeOf(child);
//{fathersName: "big Dad"}
this
walks through prototype chain.
ES6 - class (syntactical sugar )
function User(name) {
this.name = name;
}
User.prototype.sayHi = function() {
return 'Hi '+ this.name;
}
let user = new User("John");
user.sayHi();
class User {
constructor(name) {
this.name = name;
}
sayHi() {
return 'Hi ' + this.name;
}
}
let user = new User("John");
user.sayHi();
What is this?
console.log(this);//window
function whatIsThis() {
return this;
}
whatIsThis(); //window
function justAddName(name) {
this.name = name;
return this;
}
justAddName("Amy Farrah Fowler");//window
console.log(window.name); //Amy Farrah Fowler
What is this really?
(function(){
console.log(this);
})();
//window
(function(){
'use strict';
console.log(this);
})();
//undefined
Give my this
back in strict mode
(function(self){
'use strict';
console.log(self);
})(this);
//window
(function(){
'use strict';
console.log(this);
}).call(this);
//window
Spec 10.4.3
this of an Object
var buddy = {
firstName:'Penny',
lastName:this.firstName,
context:this
}
buddy.firstName; //Penny
buddy.lastName;//undefined
buddy.context;//window
var buddy = {
firstName:'Penny',
getName:function(){
return this.firstName;
},
getContext: function() {
return this;
}
};
buddy.getName(); //Penny
buddy.getContext();
// Object {getContext: function}
Understand the context of execution
var a = {
b: function() {
return this;
}
};
a.b();
//Object {b: function}
var foo = a.b;
console.log(foo);
/* function(){
return this;
};*/
foo(); //window
window.foo(); //window
var d = {
d:'my D'
};
d.c = a.b;
d.c();
//Object {d:'my D', c: function}
Watch left side of dot(.)
Some more execution context
var a = {
b: function() {
var c = function() {
console.log(this);
};
c();
}
};
a.b();//window
var a = {
b: function() {
(function() {
console.log(this);
})();
}
};
a.b(); //window
strict mode will return undefined
context of thissetTimeout inside constructor
function Menu(item){
this.item = item;
this.context = this;
setTimeout(function(){
console.log('setTimeout context:', this);
}, 10);
}
var lunch = new Menu('pizza');
//setTimeout context: window
lunch.context;
//Menu {item: "pizza", context: Menu}
Same behavior with setInterval
How to fix this?
function Menu(item){
var that = this;
this.item = item;
this.context = this;
setTimeout(function(){
console.log('setTimeout context:', that);
}, 10);
}
var lunch = new Menu('pizza');
//setTimeout context: Menu {item: "pizza", context: Menu}
lunch.context;
//Menu {item: "pizza", context: Menu}
function Menu(item){
this.item = item;
this.context = this;
setTimeout( () => {
console.log('setTimeout context:', this);
}, 10);
}
var lunch = new Menu('pizza');
//setTimeout context: Menu {item: "pizza", context: Menu}
lunch.context;
//Menu {item: "pizza", context: Menu}
DOM event handler
this = the element that fired the event
//execute it in console
document.getElementById('myButton')
.addEventListener('click', function(){
console.log(this);
});
function Bluify(e){
// Always true
console.log(this === e.currentTarget);
this.style.backgroundColor = 'blue';
}
Now. I know this
left of dot(.) will indicate value of this
window (no dot)
undefined (strict mode IIFE)
object (left of dot('.') for a method call)
newly constructed object (constructor: new keyword)
window (inside setTimeout)
element fired the event, inside event handler
use bind, call, apply to set value of this explicitly
JS: execution context
Explicitly set this
bind any function that has this
Create a new function by holding the context(this) to be used later such as dom binding.
function getMonthlyFee(fee){
var remaining = this.total - fee;
this.total = remaining;
return this.name +' remaining balance:'
+ remaining;
}
var rachel = {
name:'Rachel Green',
total:500
};
//bind
var getRachelFee = getMonthlyFee.bind(rachel, 90);
//deduct
getRachelFee();
//Rachel Green remaining balance:410
getRachelFee();
//Rachel Green remaining balance:320
bind any method on other object
var monica = {
name: 'Monica',
getMonthlyFee: function(fee){
var remaining = this.total - fee;
this.total = remaining;
return this.name +' remaining balance:'
+ remaining;
}
}
var ross = {
name:'Ross Geller',
total:250
};
//bind
var getRossFee = monica.getMonthlyFee.bind(ross, 25);
//deduct
getRossFee();
//Ross Geller remaining balance:225
getRossFee();
//Ross Geller remaining balance:200
call and apply
Just use the provided context and execute immediately
function lunch(budget, time){
return this.menu +' for ' + budget +' within '+ time +' min.';
}
var forDev = {menu: 'pizza'};
lunch.call(forDev, 5, 10);//pizza for 5 within 10 min.
lunch.apply(forDev, [5, 10]);//pizza for 5 within 10 min.
this
in arguments
8 function allows thisArg
Function.prototype.bind( thisArg [ , arg1 [ , arg2, ... ] ] )
Function.prototype.call( thisArg [ , arg1 [ , arg2, ... ] ] )
Function.prototype.apply( thisArg, argArray )
Array.prototype.every( callbackfn [ , thisArg ] )
Array.prototype.some( callbackfn [ , thisArg ] )
Array.prototype.forEach( callbackfn [ , thisArg ] )
Array.prototype.map( callbackfn [ , thisArg ] )
Array.prototype.filter( callbackfn [ , thisArg ] )
What is JavaScript?
How JavaScript works?
A single-threaded, non-blocking, asnchronous concurrent runtime
I am a programmer, give me detail
Maintain a call stack, event loop, queue, etc.
Are these in JS?
No. They are in JavaScript implementation.
call stack
function multiply(a,b){
return a * b;
}
function square (n){
return multiply(n,n);
}
function consoleSquare(n){
var squared = square(n);
console.log(squared);
}
consoleSquare(3);
Call stack
multiply
square
consoleSquare
Stack overflow
function foo(){
foo();
}
Call stack
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
foo
Blocking
Blocking methods execute synchronously
Non-blocking methods execute asynchronously
Does networking or uses timers
Usually takes a callback
Async stack
console.log('Hi');
setTimeout(function(){
console.log('Chicago');
}, 2000)
console.log('There');
// Hi
// There
// Chicago
Call stack
console.log('There')
???
console.log('Hi')
Concurrency model and Event Loop
-
Stack: frames of call
-
Heap: Objects allocated in teh memory
-
Queue: Runtime list of messages to be processed
-
Event Loop: Check if stack is empty. if empty push anything waiting in the queue
Javascript is single threaded but you have a browser
Events
Event delegate
<ul id="listToDestroy">
<li><a href="#">first item</a></li>
<li><a href="#">second item</a></li>
<li><a href="#">third item</a></li>
<li><a href="#">forth item</a></li>
<li><a href="#">Fifth item</a></li>
</ul>
var el = document.getElementById('listToDestroy');
el.addEventListener('click', function (e) {
var list = e.target.parentNode;
list.parentNode.removeChild(list);
e.preventDefault();
});
Event delegate (demo)
<ul id="listToDestroy">
<li><a href="#">first item</a></li>
<li><a href="#">second item</a></li>
<li><a href="#">third item</a></li>
<li><a href="#">forth item</a></li>
<li><a href="#">Fifth item</a></li>
</ul>
var el = document.getElementById('listToDestroy');
el.addEventListener('click', function (e) {
var list = e.target.parentNode;
list.parentNode.removeChild(list);
e.preventDefault();
});
Promise
Ready to Start?
Start a new journey with confidence.
Be the premium developer. The go to guy.
Hands on Learning
The best way to learn is to do it yourself while someone else is there to answer your questions:
- Date: Nov 11, 2017 9.45am to 5.00pm
- Location: Close to Merchandise mart.
- Promo code: chicago