Key Concepts in JavaScript
null
vs undefined
let myVariable = null; // Intentionally set to null
let myOtherVariable; // Declared but not assigned, so it's undefined
var
vs. let
var
Variables declared with var
are either function-scoped
or global-scoped
. var
variable can be used before it is declared.
let
Variables declared with let
is block scoped
{}
.
function myFunction() {
var x = 10; // Function scope
let y = 20; // Block scope
if (true) {
var z = 30; // Function scope
let w = 40; // Block scope
}
console.log(x); // 10
console.log(y); // 20
console.log(z); // 30
console.log(w); // ReferenceError: w is not defined
}
function
vs class
In javascript
when keyword function
is written,
it defines not just a function, but also a class with a constuctor which has body of that function
.
// Define class `Foo`
function Foo(value){
console.log(value);
}
// Define instance `foo1` of the class `Foo`
// and call `empty` constructor of the object
var foo1 = new Foo();
// Call `parameterized` constructor of the object
foo1.constructor(123); // 123
foo1.constructor(567); // 567
// Define instance `foo1` of the class `Foo`
// and call `parameterized` constructor of the object
var foo2 = new Foo(111); // 111
// Call `parameterized` constructor of the object
foo2.constructor(222); // 222
prototype
To define [functions](https://en.wikipedia.org/wiki/Function_(computer_programming) inside of class
in javascript
used keyword prototype
.
This means, that method's of the class
could be defined later at "runtime"
, and behavior of the instance of that class could be changed.
function Foo(value){
console.log(value);
}
//
// here can be logic
// var foo = new Foo();
// foo.Bar() // Uncaught TypeError: foo.Bar is not a function
//
// Define `method` `Bar` inside of `class` `Foo`
Foo.prototype.Bar = function(x, y){
console.log(x + y);
}
var foo = new Foo();
foo.Bar(1, 2); // 3
Equivalent class Foo
definition
function Foo(value){
// Define `method` `Bar` inside of `class` `Foo`
this.Bar = function(x, y){
console.log(x + y);
}
console.log(value);
}
var foo = new Foo();
foo.Bar(1, 2); // 3
class fields
function Foo(){
// Define fields inside of class `Foo`
this.id = 1;
this.name = "Bob";
}
// Define a method inside of Foo class
Foo.prototype.doSmth = function(){
console.log("work");
}
var foo = new Foo();
console.log(foo.id); // 1
console.log(foo.name); // Bob
foo.doSmth(); // work
Equivalent class definition
// Define instance `foo` of an anonymous class
var foo = {
// Define fields inside of class `Foo`
id: 1,
name: "Bob",
// Define a method inside of anonymous class
doSmth() {
console.log("work");
}
};
console.log(foo.id); // 1
console.log(foo.name); // Bob
foo.doSmth(); // work
object
inheritance
__proto__
In js
keyword __proto__
is used for object
inheritance.
Comparing to C#, js use object
(prototype-based inheritance), while C# use class
(class-based inheritance)
In js
object consists of fields and a reference
to the type, which can be changed durring code execution and object
will aquire new methods
.
In C#
object consists of fields, a reference
to the type(virtual method table (VMT)) and SyncBlockIndex
.
function Foo(){ }
Foo.prototype.doFooWork = function(){
console.log("foo work");
}
function Bar(){
}
Bar.prototype.doBarWork = function(){
console.log("bar work");
}
var bar = new Bar();
// Now bar has a reference to `VMT` of `Foo`
bar.__proto__ = Foo.prototype
// Other ways to change `reference` of `type` to another `type`:
// bar.__proto__ = Object.create(Foo.prototype);
// bar.__proto__ = new Foo().__proto__;
//
// Make class `Bar` itself be inherited from `Foo` class
// Object.setPrototypeOf(Bar.prototype, Foo.prototype);
bar.doFooWork(); // foo work
bar.doBarWork(); // TypeError: bar.doBarWork is not a function
Instance __proto__
has same address as class type
prototype
.
function Foo(){ }
var foo = new Foo();
foo.__proto__ === Foo.prototype; // true
Inheritance in JS
function Foo() { }
function Bar() { }
Object.setPrototypeOf(Bar.prototype, Foo.prototype);
with syntax sugar
class Foo {}
class Bar extends Foo {}
class Function
In js
each class is inherited from Function
class.
In C#
each class is inherited from Object
class.
Function
has methods call
, bind
, apply
.
Methods like call()
, apply()
, and bind()
can refer this
to any object.
call()
call()
calls a method from another object.
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
const person1 = {
firstName:"John",
lastName: "Doe"
}
person.fullName.call(person1); // Jonh Doe
apply()
apply()
calls a method from another object.
const person = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
const person1 = {
firstName: "Mary",
lastName: "Doe"
}
person.fullName.apply(person1); // Mary Doe
call()
vs apply()
The call()
method takes arguments separately
.
The apply()
method takes arguments as an array
.
bind()
With the bind()
method, an object
can borrow
a method
to another object.
const person = {
firstName:"John",
lastName: "Doe",
fullName: function () {
return this.firstName + " " + this.lastName;
}
}
const member = {
firstName:"Hege",
lastName: "Nilsen",
}
let fullName = person.fullName.bind(member);
fullName(); // Hege Nilsen
Closures
Variables declared with var
are either function-scoped
or global-scoped
.
function Foo(){
// function-scoped
var name = "Bob";
function Bar(){
console.log(name);
}
Bar();
}
Foo(); // Bob
Callback trick
function Bar(value, callback){
console.log("Bar enter.. " + value);
setTimeout(() => {
value++;
console.log("Bar: Long running job...");
callback(value);
}, "1000");
console.log("Bar exit.. " + value);
}
function Foo(){
function CallBack(value){
console.log("CallBack: " + value);
}
let value = 10;
let callBack = CallBack;
console.log("Foo: before `Bar` " + value);
Bar(value, callBack);
console.log("Foo: after `Bar` " + value);
}
Foo();
// Foo: before `Bar` 10
// Bar enter.. 10
// Bar exit.. 10
// Foo: after `Bar` 10
// ..
// Bar: Long running job...
// CallBack: 11
The event loop
To execute functions
js runtime use Queue.
Js runtime puts function's
into the queue
and executes them one by one
.
As a result, the next function
in the queue
does not start until the current one
finishes executing.
function Bar() {
console.log("Bar: ...");
}
function Foo(){
console.log("Foo: stat..");
let bar = Bar;
// Timeout: 0ms
setTimeout(bar, 0)
// Intensive work
for(let i = 0; i < 10000; i++) { }
console.log("Foo: end..");
}
Foo();
// Foo: stat..
// Foo: end..
// Bar: ...