📕
Dan Fitz's Notes
  • README
  • Ai
    • Supervised Machine Learning
      • Introduction To Machine Learning
      • Regression With Multiple Input Variables
      • Classification
  • Csharp
    • C Sharp Advanced
      • Generics
      • Delegates
      • Lambda Expressions
      • Events
    • C Sharp Fundamentals
      • Intro To C
      • Primitive Types And Expressions
      • Non Primitive Types
      • Control Flow
      • Arrays And Lists
      • Working With Dates
      • Working With Text
      • Working With Files
      • Debugging Applications
    • C Sharp Intermediate
      • Classes
      • Association Between Classes
      • Inheritance
      • Polymorphism
      • Interfaces
  • Java
    • Inheritance Data Structures Java
      • Inheritance Polymorphism Using Overriding And Access Modifiers
      • Abstract Classes And Debugging
      • File I O And Exceptions
      • Collections Maps And Regular Expressions
    • Intro To Java
      • Introduction To Java Classes And Eclipse
      • Unit Testing Arrays And Array Lists
      • Static Variables Methods And Polymorphism Using Overloading
  • Javascript
    • Algorithms Data Structures
      • Big O Notation
      • Analyzing Performance Of Arrays And Objects
      • Problem Solving Approach
      • Problem Solving Patterns
      • Recursion
      • Searching Algorithms
      • Bubble Selection And Insertion Sort
      • Merge Sort
      • Quick Sort
      • Radix Sort
      • Data Structures Introduction
      • Singly Linked Lists
      • Doubly Linked Lists
      • Stacks And Queues
      • Binary Search Trees
      • Tree Traversal
      • Binary Heaps
    • Complete Nodejs
      • Understanding Node.js
      • REST AP Is And Mongoose
      • API Authentication And Security
      • Node.js Module System
      • File System And Command Line Args
      • Debugging Node.js
      • Asynchronous Node.js
      • Web Servers
      • Accessing API From Browser
      • Application Deployment
      • Mongo DB And Promises
    • Complete React Native
      • Working With Content
      • Building Lists
      • Navigating Users Between Screens
      • State Management
      • Handling Screen Layout
      • Setting Up An App
      • More On Navigation
      • Advanced Statement Management With Context
      • Building A Custom Express API
      • In App Authentication
    • Epic React
      • React Fundamentals
      • React Hooks
      • Advanced React Hooks
      • Advanced React Patterns
      • React Performance
    • Fireship Firestore
      • Firestore Queries And Data Modeling Course
      • Model Relational Data In Firestore No SQL
    • Functional Light Javascript
      • Intro
      • Function Purity
      • Argument Adapters
      • Point Free
      • Closure
      • Composition
      • Immutability
      • Recursion
      • List Operations
      • Transduction
      • Data Structure Operations
      • Async
    • Js Weird Parts
      • Execution Contexts And Lexical Environments
      • Types And Operators
      • Objects And Functions
      • Object Oriented Java Script And Prototypal Inheritance
      • Defining Objects
    • Mastering Chrome Dev Tools
      • Introduction
      • Editing
      • Debugging
      • Networking
      • Auditing
      • Node.js Profiling
      • Performance Monitoring
      • Image Performance
      • Memory
    • React Complete Guide
      • What Is React
      • React Basics
      • Rendering Lists And Conditionals
      • Styling React Components
      • Debugging React Apps
      • Component Deep Dive
      • Building A React App
      • Reaching Out To The Web
      • Routing
    • React Testing
      • Intro To Jest Enzyme And TDD
      • Basic Testing
      • Redux Testing
      • Redux Thunk Testing
    • Serverless Bootcamp
      • Introduction
      • Auction Service Setup
      • Auction Service CRUD Operations
      • Auction Service Processing Auctions
    • Testing Javascript
      • Fundamentals Of Testing
      • Static Analysis Testing
      • Mocking Fundamentals
      • Configuring Jest
      • Test React Components With Jest And React Testing Library
    • Typescript Developers Guide
      • Getting Started With Type Script
      • What Is A Type System
      • Type Annotations In Action
      • Annotations With Functions And Objects
      • Mastering Typed Arrays
      • Tuples In Type Script
      • The All Important Interface
      • Building Functionality With Classes
    • Web Performance With Webpack
      • Intro
      • Code Splitting
      • Module Methods Magic Comments
  • Other
    • Algo Expert
      • Defining Data Structures And Complexity Analysis
      • Memory
      • Big O Notation
      • Logarithm
      • Arrays
      • Linked Lists
      • Hash Tables
      • Stacks And Queues
      • Strings
      • Graphs
      • Trees
    • Aws Solutions Architect
      • AWS Fundamentals IAM EC 2
    • Fundamentals Math
      • Numbers And Negative Numbers
      • Factors And Multiples
      • Fractions
    • Mysql Bootcamp
      • Overview And Installation
      • Creating Databases And Tables
      • Inserting Data
      • CRUD Commands
      • The World Of String Functions
      • Refining Our Selections
      • The Magic Of Aggregate Functions
    • Random Notes
      • Understanding React Hooks
  • Python
    • Data Analysis Using Python
      • Loading Querying And Filtering Data Using The Csv Module
      • Loading Querying Joining And Filtering Data Using Pandas
      • Summarizing And Visualizing Data
    • Intro To Python
      • Course Introduction Intro To Programming And The Python Language Variables Conditionals Jupyter Notebook And IDLE
      • Intro To Lists Loops And Functions
      • More With Lists Strings Tuples Sets And Py Charm
      • Dictionaries And Files
