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 ephemeralString
object wrapper which gives it nice methods likeincludes
. Sometimes called the “auto-boxing behavior” - All primitive types, except
null
andundefined
, have their correspondingobject
wrapper.
Non-primitive/objects
- Mutable
- Definition:
objects
can be seen as a collection ofproperties/methods
object
can haveproperties
andmethods
, 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.
- I used to use
-
What about
[object Object]
?- String representation when
toString()
is used. Object.prototype.toString()
returns"[object Type]"
Type
is set bySymbol.toStringTag
- When
Symbol.toStringTag
is unset, it’ll just go[object Object]
- String representation when
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()
andtypeof null
both return ‘object’. So for differentiating between subtypes, maybe useinstanceof
- So
typeof
is good if you just want to work onprimitive
values.
- One source of confusion is the
- There’s nothing tangible called
Object
- JS has many built in
objects
,Object
(w the capitalO
) 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 ofObject.prototype
- JS has many built in
Properties
property
is an association between a name (or key) and a value. When the value of aproperty
is afunction
, we call it amethod
.- Can be “assigned”, or can be set via
attributes
usingObject.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 anobject
is conceptually a hiddenproperty
prototype
of points to anotherobject
or tonull
- Usually represented using
[[Prototype]]
, sometimesobj.__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 ownthis
. So ez.
apply/call/bind
- These help us explicitly set
parameters
usingthis
- The first
parameter
of these functions point to thethisArg
(what shouldthis
point to) call
- Lets us call some function by explicitly setting
this
- Don’t need it usually
- Lets us call some function by explicitly setting
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
- like
bind
- Lets us build new functions out of
parameters
- Related to the idea of currying
- Lets us build new functions out of
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 forthen(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 toreturn
. 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 usereduce
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
- for loop / for-loop and wait
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 predefinedviews
. - 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 forNumber()
??
(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