tags : Programming Languages, Typescript

Data types and values

Values

Primitive(7)

  • Immutable
  • undefined, number, string, boolean, symbol, bigint are not objects, they’re primitives.
  • primitive and variable assigned a primitive value are different
  • No methods, no properties: But JS has wrapper around primitives. Eg. string primitive has the ephemeral String object wrapper which gives it nice methods like includes. Sometimes called the “auto-boxing behavior”
  • All primitive types, except null and undefined, have their corresponding object wrapper.

Non-primitive/objects

  • Mutable
  • Definition: objects can be seen as a collection of properties/methods
  • object can have properties and methods, none, one or both.
  • Most things except primitives are objects. Even functions.

More on non-primitive/objects

FAQ on Object & object

  • Using Object as a map

    • I used to use Object as map/dictionary for storing k-v data.
    • Not good, because it has all the extra property things that we don’t care about. It’s like taking an airplane to go 2kms. Use Map instead.
  • What about [object Object]?

    • String representation when toString() is used.
    • Object.prototype.toString() returns "[object Type]"
    • Type is set by Symbol.toStringTag
    • When Symbol.toStringTag is unset, it’ll just go [object Object]

object vs Object

  • object
    • There’s nothing tangible called object in JS. It’s a concept. It’s anything that has properties, it’s anything that’s not a primitive.
    • Issues w typeof
      • One source of confusion is the typeof operator. For anything other than a pre-defined list it’ll return “object”. This just signals that it’s some object, something’s that’s not a primitive. (typeof is like a limited best effort thing)
      • Eg. typeof new Date() and typeof null both return ‘object’. So for differentiating between subtypes, maybe use instanceof
      • So typeof is good if you just want to work on primitive values.
  • Object
    • JS has many built in objects, Object (w the capital O) is one of them.
    • Other common objects are Function, Array, Date, RegExp, Error etc.
    • Object behaves the same as {} (Object literal)
      // object literals are cool
      const obj = {
        // __proto__
        __proto__: theProtoObj,
        // Shorthand for 'handler: handler'
        handler,
        // Methods
        toString() {
          // Super calls
          return "d " + super.toString();
        },
        // Computed (dynamic) property names
        ["prop_" + (() => 42)()]: 42,
      };
    • Every object in JS is inherited of Object.prototype

Properties

  • property is an association between a name (or key) and a value. When the value of a property is a function, we call it a method.
  • Can be “assigned”, or can be set via attributes using Object.defineProperty
  • There are hidden/internal properties, usually represented via [[. eg. [[Prototype]].
  • JS objects have properties. They’re of 2 types.
    • Data property: value, writable, enumerable, configurable
    • Accessor property: get, set, enumerable, configurable
  • Prototype

    • prototype of an object is conceptually a hidden property
    • prototype of points to another object or to null
    • Usually represented using [[Prototype]], sometimes obj.__proto__ but that’s not official.
    • WATCHOUT: Functions (constructors) have a .prototype property, that’s different. It specifies what the [[Prototype]] should be for newly created objects using the constructor.

Other stuff

Functions

this

  • It has 5 perspective, check javascript garden ref. for solid info
  • arrow functions are cool, when using them this will point parent(past hack: bind, self etc.), it does not have its own this. So ez.

apply/call/bind

  • These help us explicitly set parameters using this
  • The first parameter of these functions point to the thisArg (what should this point to)
  • call
    • Lets us call some function by explicitly setting this
    • Don’t need it usually
  • apply
    • like call but lets us pass array of arguments
    • Earlier we needed to do things like Math.max.apply(null, nums), now we don’t need it cuz spread operator
    • Don’t need it usually
  • bind
    • Lets us build new functions out of parameters
    • Related to the idea of currying

Closures

  • A closure is formed by
    • Returning from a function from the execution context of a function call and referencing that inner function to a property of another object.
    • Directly assigning a reference to such a function object to, for example, a global variable, a property of a globally accessible object or an object passed by reference as an argument to the outer function call.

Promises

  • Check the execution order here
  • Not to mention, these are objects
  • catch(failureCallback) is short for then(null, failureCallback)
  • If your error handling code is the same for all steps, you can attach catch it to the end of the chain
  • The handlers we pass to .then and .catch NEED to return. Otherwise we end up creating a race condition.
  • When we do .then(()=> doSomething()) we mean .then((IGNORE_RESULT_HERE)=> doSomething())
  • Good habit to always have a .catch
  • async/await helps avoid most of the catches here.
  • Promise.all runs things concurrently(doesn’t check order), We can use reduce to run things sequentially. But make sure you want to run things sequentially. In general if simply chaining with .then, then things will be invoked in order.

Nested or flat?

const listOfIngredients = [];
 
doSomething()
  .then((url) =>
    fetch(url)
      .then((res) => res.json())
      .then((data) => {
        listOfIngredients.push(data);
      }),
  )
  .then(() => {
    console.log(listOfIngredients);
  });
 
// OR
 
doSomething()
  .then((url) => fetch(url))
  .then((res) => res.json())
  .then((data) => {
    listOfIngredients.push(data);
  })
  .then(() => {
    console.log(listOfIngredients);
  });
  • Simple promise chains are best kept flat without nesting
  • nested chains can be useful if you want to scope catch / error silencing, eg. do not make failure of some optional chain fail the whole thing.

Mix callbacks and promises?

  • Not a good idea to mix callbacks and promises
  • Better to just convert the callback thing into a promise.
    const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

await

Typed Arrays

const buffer = new ArrayBuffer(16); // just the buffer
const int32View = new Int32Array(buffer); // we add a view to the buffer
const int16View = new Int16Array(buffer); // we add another view to the same buffer!
 
// data objects containing multiple data types
const buffer = new ArrayBuffer(24);
const idView = new Uint32Array(buffer, 0, 1);
const usernameView = new Uint8Array(buffer, 4, 16);
const amountDueView = new Float32Array(buffer, 20, 1);
 
  • These are very different things technically from Array
  • Implementation: ArrayBuffer + view/context
    • ArrayBuffer : Just chunks of data, no methods nothing. fixed-length binary data buffer.
    • view/context/Dataview: data type, starting offset, and number of elements etc.
  • It’s not accessible directly, instead you use the different views, examples some predefined views.
  • If you need custom view, might look at Dataview, it gives you low level access and can change things like change the byte order.

Random notes

  • You can also use the unary plus + as a shorthand for Number()
  • ?? (Nullish coalasing is cool)
  • JS now has ?. like Ruby
  • If you pass any other object to the index signature the JavaScript runtime actually calls .toString on it before getting the result.

Versions

  • ES6/ES2015
  • ES7/ES2016: array.include, etc
  • ES2017
  • ES2018
  • ES2019
  • ES2020
  • ES2021
  • ES2022