Javascript Primitives, Objects and Classes

Vagelis Papadogiannakis

Source Development

papas_source

The 6 types of Javascript primitives

Vagelis Papadogiannakis

Source Development

papas_source

  • String
  • Number
  • Bigint
  • Boolean
  • null
  • undefined
  • Symbol

How to create Primitives:

Easy. Assign it to a variable or a constant

Vagelis Papadogiannakis

Source Development

papas_source

var my_string = "I am a string";

const my_other_string = "0042"; // still a string 

let my_number = 42;

const i_am_null = null;


All primitives are immutable. The variables that hold them, are not

my_string.toUpperCase(); 
// "A STRING"
console.log(my_string); // a string
function add_one(my_number){
  my_number += 2; // a new var is created here!
}
console.log(my_number); // 2
add_one(my_number); 
console.log(my_number); // still 2!

Variable Scope

Variable is available wherever it is declared

Vagelis Papadogiannakis

Source Development

papas_source

function fn(){
  var num = 5; // function scope
  let unused = 69; // block (=function) scoped
  if (num === 5) {
    let a = num + 2; // block scope
    const b = num + a; // block scope
    console.log(num, a, b); // 5, 7, 12
  }
  console.log(num); // 5
  console.log(a); // ReferenceError: a is not defined
                  // because a is block scoped to the `if`
  console.log(b); // We' ll never make it here :( 
}

fn();

Hoisting

Declarations are moved to the top

Vagelis Papadogiannakis

Source Development

papas_source

console.log(x); // undefined
var x = 5;
// What the computer understands
var x;
console.log(x);
x = 5;

let is hoisted, too. With a little difference... TDZ

console.log(a);
let a = 2;
// ff: ReferenceError: can't 
//   access lexical declaration
//   `a' before initialization
// ch: Uncaught ReferenceError:
//   a is not defined
var x = 2;
function foo(){
  console.log(x);
  let x = 3;
}
foo();
// same error BUT...
// if let didn't hoist
//   it would print "2"

enter

TEMPORAL

DEAD

ZONE

 

                    WAT?                       
Well, whenever control flow enters a new scope, all the let/const bindings belonging to the given scope are instantiated before any code inside of the given scope is executed aka "hoisted"

but may not be accessed in any way (this is why we get the referenceError) until the variable’s LexicalBinding is evaluated.                                   

Javascript Objects

In JS almost everything is an Object

Vagelis Papadogiannakis

Source Development

papas_source

// literal
var o = {
  name: 'papas'
};

// with constructor
var oo = new Object({
  name:'papas'
});
console.log(o);

Arrays and Functions are also Objects

function inc(num) {
  // do something
  return num + 1;
}

console.log(inc.prototype);

Every Object has its `prototype`

Javascript Objects

How Prototypal Inheritance works

Vagelis Papadogiannakis

Source Development

papas_source

var Car = function(name){
  this.name = name;
  this.toString = function() {
    return 'I am defined in the constructor! I am a ' + this.name;
  };
};
console.log(Car.prototype); // shows an Object with only constructor
Car.prototype.toString = function() {
  return 'hello from prototype. I am a ' + this.name;
};
var honda = new Car('Honda');
var tesla = new Car('Tesla');
console.log(tesla + ''); // I am defined in the constructor! I am a Tesla
tesla.toString = function(){
  return 'hello from the ' + this.name + ' instance!';
};
console.log(tesla + ''); // hello from the Tesla instance!
console.log(honda + ''); // I am defined in the constructor! I am a Honda
delete tesla.toString;
console.log(tesla + ''); // hello from prototype. I am a Tesla!
delete Car.prototype.toString;
console.log(tesla + ''); // [object Object]

Javascript Objects

Objects are passed via Reference

Vagelis Papadogiannakis

Source Development

papas_source

const john = {
  name: 'John'
};

function setname_george(o) {
  o.name = 'George';
  return o;
}

console.log(john); // {name: "John"}

const george = setname_george(john);
console.log(george); // {name: "George"} Seems legit
console.log(john); // {name: "George"} We fckd up john

Javascript Objects

Object References

Vagelis Papadogiannakis

Source Development

papas_source

const person = {
  name: 'John'
};

const data = {
  person: person
};

person.name = 'George';
console.log(data); 
// {person: {name: 'George'}}
// data is an Object.
// It holds a reference to another object, `person`.
// when `person` changes, `data` changes too...
const data = {
  person: {
    name: 'John'
  }
};

const person = data.person;
person.name = 'George';

console.log(data); 
// {person: {name: 'George'}}
// data is an Object.
// It holds a reference to another object, `person`.
// when `person` changes, `data` changes too...
const data = {
  person: {
    name: 'John'
  }
};

const person = data.person;
delete data.person;

console.log(data); 
// {}
// reference of `person` was deleted from `data` 

console.log(person); 
// {name: 'John'}
// this reference still exists!

Javascript Objects

Lets create an object instance (one of many ways)

Vagelis Papadogiannakis

Source Development

papas_source

function Person (first, last) {
  this.first_name = first;
  this.last_name = last;
  this.fullname = function(){
    return this.first_name + ' ' + this.last_name;
  }
}

const jd = new Person('John', 'Doe');
const ml = new Person('Mary', 'Lamb');

jd.first_name; // "John"
ml.last_name; // "Lamb"
jd.fullname(); // "John Doe"
ml.fullname(); // "Mary Lamb"
console.log(jd.fullname == ml.fullname); // false!

 

 

So, when we create a 1000 objects this way

1000 versions of the fullname are also created!

Not good, not at all good.

 

 

💛 Lets meet prototype 💛

 

 

Javascript Objects

Working with objects and the prototype

