Skip to content

Instantly share code, notes, and snippets.

@morgvanny
Created March 17, 2021 17:13
Show Gist options
  • Save morgvanny/60dd6a71e9f8639c70676ad08d22b5bb to your computer and use it in GitHub Desktop.
Save morgvanny/60dd6a71e9f8639c70676ad08d22b5bb to your computer and use it in GitHub Desktop.
// Data Types:
// Primitives:
// String
// Boolean
// Number
// BigInt
// undefined
// Symbol
// Null
// Object
// - Arrays
// Function
let a = "some string"
a += " extra"
// a is "some string extra"
let b = 10
b = b + 15
// b is 25
let c = 25
let object = {}
let another = object
another.color = "blue"
// object and another both look like {color: "blue"}
let oneMore = {};
[1,3,4,5] === [1,3,4,5]; // false
{} === {}; //false
// Variable Setup (JS engine does 3 steps):
// 1. Declaration - JavaScript knows it's a variable
// 2. Initialization - hoisted for var, not for let and const
// 3. Assignment
// 3 ways:
// var, let, const
// we write:
console.log(x);
var x = 15;
// js rewrites to:
var x;
console.log(x);
x = 15;
// therefore console.log(x) will log 'undefined' in the console rather than throw an error. if we declared with let or const
// it would throw an error if we tried to read or write to the variable before the declaration showed up
// for error specificity and possibly other purposes, js still hoists the _declaration_ of let/const variables, but doesn't
// _initialize_ them or assign them until the declaration and/or assignment appear in the code, so any usage of them before
// that point will result in an error being thrown
// const variables can't be reassigned. if they point to an object/array, that thing can be changed, but it will never point
// to a new thing. let variables can be - so the thing they're assigned to can be changed, but also they can just be assigned
// to a new thing entirely if desired
// let basically has the perfect balance of throwing errors when you'd want them (as opposed to var just acting weird instead
// of throwing an error) but has flexibility of reassignment. some people like to avoid unnecessary re-assignment so const
// ensures errors are thrown if that's attempted, forcing you to rethink the re-assignment or change declaration to let
// Function Declarations and Expressions:
const expressedFunction = function(a, b) {
console.log('this function was defined using an expression')
}
declaredFunction() //executes
expressedFunction() //executes
declaredFunction // does nothing. this line evaluates the value of the function itself (a structural data type)
expressedFunction // does nothing. this line evaluates the value of the function itself (a structural data type)
// declared functions are hoisted, meaning they can be called anywhere within their scope (or lower scopes)
// expressed functions aren't. they are either written as an argument to a function like this:
const array = [1,2,3]
array.map(function(num){
return 10 * num
})
/*
the function expresion above:
function(num){
return 10 * num
}
is being passed in as an argument to the map function. a slight benefit here (pretty negligible) is that since it's an
expression, it isn't occupying space in memory to be available to be called at any point - it's expressed as a one-off
to be used while mapping through the array, and can be garbage collected when finished, occupying no more space in memory
after .map is called. it also didn't have to be named - map is already set up to take an argument and in its own definition,
is able to be set up to call that function based on whatever that argument is defined as.
*/
// my personal preference - never declare functions - only write them as expressions. that way I never find myself executing
// a method before its definition has appeared - which is allowed for declared functions due to hoisting, but can make
// the code a bit confusing and have more misdirection when trying to read what's going on (but does make writing it more
// flexible). I'd rather an 'unnecessary' error to be thrown if I try to do that, forcing me to organize my code a bit better
// but it's perfectly valid to use declarations
//Difference between what a function does and what it returns:
let d = 15
const adder(a, b){
d = 25 // re-assigns d to 25 in higher scope (something this function does)
console.log('hi there') // logs message to console (another thing this function does)
return a + b // adds a and b (last thing the function _does_) and then _returns_ the sum of a and b
}
adder(4, 5) // returns 9 but also does the other stuff
const worthlessAdder(a, b){
d = 25 // re-assigns d to 25 in higher scope (something this function does)
console.log('hi there') // logs message to console (another thing this function does)
a + b // adds a and b (last thing the function _does_)
}
worthlessAdder(4,5) // does literally all the same work as the other, but doesn't bother returning an answer, just undefined
// functions always return undefined unless return is explicitly written. returns can exist within conditionals
// as soon as one is hit, the function execution is complete and it will stop doing anything that might have happened
// after that
// one exception to needing an explicit return is one-line arrow functions
const fnReturnsTen = () => 10
// that anonymous function () => 10 is assigned to the fnReturnsTen variable. when called, fnReturnsTen actually returns 10
// if {} comes after the => (which is required if the function is more than one line) that signifies a code block, which means
// there's no implicit return, and you need to write one.
// if it's a one-liner you can get away with not using {} and just whatever that code would evaluate to would be returned
// another example:
const fnReturnsProduct = (a,b) => a * b // fnReturnsProduct(3,4) returns 12
// Ruby Methods vs JavaScript Functions:
// def some_method
// 10
// end
// def other_method(arg)
// arg + 5
// end
// other_method(some_method) is literally the same as other_method(10)
// other_method will not execute until some_method has been executed and returns something, which that thing is the argument
// being passed in to other_method which executes when that's done being evaluated
const arithmaticDoer = (a,b,fn) => {
return fn(a,b)
}
const multiplier = (a, b) => {
return a * b
}
arithmaticDoer(3,3, multiplier) // returns 9
arithmaticDoer(2, 5, adder) // returns 7
// arithmaticDoer does not wait for multiplier or adder to be called/evaluated before executing. instead, it takes the
// functions themselves as arguments, and _it_ is responsible for executing them if it wants to (within its own definition
// it always calls fn(a,b) which refers to whatever function was passed in
// this is more flexible. maybe arithmaticDoer could do things to a and b before calling the function. in that case, you'd
// have to wait to call the function until during arithmaticDoer execution, rather than before
// aside:
multiplier() // returns NaN
// in js you can leave out arguments and it will just make those variables undefined. you can also pass extra args in:
multiplier(3,3,4,5,10) // returns 9
// extra args are just ignored
// CONSOLE.LOG!!!
// just a reminder to get used to using that a lot to check your assumptions and debug. it's super common to have variables
// end up being something you don't expect due to some mistake that doesn't throw an error, but instead just behaves strangely
// logging values helps determine when that happened and why
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment