├── .gitattributes ├── .yarnrc.yml ├── src ├── index.js └── circle.js ├── 03 Prototypes ├── images │ ├── 01-01.png │ └── 02-01.png ├── 08- Avoid Extending the Built-in Objects.js ├── 01- Inheritance.md ├── 07- Iterating Instance and Prototype Members.js ├── 04- Property Descriptors.js ├── 09- Cheat Sheet.js ├── 10- Exercise.js ├── 05- Constructor Prototypes.js ├── 02- Prototypes and Prototypical Inheritance.md ├── 06- Prototype vs Instance Members.js └── 03- Multilevel Inheritance.js ├── 06 ES6 Tooling ├── images │ ├── 04-01.png │ └── 04-02.png ├── 02- CommonJS Modules │ ├── before │ │ ├── index.js │ │ └── index.html │ └── after │ │ ├── index.html │ │ ├── index.js │ │ └── circle.js ├── 03- ES6 Modules │ ├── before │ │ ├── index.js │ │ └── index.html │ └── after │ │ ├── index.html │ │ ├── circle.js │ │ └── index.js ├── 04- ES6 Tooling.md ├── 06- Webpack.md ├── 01- Modules.md └── 05- Babel.md ├── 04 Prototypical Inheritance ├── images │ ├── 07-01.png │ ├── 07-02.png │ ├── 07-03.png │ └── 07-04.png ├── 03- Calling the Super Constructor.js ├── 10- Exercise- Prototypical Inheritance.js ├── 09- Cheat Sheet.js ├── 04- Intermediate Function Inheritance.js ├── 05- Method Overriding.js ├── 06- Polymorphism.js ├── 12- Exercise- Polymorphism.js ├── 07- When to Use Inheritance.md ├── 02- Resetting the Constructor.js ├── 08- Mixins.js └── 01- Creating Your Own Prototypical Inheritance.js ├── 01 Getting Started ├── 04- Course Structure.md ├── 03- Setting Up the Development Environment.md ├── 01- What is OOP.md └── 02- Four Pillars of OOP.js ├── dist └── main.js ├── .editorconfig ├── 02 Objects ├── 01- Introduction.md ├── 14- Exercise- Stopwatch.js ├── 04- Constructors.js ├── 10- Abstraction.js ├── 09- Enumerating Properties.js ├── 06- Functions are Objects.js ├── 11- Private Properties and Methods.js ├── 02- Object Literals.js ├── 08- Adding or Removing Properties.js ├── 05- Constructor Property.js ├── 07- Value vs Reference Types.js ├── 03- Factories.js ├── 13- Cheat Sheet.js └── 12- Getters and Setters.js ├── webpack.config.js ├── .gitignore ├── index.html ├── package.json ├── 05 ES6 Classes ├── 11- Exercise.js ├── 08- Inheritance.js ├── 07- Getters and Setters.js ├── 09- Method Overriding.js ├── 03- Static Methods.js ├── 02- Hoisting.js ├── 10- Cheat Sheet.js ├── 01- ES6 Classes.js ├── 06- Private Members Using WeakMaps.js ├── 04- The This Keyword.js └── 05- Private Members Using Symbols.js └── README.md /.gitattributes: -------------------------------------------------------------------------------- 1 | /.yarn/** linguist-vendored 2 | -------------------------------------------------------------------------------- /.yarnrc.yml: -------------------------------------------------------------------------------- 1 | yarnPath: .yarn/releases/yarn-2.4.0.cjs 2 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import { Circle } from "./circle"; 2 | 3 | const myCircle = new Circle(10); 4 | myCircle.draw(); 5 | 6 | console.log("changed") -------------------------------------------------------------------------------- /03 Prototypes/images/01-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/03 Prototypes/images/01-01.png -------------------------------------------------------------------------------- /03 Prototypes/images/02-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/03 Prototypes/images/02-01.png -------------------------------------------------------------------------------- /06 ES6 Tooling/images/04-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/06 ES6 Tooling/images/04-01.png -------------------------------------------------------------------------------- /06 ES6 Tooling/images/04-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/06 ES6 Tooling/images/04-02.png -------------------------------------------------------------------------------- /04 Prototypical Inheritance/images/07-01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/04 Prototypical Inheritance/images/07-01.png -------------------------------------------------------------------------------- /04 Prototypical Inheritance/images/07-02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/04 Prototypical Inheritance/images/07-02.png -------------------------------------------------------------------------------- /04 Prototypical Inheritance/images/07-03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/04 Prototypical Inheritance/images/07-03.png -------------------------------------------------------------------------------- /04 Prototypical Inheritance/images/07-04.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmschp/mosh-ultimate-javascript-mastery-series-part-2/HEAD/04 Prototypical Inheritance/images/07-04.png -------------------------------------------------------------------------------- /01 Getting Started/04- Course Structure.md: -------------------------------------------------------------------------------- 1 | # 04- Course Structure 2 | 3 | 1. Object in JavaScript 4 | 2. Prototypes 5 | 3. Prototypical Inheritance 6 | 4. ES6 Classes 7 | 5. Modules 8 | -------------------------------------------------------------------------------- /dist/main.js: -------------------------------------------------------------------------------- 1 | (()=>{"use strict";const s=new WeakMap;new class{constructor(e){s.set(this,e)}draw(){console.log("Circle with radius "+s.get(this))}}(10).draw(),console.log("changed")})(); -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | end_of_line = lf 5 | insert_final_newline = true 6 | 7 | [*.{js,json,.yml}] 8 | charset = utf-8 9 | indent_style = space 10 | indent_size = 2 11 | -------------------------------------------------------------------------------- /02 Objects/01- Introduction.md: -------------------------------------------------------------------------------- 1 | # 01 - Introduction 2 | 3 | 1. Creating Objects 4 | 2. Factories and Constructors 5 | 3. Primitives and Reference Types 6 | 4. Working with the Properties 7 | 5. Private Properties 8 | 6. Getters / Setters 9 | -------------------------------------------------------------------------------- /src/circle.js: -------------------------------------------------------------------------------- 1 | const _radius = new WeakMap(); 2 | 3 | export class Circle { 4 | constructor(radius) { 5 | _radius.set(this, radius); 6 | } 7 | 8 | draw() { 9 | console.log("Circle with radius " + _radius.get(this)); 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | 3 | module.exports = { 4 | entry: "./src/index.js", 5 | output: { 6 | filename: "main.js", 7 | path: path.resolve(__dirname, "dist"), 8 | }, 9 | // mode: "development", 10 | }; 11 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .yarn/* 2 | !/.yarn/releases 3 | !/.yarn/plugins 4 | !/.yarn/sdks 5 | 6 | # Swap the comments on the following lines if you don't wish to use zero-installs 7 | # Documentation here: https://yarnpkg.com/features/zero-installs 8 | # !/.yarn/cache 9 | #/.pnp.* 10 | -------------------------------------------------------------------------------- /01 Getting Started/03- Setting Up the Development Environment.md: -------------------------------------------------------------------------------- 1 | # 03- Setting Up the Development Environment 2 | 3 | ## Editor 4 | 5 | Using VS Code 6 | 7 | ## VS Code Extension 8 | 9 | - [Live Server](https://marketplace.visualstudio.com/items?itemName=ritwickdey.LiveServer) 10 | -------------------------------------------------------------------------------- /06 ES6 Tooling/02- CommonJS Modules/before/index.js: -------------------------------------------------------------------------------- 1 | const _radius = new WeakMap(); 2 | 3 | class Circle { 4 | constructor(radius) { 5 | _radius.set(this, radius); 6 | } 7 | 8 | draw() { 9 | console.log('Circle with radius ' + _radius.get(this)); 10 | } 11 | } 12 | 13 | const c = new Circle(10); 14 | c.draw(); -------------------------------------------------------------------------------- /06 ES6 Tooling/03- ES6 Modules/before/index.js: -------------------------------------------------------------------------------- 1 | 2 | const _radius = new WeakMap(); 3 | 4 | class Circle { 5 | constructor(radius) { 6 | _radius.set(this, radius); 7 | } 8 | 9 | draw() { 10 | console.log('Circle with radius ' + _radius.get(this)); 11 | } 12 | } 13 | 14 | const c = new Circle(10); 15 | c.draw(); -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | The Ultimate JavaScript Mastery Series - Part 2 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /06 ES6 Tooling/03- ES6 Modules/before/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /06 ES6 Tooling/02- CommonJS Modules/after/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /06 ES6 Tooling/02- CommonJS Modules/before/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /06 ES6 Tooling/03- ES6 Modules/after/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "js-basics-2", 3 | "scripts": { 4 | "babel": "babel index.js --presets=@babel/preset-env --out-file build/index.js", 5 | "build": "webpack --watch" 6 | }, 7 | "devDependencies": { 8 | "@babel/cli": "^7.12.13", 9 | "@babel/core": "^7.12.13", 10 | "@babel/preset-env": "^7.12.13", 11 | "webpack": "^5.21.2", 12 | "webpack-cli": "^4.5.0" 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /06 ES6 Tooling/02- CommonJS Modules/after/index.js: -------------------------------------------------------------------------------- 1 | // We use the require() function for to import. 2 | // This require() function is part of the CommonJs format. 3 | 4 | const Circle = require("./circle"); // Pass a relative pass to require function 5 | // When we use require() we get at is returned by this module. 6 | // module.export represent the object that is exported by this module. 7 | 8 | // If we use the syntax module.exports.Circle = Circle; we can use the following expression to get the Circle class 9 | // const Circle = require("./circle").Circle; 10 | 11 | const c = new Circle(10); 12 | c.draw(); 13 | -------------------------------------------------------------------------------- /01 Getting Started/01- What is OOP.md: -------------------------------------------------------------------------------- 1 | # 01- What is OOP 2 | 3 | Object Orientated Programming is a paradigm centered around objects rather then functions. 4 | Objects which can contain data and code: 5 | - data in the form of fields (often known as attributes or properties) 6 | - and code, in the form of procedures (often known as methods) 7 | 8 | Its is not a programming language or a tool. 9 | 10 | One of the features of OOP is that an object's method can access or modify its own data fields. And objects can have relations with one another. 11 | 12 | Most popular programming languages that support OOP are class-based, so objects are instances of classes, which also determine their types. 13 | -------------------------------------------------------------------------------- /06 ES6 Tooling/03- ES6 Modules/after/circle.js: -------------------------------------------------------------------------------- 1 | /* 2 | To export module features we can use two approaches, with the export statement 3 | 1 - Place it in front of any items you want exported out of the module 4 | 2 - Use a single export statement at the end of your module file, followed by a comma-separated list of the features you want to export wrapped in curly braces. 5 | */ 6 | 7 | const _radius = new WeakMap(); 8 | 9 | export class Circle { 10 | constructor(radius) { 11 | _radius.set(this, radius); 12 | } 13 | 14 | draw() { 15 | console.log("Circle with radius " + _radius.get(this)); 16 | } 17 | } 18 | 19 | // export { Circle, AnotherClass, comeOtherFunction, aVariable }; 20 | -------------------------------------------------------------------------------- /05 ES6 Classes/11- Exercise.js: -------------------------------------------------------------------------------- 1 | // 11 - Exercise; 2 | 3 | const _stack = new WeakMap(); 4 | 5 | class Stack { 6 | constructor() { 7 | _stack.set(this, []); 8 | } 9 | 10 | get count() { 11 | return _stack.get(this).length; 12 | } 13 | 14 | push(item) { 15 | _stack.get(this).push(item); 16 | } 17 | 18 | pop() { 19 | const stack = _stack.get(this); 20 | if (stack.length === 0) throw new Error("Stack is empty."); 21 | return stack.pop(); 22 | } 23 | 24 | peek() { 25 | const stack = _stack.get(this); 26 | if (stack.length === 0) throw new Error("Stack is empty."); 27 | return stack[stack.length - 1]; 28 | } 29 | } 30 | 31 | const s = new Stack(); 32 | -------------------------------------------------------------------------------- /06 ES6 Tooling/02- CommonJS Modules/after/circle.js: -------------------------------------------------------------------------------- 1 | // Implementation Detail 2 | const _radius = new WeakMap(); 3 | 4 | // Public Interface 5 | class Circle { 6 | constructor(radius) { 7 | _radius.set(this, radius); 8 | } 9 | 10 | draw() { 11 | console.log("Circle with radius " + _radius.get(this)); 12 | } 13 | } 14 | 15 | // The module keyword referes to the current module. 16 | // This module as a property called exports, which is an object. 17 | // And we can add one or more properties to this object. 18 | 19 | // module.exports.Circle = Circle; 20 | // module.exports.Square = Square; in case we had multiple class or functions or even variables we can add them as well. 21 | 22 | module.exports = Circle; // Because in this case we are exporting a single object we can use this syntax. 23 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/03- Calling the Super Constructor.js: -------------------------------------------------------------------------------- 1 | // 03- Calling the Super Constructor 2 | 3 | // We introduce a parameter to the shape.; 4 | // Now every shape as a color 5 | function Shape(color) { 6 | this.color = color; 7 | } 8 | 9 | Shape.prototype.duplicate = function () { 10 | console.log("duplicate"); 11 | }; 12 | 13 | function Circle(radius, color) { 14 | Shape.call(this, color); // Here we call the Shape function, and pass to it "this" witch will reference the object created when calling the Circle function, an instance of Circle, and the color paramter 15 | this.radius = radius; 16 | } 17 | 18 | Circle.prototype.draw = function () { 19 | console.log("draw circle"); 20 | }; 21 | 22 | const myCircle = new Circle(1, "blue"); 23 | console.log(myCircle); // Circle { color: 'blue', radius: 1 } 24 | -------------------------------------------------------------------------------- /02 Objects/14- Exercise- Stopwatch.js: -------------------------------------------------------------------------------- 1 | // 14 - Exercise - Stopwatch 2 | 3 | function StopWatch() { 4 | let startTime, 5 | endTime, 6 | running, 7 | duration = 0; 8 | this.start = () => { 9 | if (running) throw new Error("Stopwatch is already started"); 10 | running = true; 11 | startTime = new Date(); 12 | }; 13 | this.stop = () => { 14 | if (!running) throw new Error("Stopwatch is already stopped"); 15 | running = false; 16 | endTime = new Date(); 17 | const seconds = (endTime.getTime() - startTime.getTime()) / 1000; 18 | duration += seconds; 19 | }; 20 | this.reset = () => { 21 | startTime = null; 22 | endTime = null; 23 | running = false; 24 | duration = 0; 25 | }; 26 | Object.defineProperty(this, "duration", { 27 | get: () => { 28 | return duration; 29 | }, 30 | }); 31 | } -------------------------------------------------------------------------------- /06 ES6 Tooling/03- ES6 Modules/after/index.js: -------------------------------------------------------------------------------- 1 | // Once we exported some module features, we need to import. 2 | // This can be done with the following syntax: 3 | import { Circle } from "./circle.js"; 4 | 5 | /* 6 | We need to pass the .js file extension, or we will get SyntaxError: Unexpected token 7 | And in our html we need to include type="module" in the 10 | 11 | The proper way to fix this is using Webpack. 12 | 13 | To import several features use the import statement, followed by a comma-separated list of the features we want to import wrapped in curly braces. 14 | import { Circle, AnotherClass, comeOtherFunction, aVariable } from "./circle.js"; 15 | */ 16 | 17 | const c = new Circle(10); 18 | c.draw(); 19 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/10- Exercise- Prototypical Inheritance.js: -------------------------------------------------------------------------------- 1 | // 10- Exercise- Prototypical Inheritance 2 | 3 | function HtmlElement() { 4 | this.click = function () { 5 | console.log("clicked"); 6 | }; 7 | } 8 | 9 | HtmlElement.prototype.focus = function () { 10 | console.log("focused"); 11 | }; 12 | 13 | const myHtmlElement = new HtmlElement(); 14 | console.log(myHtmlElement); 15 | 16 | function HtmlSelectElement(...elements) { 17 | this.items = [...elements]; 18 | this.addItem = function (item) { 19 | this.items.push(item); 20 | }; 21 | this.removeItem = function (item) { 22 | const index = this.items.indexOf(item); 23 | if (index > -1) this.items.splice(index, 1); 24 | }; 25 | } 26 | 27 | HtmlSelectElement.prototype = new HtmlElement(); 28 | HtmlSelectElement.prototype.constructor = HtmlSelectElement; 29 | 30 | const myHtmlSelectElement = new HtmlSelectElement(); 31 | console.log(myHtmlSelectElement); 32 | -------------------------------------------------------------------------------- /03 Prototypes/08- Avoid Extending the Built-in Objects.js: -------------------------------------------------------------------------------- 1 | // 08- Avoid Extending the Built-in Objects 2 | 3 | /* 4 | Although is quite simply to modify the prototype of an object we should avoid modifying built-in objects 5 | */ 6 | 7 | Array.prototype.shuffle = function() { // We add shuffle method to the Array built-in object. 8 | console.log('shuffled array'); 9 | } 10 | 11 | const myArray = [1, 2, 3]; 12 | myArray.shuffle(); // We can define an array and call the shuffle method 13 | 14 | /* 15 | Although this works, we should not modify the built-in object for a number of reasons, for example: 16 | We could be using a library, and in that library someone has also extended the Array prototype, and added a shuffle method, but with a different implementation 17 | JavaScript developers could add the shuffle method in future version 18 | 19 | We should not override, neither add or remove new method or properties from the built-in objects. 20 | Modifying the built-in object might create bugs. 21 | */ 22 | -------------------------------------------------------------------------------- /05 ES6 Classes/08- Inheritance.js: -------------------------------------------------------------------------------- 1 | // 08 - Inheritance 2 | 3 | /* 4 | The extends keyword is used in class declarations or class expressions to create a class as a child of another class. 5 | If there is a constructor present in the subclass, it needs to first call super() before using "this". 6 | 7 | One may also extend traditional function-based "classes" 8 | */ 9 | 10 | class Shape { 11 | constructor(color) { 12 | this.color = color; 13 | } 14 | 15 | move() { 16 | console.log("move"); 17 | } 18 | } 19 | 20 | class Circle extends Shape { // We use the "extends" keyword 21 | constructor(color, radius) { 22 | super(color); // We first need to call the super() so it call the constructor() of the Parent Class 23 | this.radius = radius; 24 | } 25 | 26 | draw() { 27 | console.log("draw"); 28 | } 29 | } 30 | 31 | const myCircle = new Circle("red", 10); 32 | console.log(myCircle); 33 | 34 | myCircle.move(); // We can call the Parent Class method in the Child Class 35 | 36 | myCircle.draw(); -------------------------------------------------------------------------------- /03 Prototypes/01- Inheritance.md: -------------------------------------------------------------------------------- 1 | # 01- Inheritance 2 | 3 | ## Inheritance 4 | 5 | Inheritance lets one object acquire the properties and methods of another object, the Parent Object. 6 | 7 | If we have properties and method that are common to several Objects, we can define a general Object and theses objects will inherit from the general Object. 8 | 9 | Lets image we have a Circle class and a Square class that have a need the same computeOptimumLocation() method. 10 | 11 | With Inheritance both the Circle and Square could inherit a computeOptimumLocation() method from the Shape class. 12 | 13 | ![Inheritance](./images/01-01.png "Inheritance Diagram") 14 | 15 | Inheritance terms: 16 | 17 | - The Shape class is ---> Base / Super / Parent 18 | - The Circle and Square classes are ---> Derived /Sub / Child 19 | - The inheritance relationship ---> IS-A 20 | 21 | ## Classical Inheritance vs Prototypical Inheritance 22 | 23 | In JavaScript we do not have classes we have objects, thats when Prototypical Inheritance comes into place. 24 | -------------------------------------------------------------------------------- /02 Objects/04- Constructors.js: -------------------------------------------------------------------------------- 1 | // 04 - Constructors 2 | 3 | /* 4 | The Constructor Functions job is to construct or create new objects. 5 | For this types of function we use Pascal Notation instead of Camel Notation 6 | 7 | Camel Notation: oneTwoThree 8 | Pascal Notation: OneTwoThree 9 | 10 | In this type of functions instead of returning an object we inicialize an object. 11 | 12 | There is really no difference between factory and constructor function. 13 | The Constructor is familiar to programers of C# or Java. 14 | */ 15 | 16 | function Circle(radius) { 17 | this.radius = radius; 18 | this.draw = function draw() { 19 | console.log('Draw') 20 | }; 21 | }; 22 | 23 | // To create a new object using this function 24 | const circle = new Circle(1) 25 | 26 | /* 27 | When we use the "new operator 3 thing happen": 28 | 1. This operator creates an empty JavaScript object; 29 | 2. Then it will set "this" operator statement to point to the empty object; 30 | 3. Finally the "new" operator will return the object from the function. 31 | */ -------------------------------------------------------------------------------- /02 Objects/10- Abstraction.js: -------------------------------------------------------------------------------- 1 | // 10 - Abstraction 2 | 3 | function Circle(radius) { 4 | this.radius = radius; 5 | 6 | this.defaultLocation = { x: 0, y: 0 }; 7 | this.computeOptimumLocation = () => { 8 | console.log("this is the best location"); 9 | }; 10 | 11 | this.draw = function draw() { 12 | this.computeOptimumLocation(); // We define the method and call it in the draw method. THIS MAYBE NOT A GOOD PRACTICE 13 | console.log("Draw"); 14 | }; 15 | } 16 | 17 | const circle = new Circle(10); 18 | 19 | // In some situation not all the members should be accessible to the consumer or client of this object. 20 | // For example if we set it to false it is going to completely mess up the object. 21 | circle.computeOptimumLocation = false; 22 | 23 | // Maybe the computeOptimumLocation method, and defaultLocation property should be hidden, they could be implementation details, and should be hidden from the consumer of this object 24 | // Suppose we only need to call the computeOptimumLocation from inside the draw method. We will implement this in the next lecture. 25 | -------------------------------------------------------------------------------- /03 Prototypes/07- Iterating Instance and Prototype Members.js: -------------------------------------------------------------------------------- 1 | // 07- Iterating Instance and Prototype Members 2 | 3 | // We have the Circle Constructor Function with 2 instance members 4 | // 1 - Radius property 5 | // 2 - Move method 6 | 7 | function Circle(radius) { 8 | this.radius = radius; // Instance members 9 | 10 | this.move = function () { 11 | console.log("move"); 12 | }; 13 | } 14 | 15 | // We add the draw() method as a Prototype member 16 | Circle.prototype.draw = function () { 17 | console.log("draw"); 18 | }; 19 | 20 | const c1 = new Circle(1); 21 | 22 | // With Object.keys() method we can iterate over the instance members 23 | console.log(Object.keys(c1)); // [ 'radius', 'move' ] 24 | 25 | // With the for...in loop we can iterate over all members, both Instance Members and Prototype Members 26 | for (let key in c1) console.log(key); 27 | // It will log: 28 | // radius 29 | // move 30 | // draw 31 | 32 | // In JavaScript the word Own is also used instead of Instance 33 | console.log(c1.hasOwnProperty('move')); 34 | console.log(c1.hasOwnProperty("draw")); 35 | -------------------------------------------------------------------------------- /05 ES6 Classes/07- Getters and Setters.js: -------------------------------------------------------------------------------- 1 | // 07- Getters and Setters 2 | 3 | const _radius = new WeakMap(); 4 | const _move = new WeakMap(); 5 | 6 | class Circle { 7 | constructor(radius) { 8 | _radius.set(this, radius); 9 | _move.set(this, () => { 10 | console.log("move", this); 11 | }); 12 | } 13 | 14 | draw() { 15 | const radius = _radius.get(this); 16 | _move.get(this)(); 17 | console.log(`draw radius: ${radius}`); 18 | } 19 | 20 | get radius() { // Define a getter for the radius 21 | return _radius.get(this); 22 | } 23 | 24 | set radius(radius) { // Define a setter for the radius 25 | if (radius <= 0) throw Error("invalid radius"); // we can add a validation to the input value. 26 | _radius.set(this, radius); 27 | } 28 | } 29 | 30 | const myCircle = new Circle(1); 31 | console.log(myCircle.radius); // Here we read the radius property with the getter. 32 | 33 | myCircle.radius = 10; // Here we set the radius property with the setter. 34 | 35 | console.log(myCircle.radius); // Here we read again the radius property with the getter. 36 | -------------------------------------------------------------------------------- /02 Objects/09- Enumerating Properties.js: -------------------------------------------------------------------------------- 1 | // 09- Enumerating Properties 2 | 3 | /* 4 | There are different ways to iterate over the properties of an object. 5 | We saw the for loops 6 | */ 7 | 8 | const circle = { 9 | radius: 1, 10 | draw() { 11 | console.log("Draw"); 12 | }, 13 | }; 14 | 15 | // Using the for..in loop to get the properties and values of an object 16 | for (let key in circle) { 17 | console.log(key, circle[key]); 18 | } 19 | 20 | for (let key of Object.keys(circle)) { 21 | // The "Object.keys()" method will return an array of strings with the object properties. 22 | console.log(key); 23 | } 24 | 25 | for (let entry of Object.entries(circle)) { 26 | // The "Object.entries()" method will return an array with the object key value pair. 27 | console.log(entry); 28 | } 29 | 30 | if ("radius" in circle) console.log("Yes"); // With the in operator we can check if a given property exists in an object. 31 | 32 | // In case we only want to display the properties we can use a if statement. 33 | for (let key in circle) { 34 | if (typeof circle[key] !== "function") console.log(key, circle[key]); 35 | } 36 | -------------------------------------------------------------------------------- /06 ES6 Tooling/04- ES6 Tooling.md: -------------------------------------------------------------------------------- 1 | # 04- ES6 Tooling 2 | 3 | When using modern JavaScript we need two kinds of tools 4 | 5 | ## 1. Transpiler 6 | 7 | The term Transpiler comes from the combination of two words Translator + Compiler. Basically it is a tool that we give it our modern JavaScript code, and it will convert our code in code that all browsers can understand (ES5). 8 | 9 | [**Babel**](https://babeljs.io/) is a popular Transpiler for modern JavaScript. 10 | 11 | [![Babel](./images/04-01.png "Babel")](https://babeljs.io/ "Babel") 12 | 13 | ## 2. Bundler 14 | 15 | A module bundler is responsible to combine all our JavaScript files into a single JavaScript file, witch we call a bundle. The most popular module bundler is [**Webpack**](https://webpack.js.org/). 16 | 17 | So we give all our files to **Webpack**, it will minify our code, by clearing all comments and whitespace, and then it will uglify by shortening the name of our identifiers, like classes function, and so on. This will reduce the size od the bundle served to the client. 18 | 19 | [![Webpack](./images/04-02.png "Webpack")](https://webpack.js.org/ "Webpack") 20 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/09- Cheat Sheet.js: -------------------------------------------------------------------------------- 1 | function Shape() {} 2 | function Circle() {} 3 | 4 | // Prototypical inheritance 5 | Circle.prototype = Object.create(Shape.prototype); 6 | Circle.prototype.constructor = Circle; 7 | 8 | function Rectangle(color) { 9 | // To call the super constructor 10 | Shape.call(this, color); 11 | } 12 | 13 | // Method overriding 14 | Shape.prototype.draw = function () {}; 15 | Circle.prototype.draw = function () { 16 | // Call the base implementation 17 | Shape.prototype.draw.call(this); 18 | 19 | // Do additional stuff here 20 | }; 21 | 22 | // Don't create large inheritance hierarchies. 23 | // One level of inheritance is fine. 24 | 25 | // Use mixin to combine multiple objects 26 | // and implement composition in JavaScript. 27 | const canEat = { 28 | eat: function () {}, 29 | }; 30 | 31 | const canWalk = { 32 | walk: function () {}, 33 | }; 34 | 35 | function mixin(target, ...sources) { 36 | // Copies all the properties from all the source objects 37 | // to the target object. 38 | Object.assign(target, ...sources); 39 | } 40 | 41 | function Person() {} 42 | 43 | mixin(Person.prototype, canEat, canWalk); 44 | -------------------------------------------------------------------------------- /02 Objects/06- Functions are Objects.js: -------------------------------------------------------------------------------- 1 | // 06- Functions are Objects 2 | 3 | /* 4 | In JavaScript functions are objects 5 | */ 6 | 7 | function Circle(radius) { 8 | this.radius = radius; 9 | this.draw = function draw() { 10 | console.log('Draw'); 11 | } 12 | } 13 | 14 | console.log(Circle.name); // This property returns the name of the function. 15 | 16 | console.log(Circle.length); // This property returns the number of arguments. 17 | 18 | console.log(Circle.constructor); // This returns the 'Function()' constructor that was used when we create a literal function. JavaScript uses that constructor to crete this object. 19 | // Like this: 20 | const Circle1 = new Function('radius', ` 21 | this.radius = radius; 22 | this.draw = function draw() { 23 | console.log('Draw') 24 | } 25 | `); 26 | 27 | Circle.call({}, 1) // With the "call()" method we can call a function, as the first argument we pass an empty object, and then the following arguments explicitly 28 | Circle.apply({}, [1, 2]) // With the "apply()" method, it works the same way as the call but we pass the arguments as an array. 29 | 30 | // Using the call or apply method is the same as the following code: 31 | const circle = new Circle(1) 32 | console.log(circle); 33 | -------------------------------------------------------------------------------- /05 ES6 Classes/09- Method Overriding.js: -------------------------------------------------------------------------------- 1 | // 09- Method Overriding 2 | 3 | /* 4 | To override a method from the Parent Class in a Child class, we must implement the method with the same name in the Child class body 5 | It is possible to call super in the Child class method, to also reuse the same implementation as in the Parent class. 6 | */ 7 | 8 | class Shape { 9 | constructor(color) { 10 | this.color = color; 11 | } 12 | 13 | move() { 14 | console.log("move"); 15 | } 16 | flip() { 17 | console.log("flip shape"); 18 | } 19 | } 20 | 21 | class Circle extends Shape { 22 | constructor(color, radius) { 23 | super(color); 24 | this.radius = radius; 25 | } 26 | 27 | draw() { 28 | console.log("draw"); 29 | } 30 | 31 | move() { // Here we override the move method from the Parent Shape Class 32 | super.move(); // Because we call super, the implementation of the Parent class is also used. 33 | console.log("move circle"); 34 | } 35 | 36 | flip() { 37 | // Here we override the flip method from the Parent Shape Class, without using its implementation. 38 | console.log("flip circle"); 39 | } 40 | } 41 | 42 | const myCircle = new Circle("red", 10); 43 | 44 | myCircle.move(); 45 | 46 | myCircle.flip(); 47 | -------------------------------------------------------------------------------- /02 Objects/11- Private Properties and Methods.js: -------------------------------------------------------------------------------- 1 | // 11- Private Properties and Methods 2 | 3 | // To implement Abstraction in the object we remove the "this" keyword and replace it for a variable 4 | function Circle(radius) { 5 | let color = "red"; // Because were we are using a variable, instead of the "this" keyword, color it is not a property from this object, so it is not accessible from the outside. It is only a variable with local scope to this function. 6 | this.radius = radius; 7 | 8 | let defaultLocation = { x: 0, y: 0 }; 9 | let computeOptimumLocation = (factor) => { // Using this technic we can convert this method to a private method. 10 | console.log("this is the best location"); 11 | }; 12 | 13 | this.draw = function draw() { 14 | computeOptimumLocation(0.1); // We define the method and call it in the draw method. THIS MAYBE NOT A GOOD PRACTICE 15 | console.log("Draw"); 16 | }; 17 | } 18 | const myCircle = new Circle(10); 19 | 20 | // In contrast to scope we have clojure. It determines what variables will be accessible to a inner function. 21 | // The Draw function will be able to access all the local variable defined in it, and all the local variable defined in its parent function. 22 | // The defaultLocation and computeOptimumLocation are in the scope of the Circle function and the the clojure fo the draw function. -------------------------------------------------------------------------------- /05 ES6 Classes/03- Static Methods.js: -------------------------------------------------------------------------------- 1 | // 03- Static Methods 2 | 3 | /* 4 | Static methods and properties 5 | The static keyword defines a static method or property for a class. 6 | Static members (properties and methods) are called without instantiating their class and cannot be called through a class instance. 7 | Static methods are often used to create utility functions for an application, whereas static properties are useful for caches, fixed-configuration, or any other data you don't need to be replicated across instances. 8 | 9 | */ 10 | 11 | class Circle { 12 | constructor(radius) { 13 | this.radius = radius; 14 | this.move = function () { 15 | console.log("move"); 16 | }; 17 | } 18 | // Instance method 19 | draw() { 20 | console.log("draw"); 21 | } 22 | 23 | // Static method 24 | // In this example we have a Static Method, that will return a new circle, from a JSON string. 25 | static parse(jsonString) { 26 | const radius = JSON.parse(jsonString).radius; 27 | return new Circle(radius); 28 | } 29 | } 30 | 31 | const myCircle = new Circle(1); 32 | myCircle.draw(); 33 | 34 | const anotherCircle = Circle.parse('{ "radius" : 1 }'); // Width the Static method parse() we can initialize a new circle object 35 | anotherCircle.draw(); 36 | 37 | // We use static method to create utility functions that are not tied to a particular function. 38 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/04- Intermediate Function Inheritance.js: -------------------------------------------------------------------------------- 1 | // 04- Intermediate Function Inheritance 2 | 3 | function Shape(color) { 4 | this.color = color; 5 | } 6 | 7 | Shape.prototype.duplicate = function () { 8 | console.log("duplicate"); 9 | }; 10 | 11 | // We can create a function to reuse, for setting parent child relations. 12 | // This way we have cleaner code. 13 | // We use uppercase for the parameters, because it is expected they are constructor functions. 14 | function extend(Parent, Child) { 15 | Child.prototype = Object.create(Parent.prototype); 16 | Child.prototype.constructor = Child; 17 | } 18 | 19 | function Circle(radius, color) { 20 | this.radius = radius; 21 | Shape.call(this, color); 22 | } 23 | 24 | extend(Shape, Circle); // Now we can call extend() with the Shape and Circle constructor functions to establish the relationship. 25 | 26 | Circle.prototype.draw = function () { 27 | console.log("draw circle"); 28 | }; 29 | 30 | function Square(size, color) { 31 | this.size = size; 32 | Shape.call(this, color); 33 | } 34 | 35 | extend(Shape, Square); 36 | 37 | Square.prototype.square = function () { 38 | console.log("draw square"); 39 | }; 40 | 41 | const myCircle = new Circle(1, "blue"); 42 | console.log(myCircle); 43 | myCircle.duplicate(); 44 | myCircle.draw(); 45 | 46 | const mySquare = new Square(1, "red"); 47 | console.log(mySquare); 48 | -------------------------------------------------------------------------------- /02 Objects/02- Object Literals.js: -------------------------------------------------------------------------------- 1 | // 02- Object Literals 2 | 3 | /* 4 | In javascript objects are collections of key value pairs. 5 | If we have properties that are highly related we want to encapsulate then inside of an object 6 | 7 | For example, if we are building an app to draw different shapes: 8 | In the case a circle 9 | */ 10 | 11 | let radius = 1; 12 | let x = 10; 13 | let y = 20; 14 | 15 | /* 16 | Instead of defining a bunch of variables like the one above, we should put this variables inside of an object. And then we can use this object anywhere in our program. 17 | In an object the values can be of any type in JavaScript. 18 | The purpose of an object is to group related variables, and quite often we also have functions that operate in these variables. 19 | */ 20 | 21 | const circle = { 22 | radius: 1, 23 | location: { 24 | x: 10, 25 | y: 20 26 | }, 27 | isVisible: true, 28 | draw: function() { 29 | console.log('Draw') 30 | }, 31 | move: function() { 32 | console.log('Move') 33 | } 34 | }; 35 | 36 | circle.draw(); 37 | 38 | /* 39 | This is object oriented style of programming (Object Oriented Programing - OOP). 40 | This is basically a style of programming that were a program is a collections of objects that talk to each other to perform some functionality. 41 | 42 | In programing terms if a functions is part of an object we call that function a method. 43 | */ -------------------------------------------------------------------------------- /02 Objects/08- Adding or Removing Properties.js: -------------------------------------------------------------------------------- 1 | // 08- Adding or Removing Properties 2 | 3 | // Objects in JavaScript are dynamic, that means, that after we create them we can add extra properties or even delete properties. 4 | // For example if we are working with a user object. 5 | // A client, that can be a web or mobile application, is going to send a user object to the server. 6 | // On the server we can add or remove properties from the user object, like for example a token. 7 | 8 | function Circle(radius) { 9 | this.radius = radius; 10 | this.draw = function draw() { 11 | console.log("Draw"); 12 | }; 13 | } 14 | 15 | const circle = new Circle(10); 16 | 17 | circle.location = { x: 1, y: 1 }; // In here we add the location property to the circle object. 18 | console.log(circle); 19 | circle["location"] = { x: 3, y: 3 }; // The bracket notation is a different syntax to achieve the same result. 20 | console.log(circle); 21 | 22 | // The bracket notation is useful in situation we want to access that property dynamically. 23 | // Or if the property as special characters like spaces or dashes -. 24 | const propertyName = "location"; 25 | console.log(circle[propertyName]); 26 | 27 | 28 | // We can also delete properties. For example if we want to send the user object to the client, but properties like credit card info must not be sent. 29 | delete circle.location // We can use the dot notation or the bracket notation. 30 | console.log(circle); -------------------------------------------------------------------------------- /02 Objects/05- Constructor Property.js: -------------------------------------------------------------------------------- 1 | // 05- Constructor Property 2 | 3 | /* 4 | Every object in JavaScript has a property called "constructor" that references the function that was used to create that objects 5 | */ 6 | 7 | // Factory Function 8 | function createCircle(radius, x, y) { 9 | return { 10 | radius, // in JavaScript if our key and value are the same "radius: radius", we can make our code sorter and simply remove the value. 11 | location: { 12 | x, 13 | y, 14 | }, 15 | draw() { 16 | // For functions we don't need the full function syntax to define the function. 17 | console.log("Draw"); 18 | }, 19 | move() { 20 | console.log("Move"); 21 | }, 22 | }; 23 | } 24 | 25 | const circleFactory = createCircle(1, 2, 3); 26 | console.log(circleFactory.constructor); 27 | 28 | /* 29 | [Function: Object] In this case it returns a built-in constructor function "Object()". 30 | When we create an object using the object literal syntax, internally JavaScript uses the "Object()" 31 | let x = {}; JavaScript will do this: 32 | let x = new Object() 33 | */ 34 | 35 | // Constructor Function 36 | function Circle(radius) { 37 | this.radius = radius; 38 | this.draw = function draw() { 39 | console.log("Draw"); 40 | }; 41 | } 42 | 43 | const circleConstructor = new Circle(1); 44 | console.log(circleConstructor.constructor); // [Function: Circle] This returns our circle function that we use to create this object. 45 | -------------------------------------------------------------------------------- /05 ES6 Classes/02- Hoisting.js: -------------------------------------------------------------------------------- 1 | /* 2 | Hoisting is JavaScript's default behavior of moving declarations to the top. 3 | The key difference between Function Declaration and Function Expression is that: 4 | Function declarations can be called before being declared 5 | Function expression can not, it's the same as using a variable. 6 | 7 | The reason for this is when our JavaScript engine runs this code, it moves all function declarations to the top. 8 | Its called Hoisting. The process of moving Function Declarations to the top of the file, and it is made automatically by the Javascript engine. 9 | 10 | An important difference between function declarations and class declarations is that function declarations are hoisted and class declarations are not. 11 | You first need to declare your class and then access it, otherwise code like the following will throw a ReferenceError: 12 | */ 13 | 14 | sayHello(); 15 | 16 | // Function declaration 17 | function sayHello() { 18 | console.log("hello"); 19 | } 20 | 21 | // Anonymous Function Expression 22 | let sayGoodbye = function () { 23 | console.log("bye"); 24 | }; 25 | 26 | sayGoodbye(); 27 | 28 | // Class Declaration 29 | class Circle { 30 | draw() { 31 | console.log("draw"); 32 | } 33 | } 34 | 35 | const newCircle = new Circle(); 36 | newCircle.draw(); 37 | 38 | // Class Expressions 39 | const Square = class { 40 | draw() { 41 | console.log("draw"); 42 | } 43 | }; 44 | 45 | const newSquare = new Square(); 46 | newSquare.draw(); 47 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/05- Method Overriding.js: -------------------------------------------------------------------------------- 1 | // 05- Method Overriding 2 | 3 | /* 4 | In a situation where a method defined in the Parent object, may not be ideal for the Child object. We can override that method. 5 | Let's imagine that not all shapes use the same duplicate method. 6 | For example the Circle needs a different implementation of the duplicate method. 7 | */ 8 | 9 | function extend(Parent, Child) { 10 | Child.prototype = Object.create(Parent.prototype); 11 | Child.prototype.constructor = Child; 12 | } 13 | 14 | function Shape(color) { 15 | this.color = color; 16 | } 17 | 18 | Shape.prototype.duplicate = function () { 19 | console.log("duplicate"); 20 | }; 21 | 22 | function Circle(radius, color) { 23 | this.radius = radius; 24 | Shape.call(this, color); 25 | } 26 | 27 | extend(Shape, Circle); 28 | 29 | Circle.prototype.draw = function () { 30 | console.log("draw circle"); 31 | }; 32 | 33 | // Here we override the duplicate method from Shape 34 | Circle.prototype.duplicate = function () { 35 | // In case we want to call the duplicate method in the Parent object as well, we can use this syntax. 36 | Shape.prototype.duplicate(); 37 | 38 | // In case we are using "this" keyword in the implementation of the method i the Parent object, we must use the following syntax. 39 | Shape.prototype.duplicate.call(this); 40 | 41 | console.log("duplicate circle"); 42 | }; 43 | 44 | const myCircle = new Circle(1, "blue"); 45 | console.log(myCircle); 46 | myCircle.duplicate(); // Now when we call duplicate(), it is the duplicate() method in Circle that is called. -------------------------------------------------------------------------------- /05 ES6 Classes/10- Cheat Sheet.js: -------------------------------------------------------------------------------- 1 | // 10- Cheat Sheet 2 | 3 | 4 | class Circle { 5 | constructor(radius) { 6 | this.radius = radius; 7 | } 8 | 9 | // These methods will be added to the prototype. 10 | draw() {} 11 | 12 | // This will be available on the Circle class (Circle.parse()) 13 | static parse(str) {} 14 | } 15 | 16 | // Using symbols to implement private properties and methods 17 | const _size = Symbol(); 18 | const _draw = Symbol(); 19 | 20 | class Square { 21 | constructor(size) { 22 | // "Kind of" private property 23 | this[_size] = size; 24 | } 25 | 26 | // "Kind of" private method 27 | [_draw]() {} 28 | 29 | // By "kind of" I mean: these properties and methods are essentally 30 | // part of the object and are accessible from the outside. But accessing 31 | // them is hard and awkward. 32 | } 33 | 34 | // using WeakMaps to implement private properties and methods 35 | const _width = new WeakMap(); 36 | 37 | class Rectangle { 38 | constructor(width) { 39 | _width.set(this, width); 40 | } 41 | 42 | draw() { 43 | console.log("Rectangle with width" + _width.get(this)); 44 | } 45 | } 46 | 47 | // WeakMaps give us better protection than symbols. There is no way 48 | // to access private members implemented using WeakMaps from the 49 | // outside of an object. 50 | 51 | // Inheritance 52 | class Triangle extends Shape { 53 | constructor(color) { 54 | // To call the base constructor 55 | super(color); 56 | } 57 | 58 | draw() { 59 | // Call the base method 60 | super.draw(); 61 | 62 | // Do some other stuff here 63 | } 64 | } -------------------------------------------------------------------------------- /03 Prototypes/04- Property Descriptors.js: -------------------------------------------------------------------------------- 1 | // 04- Property Descriptors 2 | 3 | const person = { name: "Miguel" }; 4 | console.log(person); 5 | 6 | // If we iterate over the members of this object we will not see its prototype methods defined in objectBase. 7 | 8 | for (let key in person) console.log(key); // We will only see the key name. 9 | 10 | // The reason is our properties have attributes attached to them. sometimes this attributes prevent a property from being enumerated. 11 | 12 | const objectBase = Object.getPrototypeOf(person); 13 | console.log(objectBase); 14 | 15 | const descriptor = Object.getOwnPropertyDescriptor(objectBase, "toString"); // This will return an object called property descriptor 16 | console.log(descriptor); 17 | /* 18 | { 19 | value: [Function: toString], 20 | writable: true, ---> writable true this means we can override this method 21 | enumerable: false, ---> enumerable is false, this is why we could not see it when iterating over the person object. 22 | configurable: true ---> when set to true means we can delete this member 23 | } 24 | */ 25 | 26 | // We can set this properties for our person object. 27 | Object.defineProperty(person, "name", { 28 | writable: false, 29 | enumerable: false, 30 | configurable: false 31 | }) 32 | 33 | person.name = 'Mosh'; // If we set writable to false we can not change the value. 34 | console.log(Object.keys(person)); // This will return an empty array, because we set enumerable to false 35 | delete person.name; // With configurable set to false we can not delete the name property 36 | 37 | // By default this properties descriptors are set to true. -------------------------------------------------------------------------------- /03 Prototypes/09- Cheat Sheet.js: -------------------------------------------------------------------------------- 1 | // Every object (except the root object) has a prototype (parent). 2 | // To get the prototype of an object: 3 | Object.getPrototypeOf(obj); 4 | 5 | // In Chrome, you can inspect "__proto__" property. But you should 6 | // not use that in the code. 7 | 8 | // To get the attributes of a property: 9 | Object.getOwnPropertyDescriptor(obj, "propertyName"); 10 | 11 | // To set the attributes for a property: 12 | Object.defineProperty(obj, "propertyName", { 13 | configurable: false, // cannot be deleted 14 | writable: false, 15 | enumerable: false, 16 | }); 17 | 18 | // Constructors have a "prototype" property. It returns the object 19 | // that will be used as the prototype for objects created by the constructor. 20 | Object.prototype === Object.getPrototypeOf({}); 21 | Array.prototype === Object.getPrototypeOf([]); 22 | 23 | // All objects created with the same constructor will have the same prototype. 24 | // A single instance of this prototype will be stored in the memory. 25 | const x = {}; 26 | const y = {}; 27 | Object.getPrototypeOf(x) === Object.getPrototypeOf(y); // returns true 28 | 29 | // Any changes to the prototype will be immediately visible to all objects 30 | // referencing this prototype. 31 | 32 | // When dealing with large number of objects, it's better to put their 33 | // methods on their prototype. This way, a single instance of the methods 34 | // will be in the memory. 35 | Circle.prototype.draw = function () {}; 36 | 37 | // To get the own/instance properties: 38 | Object.keys(obj); 39 | 40 | // To get all the properties (own + prototype): 41 | for (let key in obj) { 42 | } 43 | -------------------------------------------------------------------------------- /03 Prototypes/10- Exercise.js: -------------------------------------------------------------------------------- 1 | // 10 - Exercise 2 | 3 | function StopWatch() { 4 | let startTime, 5 | endTime, 6 | running, 7 | duration = 0; 8 | Object.defineProperty(this, "duration", { 9 | get: function () { 10 | return duration; 11 | }, 12 | set: function (value) { 13 | duration = value 14 | } 15 | }); 16 | Object.defineProperty(this, "startTime", { 17 | get: function () { 18 | return startTime; 19 | }, 20 | }); 21 | Object.defineProperty(this, "endTime", { 22 | get: function () { 23 | return endTime; 24 | }, 25 | }); 26 | Object.defineProperty(this, "running", { 27 | get: function () { 28 | return running; 29 | }, 30 | }); 31 | } 32 | 33 | StopWatch.prototype.start = function () { 34 | if (this.running) throw new Error("Stopwatch is already started"); 35 | this.running = true; 36 | this.startTime = new Date(); 37 | }; 38 | 39 | StopWatch.prototype.stop = function () { 40 | if (!this.running) throw new Error("Stopwatch is already stopped"); 41 | this.running = false; 42 | this.endTime = new Date(); 43 | const seconds = (endTime.getTime() - startTime.getTime()) / 1000; 44 | this.duration += seconds; 45 | }; 46 | 47 | StopWatch.prototype.reset = function () { 48 | this.startTime = null; 49 | this.endTime = null; 50 | this.running = false; 51 | this.duration = 0; 52 | }; 53 | 54 | 55 | 56 | const sw = new StopWatch(); 57 | sw.duration = 10; 58 | 59 | // In this case of the Stop Watch the previous implementation was better. 60 | // This case we end up exposing the duration property, that was a read only property. 61 | // It broke the abstraction principle. 62 | -------------------------------------------------------------------------------- /02 Objects/07- Value vs Reference Types.js: -------------------------------------------------------------------------------- 1 | // 07- Value vs Reference Types 2 | 3 | /* 4 | As we seen before in JavaScript we have two category of type 5 | 6 | Primitives Types (or Value Types) 7 | String 8 | Numbers 9 | Boolean 10 | Symbol 11 | undefined 12 | null (object) 13 | 14 | Reference Types (or Objects) 15 | Objects 16 | Array 17 | Function 18 | 19 | 20 | */ 21 | 22 | let x = 10; 23 | let y = x; 24 | 25 | x = 20; 26 | 27 | console.log(y); // It returns 10. 28 | //Primitives are independent, the value is stored inside of the variable. 29 | 30 | let xObj = {value: 10}; 31 | let yObj = x; 32 | 33 | x.value = 20; 34 | 35 | console.log(yObj); // It return 20. 36 | // In using object they are not stored in the variable. They are stored somewhere in the memory, and the address (or the reference) of that place in memory is store in the variable. 37 | 38 | // Primitives are copied by their value. 39 | // Objects are copied by their reference. 40 | 41 | 42 | let number = 10; 43 | 44 | function increase(number) { 45 | number++; 46 | } 47 | 48 | increase(number); 49 | console.log(number); // It returns 10. 50 | // When we call increase and pass the number variable to that functions as an argument. 51 | // The "number" variable is completely independent from the "number" paramter in the "increase()" function. 52 | // The "number" parameter is local to the "increase()" function. 53 | 54 | 55 | 56 | let obj = {value: 10}; 57 | 58 | function increase(obj) { 59 | obj.value++; 60 | } 61 | 62 | increase(obj); 63 | console.log(obj); // It returns { value: 11 }. 64 | 65 | // In this case we are not dealing with two independent copies. 66 | // So any changes made to that object will be visible in the variable. -------------------------------------------------------------------------------- /04 Prototypical Inheritance/06- Polymorphism.js: -------------------------------------------------------------------------------- 1 | // 06 - Polymorphism 2 | 3 | 4 | /* 5 | Polymorphism comes from the word Polymorph. 6 | 7 | Poly: Many. 8 | Morph: Change from one form to another. 9 | So Polymorphism is the ability to take on multiple forms. 10 | 11 | This is an extremely powerful technic in OOP 12 | 13 | with the following code we have many implementation (or many forms) of the duplicate() method. 14 | */ 15 | 16 | function extend(Parent, Child) { 17 | Child.prototype = Object.create(Parent.prototype); 18 | Child.prototype.constructor = Child; 19 | } 20 | 21 | function Shape(color) { 22 | this.color = color; 23 | } 24 | 25 | Shape.prototype.duplicate = function () { 26 | console.log("duplicate"); 27 | }; 28 | 29 | function Circle(radius, color) { 30 | this.radius = radius; 31 | Shape.call(this, color); 32 | } 33 | 34 | extend(Shape, Circle); 35 | 36 | Circle.prototype.draw = function () { 37 | console.log("draw circle"); 38 | }; 39 | 40 | Circle.prototype.duplicate = function () { 41 | console.log("duplicate circle"); 42 | }; 43 | 44 | function Square(size, color) { 45 | this.size = size; 46 | Shape.call(this, color); 47 | } 48 | 49 | extend(Shape, Square); 50 | 51 | Square.prototype.draw = function () { 52 | console.log("draw Square"); 53 | }; 54 | 55 | Square.prototype.duplicate = function () { 56 | console.log("duplicate square"); 57 | }; 58 | 59 | const myShapes = [new Circle(1, "blue"), new Square(1, "red")]; 60 | 61 | // Depending on the type of the shape object, a different form, or a different implementation of the duplicate() method will be called. 62 | for (let shape of myShapes) { 63 | shape.duplicate(); 64 | } 65 | 66 | // So encapsulating variables and functions into objects, and use inheritance, allows us to execute many forms of a method. -------------------------------------------------------------------------------- /02 Objects/03- Factories.js: -------------------------------------------------------------------------------- 1 | // 03 - Factories 2 | 3 | /* 4 | In the last lesson we use the object literal syntax to create ann object. But in case we need to create more than one of teh same object. 5 | For a better implementation we use Factory and Constructor Functions. 6 | In this lesson we are looking at Factory Functions. 7 | Just like a factory producing products, this factory functions produce objects. 8 | */ 9 | 10 | // Create a new function and copy the object in it 11 | function createCircle () { 12 | const circle = { 13 | radius: 1, 14 | location: { 15 | x: 10, 16 | y: 20 17 | }, 18 | isVisible: true, 19 | draw: function() { 20 | console.log('Draw') 21 | }, 22 | move: function() { 23 | console.log('Move') 24 | } 25 | }; 26 | return circle 27 | } 28 | 29 | // We can improve syntax and make it shorter, and we can pass a parameter to the function. 30 | function createCircle (radius, x, y) { 31 | return { 32 | radius, // in JavaScript if our key and value are the same "radius: radius", we can make our code sorter and simply remove the value. 33 | location: { 34 | x, 35 | y 36 | }, 37 | draw() { // For functions we don't need the full function syntax to define the function. 38 | console.log('Draw') 39 | }, 40 | move() { 41 | console.log('Move') 42 | }, 43 | }; 44 | } 45 | 46 | /* 47 | With this Factory Function we have define our logic only in one place, and the we can call this function, in our program and pass to it different arguments. 48 | In case of a bug in the future there is only one place to modify. 49 | */ 50 | 51 | const circle1 = createCircle(1, 2, 3) 52 | circle1.draw() -------------------------------------------------------------------------------- /03 Prototypes/05- Constructor Prototypes.js: -------------------------------------------------------------------------------- 1 | // 05- Constructor Prototypes 2 | 3 | /* 4 | The constructor property returns a reference to the Object constructor function that created the instance object. 5 | Note that the value of this property is a reference to the function itself, not a string containing the function's name. 6 | 7 | The value is only read-only for primitive values such as 1, true, and "test". 8 | */ 9 | 10 | let objectLiteral = {}; 11 | console.log(Object.getPrototypeOf(objectLiteral)) 12 | console.log(objectLiteral.constructor === Object); // true 13 | 14 | let objectConstructor = new Object(); 15 | console.log(Object.getPrototypeOf(objectConstructor)); 16 | console.log(objectConstructor.constructor === Object); // true 17 | 18 | let arrayLiteral = []; 19 | console.log(arrayLiteral.constructor === Array); // true 20 | 21 | let arrayConstructor = new Array(); 22 | console.log(arrayConstructor.constructor === Array); // true 23 | 24 | let numberLiteral = 3; 25 | console.log(numberLiteral.constructor === Number); // true 26 | 27 | let numberConstructor = new Number(3); 28 | console.log(numberConstructor.constructor === Number); // true 29 | 30 | 31 | // As function in JavaScript are objects. A Constructor Function also have a prototype property 32 | 33 | function Circle(radius) { 34 | this.radius = radius 35 | } 36 | 37 | console.log(Circle.prototype); // This is the Object that will be used as the parent for object created by the Circle constructor function. Lets call it the circleBase 38 | 39 | const myCircle = new Circle(10); 40 | console.log(Object.getPrototypeOf(myCircle)); // This returns the same object as Circle.prototype, the circleBase 41 | console.log(myCircle.constructor); // This will return the circle constructor function 42 | /* 43 | ƒ Circle(radius) { 44 | this.radius = radius; 45 | } 46 | */ -------------------------------------------------------------------------------- /04 Prototypical Inheritance/12- Exercise- Polymorphism.js: -------------------------------------------------------------------------------- 1 | // 12 - Exercise - Polymorphism 2 | 3 | function HtmlElement() { 4 | this.click = function () { 5 | console.log("clicked"); 6 | }; 7 | } 8 | 9 | HtmlElement.prototype.focus = function () { 10 | console.log("focused"); 11 | }; 12 | 13 | function HtmlSelectElement(...elements) { 14 | this.items = [...elements]; 15 | this.addItem = function (item) { 16 | this.items.push(item); 17 | }; 18 | this.removeItem = function (item) { 19 | const index = this.items.indexOf(item); 20 | if (index > -1) this.items.splice(index, 1); 21 | }; 22 | this.render = function () { 23 | // let htmlOptions = ""; 24 | // this.items.forEach((item) => { 25 | // htmlOptions += `\n `; 26 | // }); 27 | // return ``; 28 | return ` 29 | `; 32 | }; 33 | } 34 | 35 | HtmlSelectElement.prototype = new HtmlElement(); 36 | HtmlSelectElement.prototype.constructor = HtmlSelectElement; 37 | 38 | function HtmlImageElement(src) { 39 | this.src = src; 40 | this.render = function () { 41 | return ``; 42 | }; 43 | } 44 | 45 | HtmlImageElement.prototype = new HtmlElement(); 46 | HtmlImageElement.prototype.constructor = HtmlImageElement; 47 | 48 | const myHtmlSelectElement = new HtmlSelectElement(1, 2, 3, 4); 49 | console.log(myHtmlSelectElement); 50 | // console.log(myHtmlSelectElement.render()); 51 | 52 | const myHtmlImageElement = new HtmlImageElement("http://blablabla.com/"); 53 | console.log(myHtmlImageElement); 54 | // console.log(myHtmlImageElement.render()); 55 | 56 | const htmlArray = [myHtmlSelectElement, myHtmlImageElement]; 57 | 58 | for (let element of htmlArray) { 59 | console.log(element.render()); 60 | } 61 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/07- When to Use Inheritance.md: -------------------------------------------------------------------------------- 1 | # 07- When to Use Inheritance 2 | 3 | While inheritance is a great tool to reuse code we should be careful using it. 4 | It is better to start with simple object, if we see these object share similar features, then we can encapsulate these features in a generic object and inherit those features 5 | 6 | In the following example Inheritance may cause some problems. 7 | We may have an Animal object with two methods: 8 | 9 | - `eat()` 10 | - `walk()` 11 | 12 | The objects that derive from Animal, Person and Dog, can inherit these two methods. 13 | 14 | ![Inheritance](./images/07-01.png "Inheritance") 15 | 16 | But maybe tomorrow we want to introduce a Goldfish object that also derives form Animal. This can break our hierarchy, because Goldfish can't walk, they swim. 17 | 18 | ![Inheritance](./images/07-02.png "Inheritance") 19 | 20 | To fix this we need to change our hierarchy, And introduce a Mammal object and a Fish object. This menas increasing the complexity of our hierarchy. 21 | 22 | ![Inheritance](./images/07-03.png "Inheritance") 23 | 24 | Avoid creating inheritance hierarchies. It is best to keep inheritance to one level. 25 | In some situations it is better to favor Composition over Inheritance. With composition in instead of having a complex hierarchy, we can compose a few objects together to create a new object, this technic gives us great flexibility. 26 | 27 | So we can have 3 plain JavaScript objects, with certain properties and methods, like: 28 | 29 | - `canWalk()` 30 | - `canEat()` 31 | - `canSwim()` 32 | 33 | If we want a Person object we can Compose `canWalk()` and `canEat()`. The same for the Goldfish, we can Compose `canSwim()` and `canEat()`. We don't have an hierarchy, and we can combine this object to create new objects. 34 | 35 | ![Inheritance](./images/07-04.png "Inheritance") 36 | 37 | In JavaScript we can use Mixing to achieve composition. 38 | -------------------------------------------------------------------------------- /03 Prototypes/02- Prototypes and Prototypical Inheritance.md: -------------------------------------------------------------------------------- 1 | 02- Prototypes and Prototypical Inheritance 2 | 3 | To implement inheritance in JavaScript objects following the example: 4 | 5 | ![Prototypical Inheritance](./images/02-01.png "Prototypical Inheritance") 6 | 7 | We implemente the common methods in the Shape object. We refer to the Shape object as the Prototype of the Circle. Prototype is essencial the parent of another object 8 | 9 | Every object in JavaScript has a parent object, when we create a object, if we inspect that object in tha console we can see the following: 10 | 11 | ```javascript 12 | let x = {}; 13 | // __proto__: 14 | // constructor: ƒ Object() 15 | // hasOwnProperty: ƒ hasOwnProperty() 16 | // isPrototypeOf: ƒ isPrototypeOf() 17 | // propertyIsEnumerable: ƒ propertyIsEnumerable() 18 | // toLocaleString: ƒ toLocaleString() 19 | // toString: ƒ toString() 20 | // valueOf: ƒ valueOf() 21 | // __defineGetter__: ƒ __defineGetter__() 22 | // __defineSetter__: ƒ __defineSetter__() 23 | // __lookupGetter__: ƒ __lookupGetter__() 24 | // __lookupSetter__: ƒ __lookupSetter__() 25 | // get __proto__: ƒ __proto__() 26 | // set __proto__: ƒ __proto__() 27 | ``` 28 | 29 | The property called `__proto__` is deprecated. 30 | 31 | We can call any of this methods in our x object. 32 | 33 | So x in an object and it has a link to another object, which is it's Prototype. This prototype, let's call it `objectBase`. Every Object in JavaScript inherits directly or indirectly from `objectBase`. 34 | 35 | `objectBase` is the root of all object in JavaScript, and it does not have a parent or Prototype. 36 | 37 | To get the Prototype of an object we can use: `Object.getPrototypeOf(x);` 38 | 39 | When we call a method in an object JavaScript will start looking for that method in the object it self. If we can't find it will go all the way up to the root object we called objectBase. 40 | 41 | A prototype is just a regular object in memory. 42 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/02- Resetting the Constructor.js: -------------------------------------------------------------------------------- 1 | // 02- Resetting the Constructor 2 | 3 | function Shape() {} 4 | 5 | // Define the duplicate() method in the Shape prototype 6 | Shape.prototype.duplicate = function () { 7 | console.log("duplicate"); 8 | }; 9 | 10 | function Circle(radius) { 11 | this.radius = radius; 12 | } 13 | 14 | // Define the draw() method in the Circle prototype 15 | Circle.prototype.draw = function () { 16 | console.log("draw circle"); 17 | }; 18 | 19 | function Square(size) { 20 | this.size = size; 21 | } 22 | 23 | // Define the draw() method in the Square prototype 24 | Square.prototype.square = function () { 25 | console.log("draw square"); 26 | }; 27 | 28 | // Here the Object.create(Shape.prototype) returns a object that inherits from shapeBase (Shape.prototype). 29 | // Then we assign it to the prototype of Circle and Square. 30 | Circle.prototype = Object.create(Shape.prototype); 31 | Square.prototype = Object.create(Shape.prototype); 32 | 33 | // If we don't reset the constructor the constructor for the Circle and Square will be the Shape constructor. 34 | console.log(Circle.prototype.constructor); // It returns the Shape constructor function 35 | /* 36 | ƒ Shape() { 37 | } 38 | */ 39 | 40 | // So if we try to create a new object with: 41 | const myObject = new Circle.prototype.constructor(); // We will get a shape object not a Circle object 42 | console.log(myObject); 43 | 44 | // In here we reset the constructor for the Circle and Square. 45 | Circle.prototype.constructor = Circle; 46 | Square.prototype.constructor = Square; 47 | // As a best practice if we reset the Prototype, we should reset the constructor as well. 48 | 49 | console.log(Circle.prototype.constructor); // Now it returns the Circle constructor function. 50 | /* 51 | ƒ Circle(radius) { 52 | this.radius = radius; 53 | } 54 | */ 55 | 56 | const myCircle = new Circle(1); 57 | myCircle.duplicate(); 58 | 59 | const mySquare = new Square(1); 60 | mySquare.duplicate(); 61 | -------------------------------------------------------------------------------- /06 ES6 Tooling/06- Webpack.md: -------------------------------------------------------------------------------- 1 | # 06- Webpack 2 | 3 | ## Install Webpack using Yarn 4 | 5 | We are installing Webpack locally as a development dependency. Run the following command `yarn add webpack webpack-cli --dev`. This will install the latest version of Webpack (version `5.21.2` at the moment). 6 | 7 | We are installing two packages: 8 | 9 | 1. webpack ---> Webpack it self 10 | 2. webpack-cli ---> Webpack Command Line Interface 11 | 12 | ## Directory structure 13 | 14 | To use Webpack we should have the following folder structure. 15 | 16 | ``` 17 | project-root-folder 18 | |- package.json 19 | |- index.html 20 | |- /src 21 | |- index.js 22 | ``` 23 | 24 | The `index.js` file in the `/src` folder is where we have our JavaScript code, and where we import other modules. 25 | 26 | ## Webpack configuration 27 | 28 | Since version 4, Webpack does not require a configuration file. But for complex projects one might be need. For this demonstration we will use a config file. 29 | 30 | ### Create config file 31 | 32 | Create a webpack.config.js file in the root folder and webpack will automatically use it. 33 | 34 | This is the standard configuration: 35 | 36 | ```javascript 37 | const path = require("path"); 38 | 39 | module.exports = { 40 | entry: "./src/index.js", 41 | output: { 42 | filename: "main.js", 43 | path: path.resolve(__dirname, "dist"), 44 | }, 45 | }; 46 | ``` 47 | 48 | ## Run Webpack 49 | 50 | To run Webpack, use the following command `yarn run webpack`. This will create a new folder for the bundle output of webpack `/dist/main.js`. 51 | 52 | Then in our `index.html` we can use the file generate by Webpack, replacing the ` 56 | ``` 57 | 58 | ### Webpack script 59 | 60 | We can add the script to run Webpack in the `package.json` file. Add the following script: 61 | 62 | ``` 63 | "build": "webpack --watch" 64 | ``` 65 | 66 | Adding the `--watch` flag will run Webpack every time we make a change to our files, and regenerates the bundle. -------------------------------------------------------------------------------- /04 Prototypical Inheritance/08- Mixins.js: -------------------------------------------------------------------------------- 1 | // 08 - Mixin 2 | 3 | /* 4 | To create mixin in JavaScript we can use the Object.assign() method 5 | The Object.assign() method copies all enumerable own properties from one or more source objects to a target object. It returns the target object. 6 | 7 | Syntax 8 | Object.assign(target, ...sources) 9 | 10 | Parameters 11 | target ---> The target object — what to apply the sources’ properties to, which is returned after it is modified. 12 | sources ---> The source object(s) — objects containing the properties you want to apply. 13 | 14 | Return value 15 | The target object. 16 | */ 17 | 18 | // We can define the features as objects: 19 | const canEat = { 20 | eat() { 21 | this.hunger--; 22 | console.log("eating"); 23 | }, 24 | }; 25 | 26 | const canWalk = { 27 | walk() { 28 | console.log("walking"); 29 | }, 30 | }; 31 | 32 | const canSwim = { 33 | swim() { 34 | console.log("swimming"); 35 | }, 36 | }; 37 | 38 | const myObject = Object.assign({}, canWalk, canEat); // Using the Object.assign() we can create a new object and add to it other objects. 39 | console.log(myObject); 40 | 41 | function Person(name) { 42 | this.name = name; 43 | } 44 | 45 | // Object.assign(Person.prototype, canWalk, canEat); // Using the Object.assign() we add method the the Person prototype 46 | mixin(Person.prototype, canWalk, canEat); 47 | 48 | const person = new Person("Miguel"); 49 | console.log(person); 50 | /* 51 | Person {name: "Miguel"} 52 | name: "Miguel" 53 | __proto__: 54 | eat: ƒ eat() 55 | walk: ƒ walk() 56 | constructor: ƒ Person(name) 57 | __proto__: Object 58 | */ 59 | 60 | function Goldfish() {} 61 | // Object.assign(Goldfish.prototype, canSwim, canEat); 62 | mixin(Goldfish.prototype, canSwim, canEat); 63 | 64 | const goldfish = new Goldfish(); 65 | console.log(goldfish); 66 | /* 67 | Goldfish {} 68 | __proto__: 69 | eat: ƒ eat() 70 | swim: ƒ swim() 71 | constructor: ƒ Goldfish() 72 | __proto__: Object 73 | */ 74 | 75 | // To improve readability and make the code more DRY we can we can encapsulate the Object.assign(target, ...source); in a function 76 | function mixin(target, ...source) { 77 | Object.assign(target, ...source); 78 | } 79 | -------------------------------------------------------------------------------- /06 ES6 Tooling/01- Modules.md: -------------------------------------------------------------------------------- 1 | # 01- Modules 2 | 3 | [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) 4 | 5 | In real world applications our code is splitted into multiple files. We call each of this files a **Module**. 6 | 7 | ## Benefits of Modules 8 | 9 | **Modularity** gives us a number of benefits. 10 | 11 | 1. Maintainability 12 | 13 | We can increase teh maintainability of our application, because our code is better organized. 14 | 15 | 2. Reuse 16 | 17 | We can reuse one or more of this modules in different parts of the application, or even in other applications. 18 | 19 | 3. Abstract 20 | 21 | We can abstract code. Hiding some of the complexity in a Module, and only expose the essentials. 22 | 23 | For example in the following code, if we can access the `const _radius = new WeakMap();` we can read the radius private property of the circle object. What we should do is place the `const _radius = new WeakMap();` and the `class Circle {}` in a different file, and then only expose the `class Circle {}` to the outside. 24 | 25 | ```javascript 26 | const _radius = new WeakMap(); 27 | 28 | class Circle { 29 | constructor(radius) { 30 | _radius.set(this, radius); 31 | } 32 | 33 | draw() { 34 | const radius = _radius.get(this); 35 | console.log(`draw radius: ${radius}`); 36 | } 37 | } 38 | 39 | const circle = new Circle(10); 40 | console.log(_radius.get(c)); // Returns the private radius property: 10 41 | ``` 42 | 43 | ## History of modules 44 | 45 | In ES5 there was no concept of modules, so different solutions emerged to solve this problem. The community of developers introduced new syntaxes to define modules, we refer fo this syntaxes as **Modules Formats**. 46 | 47 | ### Module Formats 48 | 49 | 1. AMD - Asynchronous Module Definition ---> Primarily used in Browser applications 50 | 2. CommonJS ---> Used in Node.js 51 | 3. UMD - Universal Module Definition ---> Can be used both in the Browser and Node.js 52 | 4. ES6 Modules ---> Since ES6 JavaScript natively supports a module format, used in Browsers. 53 | 54 | From this list in the next lessons we are going to focus on two formats, **CommonJS**, because it is used in Node.js and **ES6 Modules**, its used in browsers. 55 | -------------------------------------------------------------------------------- /02 Objects/13- Cheat Sheet.js: -------------------------------------------------------------------------------- 1 | // The simplest way to create an object is using an object literal 2 | const circle = { 3 | radius: 1, 4 | draw: function () {}, 5 | }; 6 | 7 | // To create multiple objects with the same structure and behaviuor (methods), use a factory or a constructor. 8 | 9 | // Factory function 10 | function createCircle(radius) { 11 | return { 12 | radius, 13 | draw: function () {}, 14 | }; 15 | } 16 | 17 | // Constructor function 18 | function Circle(radius) { 19 | this.radius = radius; 20 | this.draw = function () {}; 21 | } 22 | 23 | // Every object has a "constructor" property which returns the function that was used to construct or create that object. 24 | const x = {}; 25 | x.constructor; // returns Object() 26 | 27 | // In JavaScript, functions are objects. They have properties and methods. 28 | Circle.name; 29 | Circle.length; 30 | Circle.constructor; // returns Function() 31 | Circle.call({}, 1); // to call the Circle function 32 | Circle.apply({}, [1]); 33 | 34 | // Value types are copied by their value, reference types are copied by their reference. 35 | // Value types in JavaScript are: String, Number, Boolean, Symbol, undefined and null 36 | // Reference types are: Object, Function and Array 37 | 38 | // JavaScript objects are dynamic. You can add/remove properties: 39 | circle.location = {}; 40 | circle["location"] = {}; 41 | 42 | delete circle.location; 43 | 44 | // To enumerate the members in an object: 45 | for (let key in circle) console.log(key, circle[key]); 46 | 47 | Object.keys(circle); 48 | 49 | // To see if an object has a given property 50 | if ("location" in circle) 51 | // Abstraction means hiding the complexity/details and showing only the essentials. 52 | // We can hide the details by using private members. Replace "this" with "let". 53 | 54 | function Circle(radius) { 55 | // Public member 56 | this.radius = radius; 57 | 58 | // Private member 59 | let defaultLocation = {}; 60 | } 61 | 62 | // To define a getter/setter, use Object.defineProperty(): 63 | 64 | Object.defineProperty(this, "defaultLocation", { 65 | get: function () { 66 | return defaultLocation; 67 | }, 68 | set: function (value) { 69 | defaultLocation = value; 70 | }, 71 | }); 72 | -------------------------------------------------------------------------------- /06 ES6 Tooling/05- Babel.md: -------------------------------------------------------------------------------- 1 | # 05- Babel 2 | 3 | ## [Install NVM and Node.js](https://github.com/nvm-sh/nvm) 4 | 5 | First we need to install **nvm** which is a version manager for **Node.js**. I installed it using [Homebrew package manager](https://formulae.brew.sh/formula/nvm) `brew install nvm`. 6 | 7 | After installing **nvm**, we can install **Node.js** by running the following command `nvm install node`. This will install the latest version of **Node.js** 8 | 9 | ## [Install and use Yarn](https://yarnpkg.com/) 10 | 11 | As the **Node.js** package manager I prefer to use **Yarn**, it can be installed as a **Node.js** package with the following command `npm install -g yarn`. This will install **Yarn** globally, for all projects. 12 | 13 | Then Move into your project folder `cd ~/path/to/project`, and run `yarn set version latest`. This will install the latest version on this project. 14 | 15 | Run `yarn init` in the project root folder to start a new project. 16 | 17 | ## Install Babel using Yarn 18 | 19 | Now we can install Babel using **Yarn** with the following command `yarn add [package]`. 20 | 21 | `yarn add @babel/cli @babel/core @babel/preset-env --dev` 22 | 23 | 1. **@babel/cli** ---> Babel Command Line Interface ---> Is the tool we run from teh command line which can be used to compile files from the command line. 24 | 2. **@babel/core** ---> It is basically the core of babel where all the logic for transpiling code is implemented. 25 | 3. **@babel/preset-env** ---> Its basically teh combination of all the babel plugin's, that allows you to use the latest JavaScript features 26 | 27 | The `--dev` flag means this packages are going to be installed as development dependencies, and they will not be installed in the production environment. 28 | 29 | Im am installing the latest version. To specify a version use `yarn add [package]@[version]` 30 | 31 | ## Babel CLI 32 | 33 | Add the following script to the `package.json` 34 | Create the `build` folder in the root of the project 35 | 36 | ```json 37 | "scripts": { 38 | "babel": "babel index.js --presets=@babel/preset-env --out-file build/index.js" 39 | }, 40 | ``` 41 | 42 | Then in the terminal run `yarn run babel`. This will transpile th `index.js` file to a new file in `build/index.js`. 43 | -------------------------------------------------------------------------------- /03 Prototypes/06- Prototype vs Instance Members.js: -------------------------------------------------------------------------------- 1 | // 06- Prototype vs Instance Members 2 | 3 | function Circle(radius) { 4 | this.radius = radius; 5 | 6 | this.draw = () => { 7 | console.log("draw"); 8 | }; 9 | } 10 | 11 | const c1 = new Circle(1); 12 | console.log(c1); 13 | /* 14 | Circle {radius: 1, draw: ƒ} 15 | draw: () => { console.log("draw"); } 16 | radius: 1 17 | __proto__: Object 18 | */ 19 | const c2 = new Circle(2); 20 | console.log(c2); 21 | /* 22 | Circle {radius: 2, draw: ƒ} 23 | draw: () => { console.log("draw"); } 24 | radius: 2 25 | __proto__: Object 26 | 27 | In this implantation we will have the draw() method duplicated in each circle. 28 | If we have a thousand circles in memory, we would have a thousand copies of the draw() method.T his could take a lot of memory. 29 | */ 30 | 31 | // We can take the draw method out of the circle object and put it in the prototype. 32 | // We will have a single instance in memory of this prototype. 33 | // This way will only have a single instance of the draw method. 34 | function CircleInheritance(radius) { 35 | this.radius = radius; // Instance members 36 | 37 | this.move = function () { 38 | console.log("move"); 39 | this.bigger(); // Here we call a Prototype member in an instance member. 40 | }; 41 | } 42 | 43 | // Prototype members 44 | // This way we move the draw method to the prototype 45 | CircleInheritance.prototype.draw = function () { 46 | this.move(); // We can reference an Instance method in an prototype method and vice versa 47 | console.log("draw"); 48 | }; 49 | 50 | CircleInheritance.prototype.bigger = function () { 51 | console.log("bigger circle"); 52 | }; 53 | 54 | const c3 = new CircleInheritance(3); 55 | console.log(c3); 56 | /* 57 | CircleInheritance {radius: undefined} 58 | radius: undefined 59 | __proto__: Object 60 | */ 61 | 62 | const c4 = new CircleInheritance(4); 63 | console.log(c4); 64 | /* 65 | CircleInheritance {radius: undefined} 66 | radius: undefined 67 | __proto__: Object 68 | */ 69 | 70 | // We can override a method from objectBase, in the prototype of our circle object. 71 | CircleInheritance.prototype.toString = function () { 72 | return "This circle has a radius of " + this.radius; 73 | }; 74 | 75 | console.log(c3.toString()); 76 | console.log(c4.toString()); -------------------------------------------------------------------------------- /05 ES6 Classes/01- ES6 Classes.js: -------------------------------------------------------------------------------- 1 | // 01- ES6 Classes 2 | 3 | /* 4 | In modern JavaScript ES6 (ES2015) we have a new way to create object and implement inheritance, using classes. 5 | Classes in JavaScript are not like classes in other Object Orientated Languages, like Java or Ruby. 6 | They are essential syntactic sugar over Prototypical Inheritance. 7 | 8 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes 9 | Classes are in fact "special functions", and just as you can define function expressions and function declarations, the class syntax has two components: 10 | class expressions 11 | class declarations. 12 | */ 13 | 14 | // Using the old syntax ---> Constructor Function 15 | function CircleOld(radius) { 16 | // Defining the radius property as an Instance member 17 | this.radius = radius; 18 | // Defining the move method as an Instance member 19 | this.move = function () { 20 | console.log("move"); 21 | }; 22 | } 23 | 24 | CircleOld.prototype.draw = function () { 25 | // Defining the draw method as an Prototype member 26 | console.log("draw"); 27 | }; 28 | 29 | // Using the new syntax ---> Class 30 | class CircleNew { 31 | // Body of the class 32 | // The constructor method is used to initialize objects. 33 | constructor(radius) { 34 | // Defining the radius property, in the Constructor Body, as an Instance member. 35 | this.radius = radius; 36 | // Defining the move method, in the Constructor Body, as an Instance member. 37 | this.move = function () { 38 | console.log("move"); 39 | }; 40 | } 41 | 42 | // Defining the draw method, in the Class Body, as an Prototype member. 43 | draw() { 44 | console.log("draw"); 45 | } 46 | } 47 | 48 | const oldCircle = new CircleOld(1); // Instantiating a new circle with the Constructor function 49 | /* 50 | CircleOld {radius: 1, move: ƒ} 51 | move: ƒ () 52 | radius: 1 53 | __proto__: 54 | draw: ƒ () 55 | constructor: ƒ CircleOld(radius) 56 | __proto__: Object 57 | */ 58 | 59 | const newCircle = new CircleNew(1); // Instantiating a new circle with the Class syntax 60 | /* 61 | CircleNew {radius: 1, move: ƒ} 62 | move: ƒ () 63 | radius: 1 64 | __proto__: 65 | constructor: class CircleNew 66 | draw: ƒ draw() 67 | __proto__: Object 68 | */ 69 | 70 | console.log(typeof CircleNew); // 'function' 71 | -------------------------------------------------------------------------------- /05 ES6 Classes/06- Private Members Using WeakMaps.js: -------------------------------------------------------------------------------- 1 | // 06- Private Members Using WeakMaps 2 | 3 | // The WeakMap object is a collection of key/value pairs in which the keys are objects only and the values can be arbitrary values. 4 | // The object references in the keys are held weakly, meaning that they are a target of garbage collection (GC) if there is no other reference to the object anymore. 5 | 6 | const _radius = new WeakMap(); 7 | const _move = new WeakMap(); 8 | 9 | class Circle { 10 | constructor(radius) { 11 | // We call the set method in _radius, as a first argument we have to pass an object, so we pass "this" as a reference to the object that will be created by the Circle class. 12 | // Technically we can access this private property, if we can access the private property, We can hide the _radius in a module and only export the Circle class. 13 | _radius.set(this, radius); 14 | _move.set(this, () => { 15 | // Creating a private method. 16 | // If we use a arrow function "this" will reference the instance of the object. Because arrow function use the this value of their containing function. Here the constructor. 17 | // If we use a function declaration "this" will reference the global object. And because we are in a Class will return undefined. 18 | console.log("move", this); 19 | }); 20 | } 21 | 22 | draw() { 23 | const radius = _radius.get(this); // We can use this syntax to access private properties within the class body. 24 | _move.get(this)(); // With the same syntax we can access the private method. 25 | console.log(`draw radius: ${radius}`); 26 | } 27 | } 28 | 29 | const myCircle = new Circle(1); 30 | myCircle.draw(); 31 | 32 | // Instead of using one WeakMap to each property or method. We can use the same as WeakMap to all private properties and methods. 33 | const privateProps = new WeakMap(); 34 | 35 | class AnotherCircle { 36 | constructor(radius) { 37 | privateProps.set(this, { 38 | radius: radius, 39 | move: () => { 40 | console.log("move", this); 41 | }, 42 | }); 43 | } 44 | draw() { 45 | const radius = privateProps.get(this.radius); // We can use this syntax to access private properties within the class body. 46 | _move.get(this.move()); // With the same syntax we can access the private method. 47 | console.log(`draw radius: ${radius}`); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /05 ES6 Classes/04- The This Keyword.js: -------------------------------------------------------------------------------- 1 | // 'use strict'; 2 | 3 | // 04- The This Keyword 4 | 5 | /* 6 | Binding this with prototype and static methods 7 | When a static or prototype method is called without a value for this, such as by assigning the method to a variable and then calling it, the this value will be undefined inside the method. 8 | This behavior will be the same even if the "use strict" directive isn't present, because code within the class body's syntactic boundary is always executed in strict mode. 9 | 10 | On the other hand using function-based syntax in non–strict mode, then this method calls are automatically bound to the initial this value, 11 | which by default is the global object (global in node.js and the window in browser). 12 | In strict mode, autobinding will not happen; the value of this remains as passed. 13 | */ 14 | 15 | function CircleFunction() { 16 | this.draw = function () { 17 | console.log(this); // This will point to the object created by the function 18 | }; 19 | } 20 | 21 | const circleFunc = new CircleFunction(); 22 | 23 | // Method call ---> We are calling a method on an object. 24 | circleFunc.draw(); // Here "this" is pointing to the object circleFunc 25 | /* 26 | CircleFunction {draw: ƒ} 27 | draw: ƒ () 28 | __proto__: 29 | constructor: ƒ CircleFunction() 30 | __proto__: Object 31 | */ 32 | 33 | console.log(circleFunc.draw); 34 | /* 35 | It will return the function 36 | ƒ () { 37 | console.log(this); 38 | } 39 | */ 40 | 41 | const drawFunc = circleFunc.draw; // When we assign the draw function to a variable, without calling the functions, and only reference it. 42 | 43 | // Function call ---> We are calling draw() as a standalone function that is not part of an object. 44 | drawFunc(); 45 | // Here "this" is pointing to the glocal object. It returns the global object: 46 | // Window {window: Window, self: Window, document: document, name: "", location: Location, …} 47 | // If we use strict mode, if will return ---> undefined 48 | 49 | class CircleClass { 50 | draw() { 51 | console.log(this); 52 | } 53 | } 54 | 55 | const circleClass = new CircleClass(); 56 | const drawClass = circleClass.draw; 57 | drawClass(); 58 | // Because the body of the class is always executed in strict mode. 59 | // Here it will return undefined, here it will return undefined even if we do not explicitly enable the strict mode. 60 | // This will prevent use from modifying the global object. 61 | -------------------------------------------------------------------------------- /05 ES6 Classes/05- Private Members Using Symbols.js: -------------------------------------------------------------------------------- 1 | // 05- Private Members Using Symbols 2 | 3 | // One of the core principles of OOP is abstraction, hiding the details, and showing only the essential. 4 | // To implement abstraction we hide certain properties and methods. 5 | // We make them private. 6 | 7 | // In the following example Properties and Methods from the circle class as public. 8 | class CirclePublic { 9 | constructor(radius) { 10 | this.radius = radius; 11 | } 12 | draw() { 13 | console.log("draw"); 14 | } 15 | } 16 | 17 | const myPublicCircle = new CirclePublic(1); 18 | // We can access this properties an methods form the outside. 19 | console.log(myPublicCircle.radius); 20 | myPublicCircle.draw(); 21 | 22 | /* 23 | In this example we will use private Methods and Properties. 24 | There are 3 approaches to this 25 | 1 - Use an underscore "this._radius", this is just a naming convention that some developers use, but it does not actually make the methods or properties private. DO NOT USE 26 | 2 - Using Symbols 27 | 3 - Using WeakMaps 28 | 4 - Using # names ---> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Private_class_fields 29 | */ 30 | 31 | console.log(Symbol() === Symbol()); // It returns false, because every time we call the Symbol() we get a new unique value. 32 | 33 | const _radius = Symbol(); // We call the Symbol(); function to generate a Symbol, which is essential a unique identifier. 34 | const _draw = Symbol(); 35 | 36 | class CirclePrivate { 37 | constructor(radius) { 38 | this[_radius] = radius; // To use the _radius Symbol as a property we use the bracket notation. 39 | } 40 | // In ES6 we can use the Computed Property Name feature to create a private method 41 | // We add brackets, the expression inside the brackets is evaluated, and the result will be use as the name of the method or property. 42 | [_draw]() { 43 | console.log("draw"); 44 | } 45 | } 46 | 47 | const myPrivateCircle = new CirclePrivate(1); 48 | 49 | console.log(myPrivateCircle._radius); // The radius property is private, so it returns undefined 50 | 51 | // There is a hack around it 52 | const circleProperties = Object.getOwnPropertySymbols(myPrivateCircle); // This will return an array of symbols 53 | console.log(circleProperties); // [Symbol()] 54 | 55 | // If we access the first item in the array and pass to it to the myPrivateCircle, using the bracket notation. It will return 1, the value of the property _radius. 56 | console.log(myPrivateCircle[circleProperties[0]]); 57 | 58 | // myPrivateCircle.draw(); // If we try to use the draw() methods it will raise an exception TypeError: myPrivateCircle.draw is not a function 59 | 60 | 61 | -------------------------------------------------------------------------------- /04 Prototypical Inheritance/01- Creating Your Own Prototypical Inheritance.js: -------------------------------------------------------------------------------- 1 | // 01- Creating Your Own Prototypical Inheritance 2 | 3 | /* 4 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain#inheritance_with_the_prototype_chain 5 | https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create 6 | 7 | Lets imagine we have a Circle object with a duplicate() method. 8 | And later we need a Square object that needs the exact same implementation of duplicate(). 9 | Instead of implementing the duplicate() method in both objects, we can have a Shape object with the duplicate() method. 10 | And both the Circle and Square object will inherit from the Shape object. 11 | 12 | To do this we use the Object.create() method 13 | The Object.create() method creates a new object, using an existing object as the prototype of the newly created object. 14 | 15 | Syntax 16 | Object.create(proto, [propertiesObject]) 17 | 18 | Parameters 19 | proto 20 | The object which should be the prototype of the newly-created object. 21 | 22 | propertiesObject - Optional 23 | 24 | If specified and not undefined, an object whose enumerable own properties (that is, those properties defined upon itself and not enumerable properties along its prototype chain) specify property descriptors to be added to the newly-created object, with the corresponding property names. 25 | These properties correspond to the second argument of Object.defineProperties(). 26 | 27 | Return value 28 | A new object with the specified prototype object and properties. 29 | 30 | Exceptions 31 | The proto parameter has to be either 32 | 33 | null or 34 | an Object excluding primitive wrapper objects. 35 | If proto is neither of these a TypeError is thrown. 36 | */ 37 | 38 | function Shape() { 39 | console.log("this is a shape"); 40 | } 41 | 42 | // Define the duplicate() method in the Shape prototype 43 | Shape.prototype.duplicate = function () { 44 | console.log("duplicate"); 45 | }; 46 | 47 | function Circle(radius) { 48 | this.radius = radius; 49 | } 50 | 51 | // Define the draw() method in the Circle prototype 52 | Circle.prototype.draw = function () { 53 | console.log("draw circle"); 54 | }; 55 | 56 | function Square(size) { 57 | this.size = size; 58 | } 59 | 60 | // Define the draw() method in the Square prototype 61 | Square.prototype.square = function () { 62 | console.log("draw square"); 63 | }; 64 | 65 | // Here the Object.create(Shape.prototype) returns a object that inherits from shapeBase (Shape.prototype). 66 | // Then we assign it to the prototype of Circle and Square. 67 | Circle.prototype = Object.create(Shape.prototype); 68 | Square.prototype = Object.create(Shape.prototype); 69 | 70 | const myCircle = new Circle(1); 71 | myCircle.duplicate(); 72 | 73 | const mySquare = new Square(1); 74 | mySquare.duplicate(); 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Code with Mosh - The Ultimate JavaScript Mastery Series - Part 2](https://codewithmosh.com/p/object-oriented-programming-in-javascript) 2 | 3 | [![The Ultimate JavaScript Mastery Series - Part 2](https://process.fs.teachablecdn.com/ADNupMnWyR7kCWRvm76Laz/resize=width:705/https://www.filepicker.io/api/file/GaDoSeRHQqeFuL19uPWR "The Ultimate JavaScript Mastery Series - Part 2")](https://codewithmosh.com/p/object-oriented-programming-in-javascript "The Ultimate JavaScript Mastery Series - Part 2") 4 | 5 | ### Introduction 6 | 7 | This repository was made while studying with [Mosh Hamedani](https://programmingwithmosh.com/ "Programming with Mosh"), in [Code with Mosh](https://codewithmosh.com/ "Code with Mosh"). And it contains all my notes from the course. It can be used as an extensive JavaScript cheatsheet. 8 | 9 | ### Course content 10 | 11 | 1. Getting Started 12 | 2. Objects 13 | 3. Prototypes 14 | 4. Prototypical Inheritance 15 | 5. ES6 Classes 16 | 6. ES6 Tooling 17 | 18 | ### Getting Started (17m) 19 | 20 | 1. What is OOP (1:45) 21 | 2. Four Pillars of OOP (7:02) 22 | 3. Setting Up the Development Environment (2:16) 23 | 4. Course Structure (2:55) 24 | 25 | ### Objects (1h15m) 26 | 27 | 1. Introduction (0:44) 28 | 2. Object Literals (3:03) 29 | 3. Factories (2:51) 30 | 4. Constructors (5:36) 31 | 5. Constructor Property (2:24) 32 | 6. Functions are Objects (4:47) 33 | 7. Value vs Reference Types (5:49) 34 | 8. Adding or Removing Properties (3:53) 35 | 9. Enumerating Properties (2:50) 36 | 10. Abstraction (4:02) 37 | 11. Private Properties and Methods (4:05) 38 | 12. Getters and Setters (5:36) 39 | 13. Cheat Sheet 40 | 14. Exercise- Stopwatch (2:08) 41 | 15. Solution- Stopwatch (2:31) 42 | 43 | ### Prototypes (40m) 44 | 45 | 1. Inheritance (2:26) 46 | 2. Prototypes and Prototypical Inheritance (5:33) 47 | 3. Multilevel Inheritance (2:51) 48 | 4. Property Descriptors (5:07) 49 | 5. Constructor Prototypes (3:52) 50 | 6. Prototype vs Instance Members (6:04) 51 | 7. Iterating Instance and Prototype Members (2:39) 52 | 8. Avoid Extending the Built-in Objects (1:41) 53 | 9. Cheat Sheet 54 | 10. Exercise (1:33) 55 | 11. Solution (5:38) 56 | 57 | ### Prototypical Inheritance (50m) 58 | 59 | 1. Creating Your Own Prototypical Inheritance (5:34) 60 | 2. Resetting the Constructor (4:00) 61 | 3. Calling the Super Constructor (3:48) 62 | 4. Intermediate Function Inheritance (3:05) 63 | 5. Method Overriding (3:29) 64 | 6. Polymorphism (4:22) 65 | 7. When to Use Inheritance (3:23) 66 | 8. Mixins (5:53) 67 | 9. Cheat Sheet 68 | 10. Exercise- Prototypical Inheritance (3:18) 69 | 11. Solution- Prototypical Inheritance (5:53) 70 | 12. Exercise- Polymorphism (2:35) 71 | 13. Solution- Polymorphism (5:11) 72 | 73 | ### ES6 Classes (55m) 74 | 75 | 1. ES6 Classes (5:41) 76 | 2. Hoisting (3:46) 77 | 3. Static Methods (4:17) 78 | 4. The This Keyword (4:57) 79 | 5. Private Members Using Symbols (7:48) 80 | 6. Private Members Using WeakMaps (6:58) 81 | 7. Getters and Setters (2:50) 82 | 8. Inheritance (4:00) 83 | 9. Method Overriding (2:33) 84 | 10. Cheat Sheet 85 | 11. Exercise (3:25) 86 | 12. Solution (4:20) 87 | 88 | ### ES6 Tooling (30m) 89 | 90 | 1. Modules (3:42) 91 | 2. CommonJS Modules (5:51) 92 | 3. ES6 Modules (3:23) 93 | 4. ES6 Tooling (1:26) 94 | 5. Babel (7:11) 95 | 6. Webpack (8:26) 96 | 7. Cheat Sheet 97 | 8. What to Learn Next 98 | -------------------------------------------------------------------------------- /02 Objects/12- Getters and Setters.js: -------------------------------------------------------------------------------- 1 | // 12- Getters and Setters 2 | 3 | /* 4 | Getters 5 | The get syntax binds an object property to a function that will be called when that property is looked up. 6 | 7 | Description 8 | Sometimes it is desirable to allow access to a property that returns a dynamically computed value, 9 | or you may want to reflect the status of an internal variable without requiring the use of explicit method calls. 10 | In JavaScript, this can be accomplished with the use of a getter. 11 | 12 | It is not possible to simultaneously have a getter bound to a property and have that property actually hold a value, 13 | although it is possible to use a getter and a setter in conjunction to create a type of pseudo-property. 14 | 15 | 16 | Setters 17 | The set syntax binds an object property to a function to be called when there is an attempt to set that property. 18 | 19 | Description 20 | In JavaScript, a setter can be used to execute a function whenever a specified property is attempted to be changed. 21 | Setters are most often used in conjunction with getters to create a type of pseudo-property. 22 | It is not possible to simultaneously have a setter on a property that holds an actual value. 23 | */ 24 | 25 | const person = { 26 | firstName: "Miguel", 27 | lastName: "Pimenta", 28 | get fullName() { 29 | return `${this.firstName} ${this.lastName}`; 30 | }, 31 | set fullName(name) { 32 | const nameParts = name.split(" "); 33 | this.firstName = nameParts[0]; 34 | this.lastName = nameParts[1]; 35 | }, 36 | }; 37 | 38 | console.log(person.fullName); // Here we print Miguel Pimenta using the getter 39 | 40 | person.fullName = "Viviane Sedola"; // Here with the setter we modify the full name to Viviane Sedola 41 | 42 | console.log(person.fullName); // Now with the getter the result is Viviane Sedola 43 | console.log(person); 44 | 45 | /* 46 | Object.defineProperty() 47 | For this example using Object.defineProperty() 48 | The static method Object.defineProperty() defines a new property directly on an object, or modifies an existing property on an object, and returns the object. 49 | 50 | Syntax 51 | Object.defineProperty(obj, prop, descriptor) 52 | 53 | Parameters 54 | obj 55 | The object on which to define the property. The object to which we want to add a new property to. 56 | 57 | prop 58 | The name or Symbol of the property to be defined or modified. 59 | 60 | descriptor 61 | The descriptor for the property being defined or modified. 62 | */ 63 | 64 | function Circle(radius) { 65 | let color = "red"; // Because were we are using a variable, instead of the "this" keyword, color it is not a property from this object, so it is not accessible from the outside. It is only a variable with local scope to this function. 66 | this.radius = radius; 67 | 68 | let defaultLocation = { x: 0, y: 0 }; 69 | 70 | this.draw = function draw() { 71 | console.log("Draw"); 72 | }; 73 | 74 | Object.defineProperty(this, 'defaultLocation', { 75 | get: () => { 76 | return defaultLocation; 77 | }, 78 | set: (value) => { 79 | if (!value.x || !value.y) // In the setter we can add logic to validate the argument passed to it. 80 | throw new Error("Invalid location") 81 | 82 | defaultLocation = value; 83 | } 84 | }); 85 | } 86 | 87 | const myCircle = new Circle(10); 88 | console.log(myCircle.defaultLocation); 89 | 90 | myCircle.defaultLocation = {x: 1, y: 1 }; 91 | console.log(myCircle.defaultLocation); 92 | -------------------------------------------------------------------------------- /01 Getting Started/02- Four Pillars of OOP.js: -------------------------------------------------------------------------------- 1 | // 02- Four Pillars of OOP 2 | 3 | /* 4 | 4 Pillar 5 | - Encapsulation 6 | - Abstraction 7 | - Inheritance 8 | - Polymorphism 9 | 10 | Before Object Orientated Programming, there was Procedural Programming. 11 | In Procedural Programming paradigm a program is divided into set of Function. We have data stored in a bunch of variables and Functions that operate in those variables. 12 | In OOP we combine a group of functions and variables into a unit, this unit is called an Object. 13 | The variables are called the properties and the functions methods. 14 | */ 15 | 16 | // Encapsulation 17 | 18 | // Procedural Programming 19 | // This is an implementation to calculate the wage of an employee. The variable that store the data and the function that operates in that data. 20 | let baseSalary = 30000; 21 | let overtime = 10; 22 | let rate = 20; 23 | 24 | function getWage(baseSalary, overtime, rate) { 25 | return baseSalary + overtime * rate; 26 | } 27 | 28 | getWage(baseSalary, overtime, rate); 29 | 30 | // Object Orientated Programming 31 | // We encapsulate the properties and the function in a single object. 32 | // In this way the functions does not have parameters. 33 | // Because the variables and the function are related, they are part of one unit. 34 | let employee = { 35 | baseSalary: 30000, 36 | overtime: 10, 37 | rate: 20, 38 | getWage() { 39 | return this.baseSalary + (this.overtime + this.rate); 40 | }, 41 | }; 42 | 43 | console.log(employee.getWage()); 44 | 45 | /* 46 | Abstraction 47 | For example a TV as a remote, we simply press a button like change volume or chanel, and the magic happens. We don't care about what happens in the index. 48 | All the complexity is hidden away. 49 | We can apply the same technic in our Objects. We can hide some of the properties and methods from the outside, and this gives us some benefits: 50 | -Simpler interface. Will make the interface of those objects simpler. Using and understanding an object with less properties and methods it's easier, 51 | - Reduce the impact of change. We can change some methods or properties, and it will not impact the outside, because we do not have any code that talks to these private methods. 52 | We should hide the details and complexity and show or expose only the essential. 53 | 54 | */ 55 | 56 | /* 57 | Inheritance 58 | Inheritance lets one object acquire the properties and methods of another object. 59 | If we have properties and method that are common to several Objects, we can define a general Object and theses objects will inherit from the general Object 60 | */ 61 | 62 | /* 63 | Polymorphism 64 | Means we can override a method or property inherited from the parent object, so it perform a different action in the child object. 65 | W might have a base prototype that is called Animal which defines makeNoise. 66 | Then every type extending from that prototype can override to do their own custom work. 67 | */ 68 | // Let's set up an Animal and Dog example 69 | function Animal(){} 70 | function Dog(){} 71 | 72 | Animal.prototype.makeNoise = function(){ 73 | console.log("Base noise"); 74 | }; 75 | 76 | // Most animals we code up have 4. This can be overridden if needed 77 | Animal.prototype.legs = 4; 78 | 79 | Dog.prototype = new Animal(); 80 | 81 | Dog.prototype.makeNoise = function(){ 82 | console.log("Woof woof"); 83 | }; 84 | 85 | var animal = new Animal(); 86 | var dog = new Dog(); 87 | 88 | animal.makeNoise(); // Base noise 89 | dog.makeNoise(); // Woof woof- this was overridden 90 | dog.legs; // 4! This was inherited 91 | 92 | -------------------------------------------------------------------------------- /03 Prototypes/03- Multilevel Inheritance.js: -------------------------------------------------------------------------------- 1 | // 03- Multilevel Inheritance 2 | 3 | // If we create a new array and inspect it we will se the following 4 | 5 | let myArray = []; 6 | /* 7 | [] 8 | length: 0 9 | __proto__: Array(0) 10 | concat: ƒ concat() 11 | constructor: ƒ Array() 12 | copyWithin: ƒ copyWithin() 13 | entries: ƒ entries() 14 | every: ƒ every() 15 | fill: ƒ fill() 16 | filter: ƒ filter() 17 | find: ƒ find() 18 | findIndex: ƒ findIndex() 19 | flat: ƒ flat() 20 | flatMap: ƒ flatMap() 21 | forEach: ƒ forEach() 22 | includes: ƒ includes() 23 | indexOf: ƒ indexOf() 24 | join: ƒ join() 25 | keys: ƒ keys() 26 | lastIndexOf: ƒ lastIndexOf() 27 | length: 0 28 | map: ƒ map() 29 | pop: ƒ pop() 30 | push: ƒ push() 31 | reduce: ƒ reduce() 32 | reduceRight: ƒ reduceRight() 33 | reverse: ƒ reverse() 34 | shift: ƒ shift() 35 | slice: ƒ slice() 36 | some: ƒ some() 37 | sort: ƒ sort() 38 | splice: ƒ splice() 39 | toLocaleString: ƒ toLocaleString() 40 | toString: ƒ toString() 41 | unshift: ƒ unshift() 42 | values: ƒ values() 43 | Symbol(Symbol.iterator): ƒ values() 44 | Symbol(Symbol.unscopables): {copyWithin: true, entries: true, fill: true, find: true, findIndex: true, …} 45 | __proto__: 46 | constructor: ƒ Object() 47 | hasOwnProperty: ƒ hasOwnProperty() 48 | isPrototypeOf: ƒ isPrototypeOf() 49 | propertyIsEnumerable: ƒ propertyIsEnumerable() 50 | toLocaleString: ƒ toLocaleString() 51 | toString: ƒ toString() 52 | valueOf: ƒ valueOf() 53 | __defineGetter__: ƒ __defineGetter__() 54 | __defineSetter__: ƒ __defineSetter__() 55 | __lookupGetter__: ƒ __lookupGetter__() 56 | __lookupSetter__: ƒ __lookupSetter__() 57 | get __proto__: ƒ __proto__() 58 | set __proto__: ƒ __proto__() 59 | 60 | |---------| 61 | | objBase | 62 | |---------| 63 | | 64 | | 65 | | 66 | |---------| 67 | |arrayBase| 68 | |---------| 69 | | 70 | | 71 | | 72 | |---------| 73 | | myArray | 74 | |---------| 75 | 76 | So we have myArray, that we created, and it derives from arrayBase and arrayBase derives from objectBase. 77 | This is whats it's called multilevel inheritance. 78 | */ 79 | 80 | 81 | // The custom object created using the constructor function 82 | function Circle(radius) { 83 | this.radius = radius; 84 | this.draw = () => { 85 | console.log('draw'); 86 | } 87 | } 88 | 89 | const myCircle = new Circle(10); 90 | 91 | /* 92 | Circle {radius: 10, draw: ƒ} 93 | draw: () => { console.log("draw"); } 94 | radius: 10 95 | __proto__: 96 | constructor: ƒ Circle(radius) 97 | arguments: null 98 | caller: null 99 | length: 1 100 | name: "Circle" 101 | prototype: {constructor: ƒ} 102 | __proto__: ƒ () 103 | [[FunctionLocation]]: index.js:1 104 | [[Scopes]]: Scopes[2] 105 | __proto__: 106 | constructor: ƒ Object() 107 | hasOwnProperty: ƒ hasOwnProperty() 108 | isPrototypeOf: ƒ isPrototypeOf() 109 | propertyIsEnumerable: ƒ propertyIsEnumerable() 110 | toLocaleString: ƒ toLocaleString() 111 | toString: ƒ toString() 112 | valueOf: ƒ valueOf() 113 | __defineGetter__: ƒ __defineGetter__() 114 | __defineSetter__: ƒ __defineSetter__() 115 | __lookupGetter__: ƒ __lookupGetter__() 116 | __lookupSetter__: ƒ __lookupSetter__() 117 | get __proto__: ƒ __proto__() 118 | set __proto__: ƒ __proto__() 119 | 120 | Every time we call the Circle constructor to create a new circle, this constructor will create anew circle and set it's prototype to circleBase. 121 | Objects created by a given constructor will have the same prototype. 122 | All circle objects created by the circle constructor will have the circleBase prototype. 123 | 124 | |---------| 125 | | objBase | 126 | |---------| 127 | | 128 | | 129 | | 130 | |----------| 131 | |circleBase| 132 | |----------| 133 | | 134 | | 135 | | 136 | |---------| 137 | |myCircle | 138 | |---------| 139 | 140 | */ --------------------------------------------------------------------------------