Vagelis Papadogiannakis

Source Development

papas_source

function Person () {}

Person.prototype = {
  first: 'John', last: 'Doe',
  hobbies: ['sitting', 'sleeping'],
  fullname: function(){
    return this.first_name + ' ' + this.last_name;
  }
};

const jd = new Person(), ml = new Person();
ml.first = 'Mary'; ml.last = 'Lamb';

console.log(jd); // "Person {}"
console.log(ml); // "Person {first: 'Mary', last: 'Lamb'}
console.log(jd.fullname == ml.fullname); // true!

 

   jd is created and no properties are assigned.

   jd does not have a `first` or `last` property.
  They are inherited by the prototype.

  ml is created and both `first` and `last` properties

  are assigned to it.
  ml's prototype inherited properties, are overwritten

 

Dont you just 💛 prototype ?

 

Javascript Objects

Lets play more!

Vagelis Papadogiannakis

Source Development

papas_source

function Person () {}

Person.prototype = {
  first: 'John', last: 'Doe',
  hobbies: ['sitting', 'sleeping'],
  fullname: function(){
    return this.first_name + ' ' + this.last_name;
  }
};

const jd = new Person(), ml = new Person();
ml.first = 'Mary'; ml.last = 'Lamb';

ml.hobbies[1] = 'running';
console.log(ml.hobbies); // ["sitting", "running"]
console.log(jd.hobbies); // ["sitting", "running"] <- WTaF?

 

  Don't forget, arrays are Objects. When we messed with
  marry's `hobbies` property, we messed with an Array

  The Array was mutated. ALL OF IT. WHERE-EVER it was.
  (bummer - It just "happened" to be on the prototype)

 

  Since john's `hobbies` property was also pointing

  to that same Array they were modified also.

 

This stinks... So, what do we do? 🥁🥁🥁🥁

 

Javascript Objects

Well it is simple... We use a combination of the prototype and the constructor function

Vagelis Papadogiannakis

Source Development

papas_source

function Person () {
  this.hobbies = ['sitting', 'sleeping'];
}

Person.prototype = {
  first: 'John', last: 'Doe',
  fullname: function(){
    return this.first_name + ' ' + this.last_name;
  }
};

const jd = new Person(), ml = new Person();
ml.first = 'Mary'; ml.last = 'Lamb';

ml.hobbies[1] = 'running';
console.log(ml.hobbies); // ["sitting", "running"]
console.log(jd.hobbies); // ["sitting", "sleeping"] yup, that's me

Javascript Objects

All together and best practices

Vagelis Papadogiannakis

Source Development

papas_source

function Person (first, last) {
  if (!(this instanceof Person)) {
    // this is your safeguard in case you forget the `new` keyword
    return new Person(first, last);
  }
  this.first = first;
  this.last = last;
  return this;
};

Person.prototype = {
  fullname: function(){
    return this.first + ' ' + this.last;
  }
}

const john_doe = new Person('John', 'Doe');
const john_do = Person('John', 'Doe'); // yeay!

Javascript Classes

How to declare a Class

Vagelis Papadogiannakis

Source Development

papas_source

class Person {
  constructor (first, last) {
    this.first = first;
    this.last = last;
  }

  fullname() {
    return this.first + ' ' + this.last;
  }
}

const jd = new Person('John', 'Doe');

Javascript Classes

Vagelis Papadogiannakis

Source Development

papas_source

class Car {
  constructor (name, hp) {
    this.name = name;
    this.hp = hp;
  }
  static race(car1, car2) {
    const winner = car1.hp > car2.hp ? car1 : car2;
    return "the winner is " + winner.name;
  }
}

const lada = new Car("Lada Niva", 80);
const ferrari = new Car("Ferrari", 661);
Car.race(lada, ferrari);
// "the winner is Ferrari"

Static functions

Javascript Classes

Vagelis Papadogiannakis

Source Development

papas_source

class Animal {
  constructor (name) {
    this.name = name;
  }
}
class WalkingAnimal extends Animal{
  constructor (name) {
    super(name); // `super()` before `this`!
    this.can_walk = true;
    this.walk_distance = 0;
  }
  walk (meters) {
    this.walk_distance += meters;
  }
}
class SwimmingAnimal extends Animal{
  constructor (name) {
    super(name);
    this.can_swim = true;
    this.swim_distance = 0;
  }
  swim (meters) {
    this.swim_distance += meters;
  }
}

const peppa = new WalkingAnimal('Peppa Pig');
const nemo = new SwimmingAnimal('Nemo Clownfish');

So, How do we create a `tux` animal?

It can walk, and it can swim!

Javascript Prototypal Inheritance

Vagelis Papadogiannakis

Source Development

papas_source

function Animal() {}
function WalkingAnimal() {}
function SwimmingAnimal() {}
function WalkingSwimmingAnimal() {}

Animal.prototype = { name: '' };

WalkingAnimal.prototype = Object.assign({}, Animal.prototype, {
  can_walk: true, walk_distance: 0, walk:function(distance){
    this.walk_distance += distance;
  }
});

SwimmingAnimal.prototype = Object.assign({}, Animal.prototype, {
  can_swim: true, swim_distance: 0, swim:function(distance){
    this.swim_distance += distance;
  }
});

WalkingSwimmingAnimal.prototype = Object.assign({}, 
  WalkingAnimal.prototype, 
  SwimmingAnimal.prototype
);

const dog = new WalkingAnimal(); dog.walk(4);
const fish = new SwimmingAnimal(); fish.swim(10);
const tux = new WalkingSwimmingAnimal(); tux.swim(7); tux.walk(4);
console.table({dog, fish, tux});

THE END

ANY QUESTIONS?

Made with Slides.com