JS Algorithms And Data Structures Certification

Notes from following freeCodeCamp's JS algorithms and data structures cert.

Basic JavaScript

  • Check out the assortment of assignment operators. I typically only use += and never think of using the rest!

  • Characters in string are immutable. The strings themselves are not. So you can change the value of a whole string (s = 'new value'), you can read single characters with bracket notation (let t = s[2]), but you cannot change a single character in an existing string (s[2] = 'a' // not!).

  • Become more fluent with array methods: push, pop, shift, unshift, splice, slice, concat, forEach, indexOf, lastIndexOf, includes, find, findIndex, filter, map, sort, reverse, split, join, reduce, reduceRight, isArray.

  • Assigning a value to an undeclared variable implicitly creates it as a global variable (it becomes a property of the global object) when the assignment is executed. The differences between declared and undeclared variables are:

    1. Declared variables are constrained in the execution context in which they are declared. Undeclared variables are always global.

    2. Declared variables are created before any code is executed. Undeclared variables do not exist until the code assigning to them is executed.

    3. Declared variables are a non-configurable property of their execution context (function or global). Undeclared variables are configurable (e.g. can be deleted).

  • Study scopes.

  • Understand coercion and different behavior between == vs === and != !==.

  • Review switch syntax and patterns.

ES6

  • It seems that 'use strict'; at the top of your files or the start of functions is recommended. It's rather annoying to have to write that every time, don't you think? Javascript.info has a good succinct article on how to use strict mode.

    I've also found some recommendations warning that if your code is processed by some build system (minification, concatenation...), you might have unexpected results when mixing strict and sloppy scripts. One solution is to 'use strict'; at the start of functions. Another problem to consider is that if your code is executed in older browsers, they might not support strict mode and you might get unexpected results as well. Preventing problems in this scenario would require careful testing.

  • In JavaScript, const does not mean constant, but one-time assignment. But, the part that's constant is the reference to an object stored within the constant variable, not the object itself.

    javascript
    const settings = {
    baseUrl: 'https://example.com'
    };
    settings = {}; // fail!
    settings.baseUrl = 'https://evil.example.com'; // win!

    Declaring a variable to be constant doesn't make the objects it references immutable. Object properties can change or be deleted altogether. The same goes for arrays assigned to a constant variable; Elements can be added, removed, reordered, or modified.

    To make an object truly immutable, you can pass it to the Object.freeze function to prevent any changes to its properties. Be aware that freeze is shallow, so you'll have to recursively call it for nested objects if you want the entire object tree to be frozen. If you need immutable data structures, it might be safer and more convenient to use a library such as Facebook's Immutable.js which is specifically made for this purpose.

  • An arrow function expression is a syntactically compact alternative to a regular function expression, although without its own bindings to the this, arguments, super, or new.target keywords.

    Arrow function expressions are ill suited as methods, and they cannot be used as constructors. Arrow functions are always anonymous. Two factors influenced the introduction of arrow functions: shorter functions and non-binding of this. An arrow function does not have its own this; the this value of the enclosing execution context is used.

  • Functions that operate on other functions, either by taking them as arguments or by returning them, are called higher-order functions. Eloquent JavaScript has a great article on higher-order functions.

  • I always forget that I can declare function parameters with default values. Default function parameters allow named parameters to be initialized with default values if no value or undefined is passed:

    javascript
    function multiply(a, b = 1) {
    return a * b;
    }
  • I use destructuring assignment regularly, but I rarely reach out for new names and default values:

    javascript
    let o = { p: 42, q: true };
    let { p, q } = o; // basic
    let { p: foo, q: bar } = o; // new names
    let { q = false, r = 'hi' } = o; // default values
    let { p: foo = 1, q, r: bar = 'hi' } = o; // combined
  • I haven't written much code using classes in JavaScript. JavaScript classes, introduced in ECMAScript 2015, are primarily syntactical sugar over JavaScript's existing prototype-based inheritance. The class syntax does not introduce a new object-oriented inheritance model to JavaScript. JavaScript.info article on classes is quite good.

    In summary, the basic class syntax looks like this:

    javascript
    class MyClass {
    prop = value;
    constructor(...) {
    // ...
    }
    method(...) {}
    get something(...) {}
    set something(...) {}
    [Symbol.iterator]() {}
    // ...
    }

    MyClass is technically a function. Methods are written to MyClass.prototype.

Regular Expressions

  • Use regular expressions with many methods. Popular ones are:

    • str.match(regExp)
    • regExp.test(str)
    • str.replace(regExp, newStr|fun)
  • Match literals like this /hello/

  • Provide alternatives like this /yes|no|maybe/

  • Flags go at the end of the regular expression like this /regex/flags. The two most popular flags are: i for case insensitive search and g for global search.

  • . matches any character except newline, but can be made to include newline with the s flag.

  • Use square brackets to define character sets: /[abc]/ would be equivalent to /a|b|c/, if I'm not mistaken. Use - to define ranges. Use [^...] to define a character set by specifying its complement. I.e. [^abc] matches everything except a, b or c.

  • For frequently used character sets, shorthand character classes exist. The most popular:

    • \w equivalent to [A-Za-z0-9_] and \W its complement
    • \d equivalent to [0-9] and \D its complement
    • \s equivalent to [ \r\t\f\n\v] and \S its complement.
  • Quantifiers establish whether a given character or group can repeat itself:

    • ? 0 or 1 times
    • * 0 or more times
    • + 1 or more times
    • {n} exactly n times
    • {min,max} a number of times in between min and max (inclusive). Either min or max can be omitted.
  • ^ at the beginning of the regular expression denotes beginning of string. $ at the end denotes end of string.

  • Lookaheads establish an extra condition without becoming part of the match. Positive lookahead x(?=y) matches x when followed by y. Negative lookahead x(?!y) matches x when not followed by y.

  • Note that ^ and ? mean different things depending on where they're used.

  • By default, regular expressions behave in a greedy manner. For example, /t[a-z]*i/ applied to "titanic" will produce the biggest match, "titani". By adding a question mark like so /t[a-z]*?i/, the match behaves in a lazy manner and the smallest match is returned "ti".

  • Create capture groups by using parenthesis (...), which can be referenced subsequently inside the regular expression by number \1, \2, etc. They can also be referenced in replace like so $1, $2, etc.

Debugging

  • Three types of bugs:
    • syntax errors that prevent a program from running,
    • runtime errors when code fails to execute or has unexpected behavior, and
    • semantic (or logical) errors when code doesn't do what it's meant to.

Object Oriented Programming

  • An object is just a data structure that holds property/value pairs. The values can be of any arbitrary type: strings, numbers, objects... When a property has a value of type Function, we call it a method.

  • Constructors are functions that create new objects. They follow a few conventions:

    • They are defined with a capitalized name to distinguish them from other functions that are not constructors.

    • They use the keyword this to set properties of the object they will create. Inside the constructor, this refers to the new object it will create.

    • They define properties and behaviors instead of returning a value as other functions might.

  • You can use obj instanceof Obj to test if a specific obj object is an instance of the Obj constructor.

  • An object has two types of properties: own properties and prototype properties. Own properties are defined directly on the object instance itself. And prototype properties are defined on the prototype. .hasOwnProperties(key) returns false for prototype properties, but the in operator works with both. But it's more complicated, so check Enumerability and ownership of properties

    Enumerable properties are those properties whose internal enumerable flag is set to true, which is the default for properties created via simple assignment or via a property initializer (properties defined via Object.defineProperty and such default enumerable to false). Enumerable properties show up in for...in loops unless the property's key is a Symbol. Ownership of properties is determined by whether the property belongs to the object directly and not to its prototype chain. Properties of an object can also be retrieved in total.

  • Manually setting the prototype of a new object will erase (overwrite, I guess) the constructor property. One solution is to include the constructor in the object literal we're using to overwrite prototype.

    javascript
    function Dog(name) {
    this.name = name;
    }
    // Modify the code below this line
    Dog.prototype = {
    constructor: Dog,
    numLegs: 2,
    eat: function() {
    console.log('nom nom nom');
    },
    describe: function() {
    console.log('My name is ' + this.name);
    }
    };

Functional programming

  • Functional programming is about:

    • Isolated functions - there is no dependence on the state of the program, which includes global variables that are subject to change

    • Pure functions - the same input always gives the same output

    • Functions with limited side effects - any changes, or mutations, to the state of the program outside the function are carefully controlled

  • Functions passed as arguments are referred to as callbacks.

  • Functions that can be assigned to a variable, passed into another function, or returned from another function just like any other normal value, are called first class functions. All functions are first class in JavaScript.

  • Functions that take functions as arguments or return functions are called higher order functions. The functions that are passed as arguments or returned as results are called lambdas.

  • In functional programming, changing or altering things is called mutation, and the outcome is called a side effect. A function, ideally, should be a pure function, meaning that it does not cause any side effects.

  • Another principle of functional programming is to always declare your dependencies explicitly. This means if a function depends on a variable or object being present, then pass that variable or object directly into the function as an argument.

  • reduce caveat: the first time the callback is called, accumulator and currentValue can be one of two values. If initialValue is provided in the call to reduce(), then accumulator will be equal to initialValue, and currentValue will be equal to the first value in the array. If no initialValue is provided, then accumulator will be equal to the first value in the array, and currentValue will be equal to the second.

  • Check out the every and some methods!