Powered by GitBook
On this page
  • Objects and the Dot
  • Framework Aside: Faking Namespaces
  • JSON And Object Literals
  • Built-in methods for JSON
  • Functions are Objects
  • Function Statements and Function Expressions
  • Expressions and statements
  • Applied to functions
  • Conceptual Aside: By Value vs. By Reference
  • Changing and comparing values
  • Objects, Functions, and this
  • Conceptual Aside: Arrays, Collections of Anything
  • Arguments and Spread
  • Arguments variable
  • Spread operator
  • Framework Aside: Function Overloading
  • Conceptual Aside: Syntax Parsers
  • Dangerous Aside: Automatic Semicolon Insertion
  • Framework Aside: Whitespace
  • Immediately Invoked Function Expressions (IIFEs)
  • Writing IIFE without throwing error
  • Framework Aside: IIFEs and Safe Code
  • Overriding global object
  • Understanding Closures
  • Weird case of closures
  • Framework Aside: Function Factories
  • Closures and Callbacks
  • Call, Apply, and Bind
  • Function borrowing
  • Function currying
  • Functional Programming
  1. Javascript
  2. Js Weird Parts

Objects And Functions

Objects and the Dot

Think of objects as sitting in memory with a reference address. Inside objects, there can then be references to other things sitting in memory too with their own addresses, which are connected to the original object. These can be primitive values, other objects, or functions—or properties and methods!

const person = {};

person["key"] = "value";

When an object is created, the variable stores the memory address to where the object is stored. When you create a property, you use the computed member access operator or [] to create a new name/value pair. The value gets stored in that name in memory, and its memory address is given to the object.

Similarly, the member access operator does the same thing, but you can't dynamically choose the name in the object.

Note: Both member access operators are just functions that take the object and the name as arguments and then return the value stored at that name in the object.

Framework Aside: Faking Namespaces

Namespaces are containers for variables and functions. They're used to keep variables and functions with the same names separate.

JavaScript can fake namespaces by storing variables and functions inside objects!

JSON And Object Literals

In the past, people sent data across the internet using XML, which took this kind of format:

<object>
  <firstName>Mary</firstName>
  <isProgrammer>true</isProgrammer>
</object>

The problem is that XML has redundancies. Specifically, it has closing brackets that repeat the property name, which is a lot of wasted download bandwidth for large sets of data.

The solution: JSON. JSON is a subset of the object literal syntax with a few key differences.

{
  "firstName": "Mary",
  "isProgrammer": true
}

Differences include:

  • JSON's keys must be wrapped in quotes

  • JSON's keys can't store functions

Built-in methods for JSON

Technically, JSON isn't JavaScript. But because JSON is so similar to object literals, you can convert between them easily with these methods...

JSON.stringify(objectLiteral); takes an object literal and converts it to a JSON-formatted string.

JSON.parse(jsonString); takes a JSON-formatted string and converts it to an object in JavaScript.

Functions are Objects

Note: Functions in JavaScript are first-class functions. Everything you can do with other data types you can do with functions: assign them to variables, pass them as arguments into other functions, and even create them on the fly anonymously.

When we say functions are objects, that means functions have:

  • Ability to attach properties

  • Ability to attach other objects

  • Ability to attach methods

In addition, functions have special properties:

  • Name: this is where the name of the function gets stored (doesn't exist if anonymous function)

  • Code: this is where the code written inside the function gets stored (and also what gets run when you invoke the function)

Function Statements and Function Expressions

Expressions and statements

Expressions return a value. (That value doesn't necessarily have to be saved in a variable, but it can be). Examples:

var a = 3; // assignment operator returns 3
1 + 2; // plus operator returns 3

Statements just do work; they run the code and that's it. Examples:

if (true) { console.log("RUN")! }; // if statements just run;
var a = if (true) {}; // this doesn't return anything for a to store!

Applied to functions

Function statements don't return a value; they just get stored in memory:

// No value gets returned here
// It simply gets stored in memory during creation of execution context
function greet() {
  console.log("Hi");
};

Function expressions return a value, which you can store in a variable:

// creates a function object
// Variable points to memory address of function object
var anonymousGreet = function() {
  console.log("Hi");
};

Important differences with function expressions:

  • Function expressions are anonymous. They're not given a name property. Instead, function expressions have variable names that point to the anonymous function.

  • Function expressions create an object. Function statements just store the code in memory.

  • Function expressions are NOT hoisted. The execution context doesn't evaluate the right side of the equality operator, so you can't successfully invoke the function.

Conceptual Aside: By Value vs. By Reference

By value is where the value itself is given when passing the value around, creating copies along the way.

const a = 3; // value 3 gets stored in memory and a points to it
const b = a; // value 3 gets COPIED and stored in new place in memory and b points to new place

By reference is where the reference (or memory address) is given when passing the value around. No copies are created.

const a = {}; // a points to this object in memory
const b = a; // b points to the same object

Changing and comparing values

One side effect is that by value and by reference behave differently when you change the value.

let a = 3;
let b = a;
a = 4;
console.log(a, b); // logs 4 and 3; b isn't affected by re-assignment

let a = {};
b = a;
a.greeting = "Hello";
console.log(b.greeting, a.greeting); // logs "Hello" twice; adding the property to a affects b too

Objects, Functions, and this

Recall that this get defined every time an execution context is created.

When a function is created in the global object, this points to the global object:

function logThis() {
  console.log(this); // logs global object
};

When a method is created in an object, this points to the object:

const obj = {
  logThis: function() { console.log(this); } // logs obj
};

// Note: You're using an anonymous function expression to create the method!

When a function is created inside a method, this points to the global object again. Many people consider this a bug:

const obj = {
  logThis: function() {
    const logDis = function() { console.log(this); };
    logDis(); // logs global object
  }
};

// SOLUTION: pass this by reference to hold onto it
const obj = {
  logThis: function() {
    const self = this; // pass by reference!
    const logDis = function() { console.log(self); };
    logDis(); // logs obj
  }
};

Conceptual Aside: Arrays, Collections of Anything

Arrays can hold literally anything: strings, numbers, booleans, functions, objects, everything!

const arr = [
  1,
  false,
  "hello",
  {},
  function() {}
];

Arguments and Spread

Arguments variable

When a function is invoked, the JavaScript engine sets up the execution context. One special variable it sets up in this process is called the arguments variable.

greet("Dan");

function greet(firstName, lastName, language) {
  language = language || "en"; // sets default value if one isn't provided

  console.log(firstName); // logs "Dan"
  console.log(lastName); // logs undefined
  console.log(language); // logs "en"

  console.log(arguments); // logs ["Dan", undefined, "en"]
};

Note: The JavaScript engine will hoist the parameters and give them an initial value of undefined.

Note 2: The arguments variable is array-like. It has some features of an array but not all. (Many people think this is a bug.)

Spread operator

The arguments variable is being deprecated. The new way is the spread ... operator.

// ...arguments captures all the arguments in one variable
function greet(..arguments) {
  console.log(arguments);
};

Framework Aside: Function Overloading

Function overloading is the ability to create multiple functions of the same name that each get called to perform different tasks depending on context. JavaScript does not have this feature.

The JavaScript workaround is to use functional programming and leverage the fact that functions are first-class (you can pass them into other functions):

function greet(language) {
  if (language === "en") {
    console.log("Hello!");
  };

  if (language === "fr") {
    console.log("Bonjour !");
  };
};

// You're creating shorthand functions that do the parameter passing for you!
function greetEnglish() { greet("en"); };
function greetFrancais() { greet("fr"); };

The above pattern is often used by frameworks to make using the framework easier.

Conceptual Aside: Syntax Parsers

The syntax parser will literally run through your code character by character and decide what you're going to do based on a strict set of rules.

Example is the return statement:

r // syntax parser sees an r and expects return
re
ret
retu
retur
return;

The power of the syntax parser is it can make changes to the actual code you write.

Dangerous Aside: Automatic Semicolon Insertion

Syntax parsers try to be helpful by adding semicolons for you. You should always add your own semicolons because you don't want the syntax parser to do it.

Fun fact: Semicolons are not optional, but the syntax parser makes it seem optional.

Example issue:

function greet() {
  // Let's say you want to break your return statement into multiple lines...
  return
  {
    greeting: "Hello"
  };
};

console.log(greet()); // logs undefined

In the example above, the syntax parser sees a new line character after return. Seeing that, it thinks the return statement ends at that line, so it converts to return;, which ends the function!

The solution is to always start with an opening bracket on the same line. This ensures that the syntax parser knows to expect more further down.

function greet() {
  return {
    greeting: "Hello"
  };
};

Framework Aside: Whitespace

Whitespace are invisible characters that create literal space between your other characters. Includes returns, tabs, spaces.

Immediately Invoked Function Expressions (IIFEs)

An IIFE is where you invoke a function expression immediately after creating it.

function(name) {
  console.log("Hello " + name);
}();

This works because of operator precedence. The anonymous function creates a function object first. Then immediately afterwards, the code property in the function object is invoked using ().

Writing IIFE without throwing error

You can write expressions with no variables, and it won't throw an error.

3;
"Hello";
{ name: "Dan" };

The problem with function expressions is that the syntax parser will expect a function statement because it starts with the word function. As a result, an error is thrown.

// SyntaxError: function statement requires a name
function() { console.log("Hello") };

Solution: Wrap the function expression in parentheses (a group) first.

(function() { console.log("Hello") })();

// NOTE: The () invoking the function can be both inside or outside of the grouping

Framework Aside: IIFEs and Safe Code

IIFEs are used in frameworks to promote safe code (similar to namespacing).

// app.js file contents
const greeting = "Hola";

// framework.js file contents
(function() {
  const greeting = "Hello";

  // run framework code here
})();

console.log(greeting); // logs "Hola"

In the example above, the IIFE creates a new execution context where the variables created don't affect the variables in the global execution context. This helps ensure that there are no conflicts between JS files.

Pro tip: You will find many frameworks wrap their entire source code in an IIFE for the above reasons.

Overriding global object

Inside an IIFE, you can intentionally override properties in the global object by simply passing the global object as an argument into the IIFE.

(function(global) {
  global.greeting = "Hello";
})(window);

Note: The special power of an IIFE here is that overriding the global object must be intentional. You can't accidentally override.

Understanding Closures

A closure is where an execution context closes in its outer variables.

function greet(whatToSay) {
  return function(name) {
    console.log(whatToSay + " " + name);
  };
};

const sayHi = greet("Hi");
sayHi("Dan");

In the example above, greet("Hi"); creates a new execution context that contains the lexically scoped variable whatToSay. Then it gets popped off the stack because the code has successfully run.

However, sayHi("Dan");, when run, still can access whatToSay. Why?

Answer: Because sayHi was created inside greet, the JavaScript engine will make sure that it has access to the variables it's supposed to have access to. That means whatToSay is available even though greet is not even in the execution stack. We say that sayHi closed in its outer variables. This is a built-in feature of JavaScript.

Note: Variables in execution contexts don't get removed from memory when the code block finishes. This happens periodically during a phase called garbage collection.

Weird case of closures

The following code snippet will log 3 three times because i is 3 at the time of function invocation. This makes sense when you think about closure.

function buildFunctions() {

  var arr = [];

  for (var i = 0; i < 3; i++) {
    arr.push(
      function () {
        console.log(i);
      };
    );
  };

  return arr;
};

var fs = buildFunctions();

fs[0]();
fs[1]();
fs[2]();

The ES6 solution is to just use let. let block scopes i for each iteration of the for loop:

for (let i = 0; i < 3; i++) {
  // ...
};

OR the ES5 solution is to use an IIFE to create a unique execution context for each iteration:

for (var i = 0; i < 3; i++) {
  (function(j) {
    return function() {
      console.log(j);
    };
  })(i);
};

IIFEs work because each IIFE has its own j that it can reference when the function is invoked.

Framework Aside: Function Factories

Function factories are functions that create other functions and return them. Their power comes in the fact that they utilize closures.

function makeGreeting(language) {
  const greetingMap = {
    "en": "Hello",
    "fr": "Bonjour"
  };

  return function(firstName, lastName) {
    console.log(`${greetingMap[language]} ${firstName} ${lastName}`);
  };
};

const greetEnglish = makeGreeting("en");
const greetFrancais = makeGreeting("fr");

greetEnglish("Dan", "Fitz"); // logs "Hello Dan Fitz" b/c "en" is part of closure
greetFrancais("Dan", "Fitz"); // logs "Bonjour Dan Fitz" b/c "fr" is part of closure

Note: Every call of makeGreeting creates its own execution context. That's why greetingMap[language] still works when we call the functions created.

Closures and Callbacks

Functions that take callback functions make use of closures, first-class functions, and function expressions all at once!

const sayHiLater = function() {
  const greeting = "Hi!";

  // setTimeout takes a function expression as an argument!
  setTimeout(function() {
    
    console.log(greeting); // greeting is an outer variable that gets closed in!

  }, 3000);
};

sayHiLater();

Note: A callback function is a function that gets passed as an argument to another function to be run when that other function finishes.

Call, Apply, and Bind

Functions are objects, and built into them are special methods: call, apply, and bind.

bind(targetThis); binds whatever you want this to refer to when the function is invoked, returning a copy of the function with the new binding:

const newThis = function() {
  console.log(this.name);
}.bind({ name: "Dan" });

newThis(); // logs "Dan"

call(targetThis, ...arguments); sets a this and calls the function:

const logName = function(greeting, message) {
  console.log(greeting + " " + this.name + ". " + message);
};

logName.call({ name: "Dan" }, "Hello", "I love you!"); // logs "Hello Dan. I love you!"

apply(targetThis, [...arguments]); does the same thing as call but takes an array of arguments:

logName.apply({ name: "Dan" }, ["Hello", "I love you!"]);

Function borrowing

Sometimes you have 2 objects that are very similar, but one has a method that you want to use on the other. You can use one of the function methods to borrow the method and use it on the intended object.

const person = {
  name: "Dan Fitz",
  logName: function() { console.log(this.name) };
};

const person2 = {
  name: "John Wage",
};

person.logName.call(person2); // logs "John Wage"

Function currying

Function currying is the process of breaking down a function that takes multiple arguments into a series of functions that each take 1 argument. bind is powerful for this:

function multiply(a, b) {
  return a * b;
};

const multiplyByTwo = multiple.bind(this, 2); // 2 is now the permanent value for the first argument
multiplyByTwo(3); // returns 6

Note: You can also think of function currying as creating a copy of a function with some preset parameters. It's very useful in mathematical situations.

Functional Programming

??

PreviousTypes And OperatorsNextObject Oriented Java Script And Prototypal Inheritance

Last updated 3 years ago