Common Regex:
For checking for a format such as : (856) 999-7777 use regex: /^\(\d{3}\)\s\d{3}-\d{4}$/
Ternary
|
1 2 3 4 5 6 7 8 |
(condition) ? 'value if true' : 'value if false'; // Can also have multiple ?'s, below has 3 conditions total if the // first 2 are false. let result = (condition) ? 'value if true' : (2ndconditionIfFalse) ? 'value if 2nd con is true' : (3rdConditionIfFalse) ? 'returned value if 3rd is true' : 'returned value if 3rd is false'; |
Boolean conversions
A number 0, an empty string "", null, undefined, and NaN all become false. Because of that they are called “falsy” values.
Break & Continue
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
// break will "break" out of the loop entirely for (let i = 0; i < 3; i++) { if (i == 2) { break; } alert(i); // alert will never show 2 because it will break the loop } // continue will allow the following to execute in a loop for (let i = 0; i < 3; i++) { if (i == 2) { continue; } alert(i); // alert will only show 2 because the "continue" keyword } |
For loop:
|
1 2 3 4 5 |
for (let i = 0; i < 5; ++i) alert( i ); // Execute once i = 0 before everything (begin). // Check the condition i < 5 // If true – note it willonly execute the loop body alert(i), and then i++ |
Breaking out of a nest for loop ( named loops ):
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
outer: for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { let input = prompt(`show values: (${i},${j})`, ''); // if an empty string or canceled, then break out of both loops // other wise it will keep prompting with new values if (!input) break outer; // (*) // do something with the input ( or i / j ) if the loop isn't broken out of } } alert('Done!'); |
Curried Functions
The process of breaking up a multiple parameter function in to multiple single(or more) parameters.
Useful for : If you don’t provide all parameters for a function, it returns a function whose input are the remaining parameters and whose output is the result of the original function.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// normal function that takes in multiple parameters at once function tripleAdd1(num1, num2, num3) { return num1 + num2 + num3; } // curried version of the function above that breaks down the 3 parameters // in to a set of single parameter functions function tripleAdd(num1) { return function(num2) { return function(num3) { return num1 + num2 + num3; }; }; } |
Useful ways of using Currying:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
function getTravelTime(distance) { return function(speed) { return distance / speed; }; } // getTravelTime usually takes distance and speed but to use for specific // cases where the distance doesn't change.. you can use below which will end up // return a function customized to using the same distance since it doesn // exist const travelTimeBosNyc = getTravelTime(400); // above creates a function with a preset distance of 400 // below travelTimeBoysNyc supplies the speed variable to finally calculate // completely. console.log(travelTimeBosNyc(100)); |
Closures
Closures provide two unique purposes. One is memory management and the other is encapsulation. Currying is an example usage of Closures.
Using closures creates a lexical scope that will store variables within it and are available for subsequent functions that may be returned within a function.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
//Memory Management(container) function MultiplyBy(num1){ // function within a function creates the closure. num1 is available // to the returned function return function(num2){ return num1*num2; } } const MultiplyByFive=MultiplyBy(5); // sets num1=5 console.log(MultiplyByFive(2)); // returns 10 // MultiplyBy is called with 5 as the param and and returns a new // function stored in MultiplyByFive that will keep the num1=5 for the // lifetime of MultiplyByFive // all values declared within the closure functions as well as the params // are available due to their lexical scope |
For Encapsulation the same idea exists except that a function that is declared within another function but not directly returned (instead as maybe a property of a returned object instead) will still benefit from being able to access the internal values of the nesting closure function
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 |
function MakeCounter(){ let count=0; const increaseCount=()=>{count++} // will increase count stored in lexical scope(closure) const displayCount=()=>{console.log(count)} //instead of returning functions, we encapsulate //in a object what we want available to the user return { increaseCount, displayCount } } let newCounter=MakeCounter(); newCounter.displayCount(); // shows as 0 since count is initialized at 0 /* the provided function in the object will increase count by 1. In this case 3 times */ newCounter.increaseCount(); newCounter.increaseCount(); newCounter.increaseCount(); newCounter.displayCount(); // shows 3 as the count that's in lexical scope |
Closure to count how many times a function to ran
The function initializes a counter and then returns an anonymous function which increments the counter. To be used, a variable must be made that is equal to the containing function and is invoked. Then, the variable created will be invoked in order to increase the count.
Example below:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
function myFunc() { let count = 0; return function() { count++; return count; }; } console.log(myFunc()); const instanceOne = myFunc(); const instanceTwo = myFunc(); console.log('instanceOne: ', instanceOne()); // returns 1 console.log('instanceOne: ', instanceOne()); // returns 2 console.log('instanceOne: ', instanceOne()); // returns 3 console.log('instanceTwo: ', instanceTwo()); // returns 1 console.log('instanceTwo: ', instanceTwo()); // returns 2 console.log('instanceOne: ', instanceOne()); // returns 4 |
Hoisting
Variable that are defined are brought to the top of the file ( or function it resides in i.e. IIFE ) but remain undefined until the line where the variable is set.
For example.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
var temp; // the existence of the variable temp is brought to the top // but remains undefined until the actual line below // ( originally var temp="Jason"; ) temp="Jason"; // This is truth for function expressions as well. var tempFunction=function(){ // inside of function expression. } |
function declarations are also hoisted but are set at the time that the interrupter runs. function declarations can be safer for this reason.
When a variable or function is created within another function or IIFE, it is hoisted only to the top of the parent function (function scope) – not the global scope. This only applies when using var as it is function scoped.
const and let are aware of global/function scope but unlike var, const and let are aware of block scope (function,if,for,while loop). Hoisting with const and let only happens to the top of the block it was declared in.
unlike var, const and let do not have any value when hoisted until the actual declaration is reached and will throw an error if trying to be accessed before it’s declaration is reached. var is automatically undefined until it’s declaration is reached and will not throw an error if is tried to be accessed before it is defined/declared.
Strict mode
Enabled by placing ‘use strict’; at the top of a js file.
Strict mode will enforce a few things. One is that a variable must use either var,let or const or it will be considered undefined.
|
1 2 3 4 5 6 7 8 9 |
// in strict mode below is not accept and will result in undefined code="the code"; console.log(code); // below will work however var code="the code"; console.log(code); |
In strict mode, all function parameters must have an unique name. Otherwise, an error will be thrown.
Without strict mode, JavaScript will interpret the last use of the parameters name as the prevailing value.
|
1 2 3 4 5 6 |
function test(a,a,b){ console.log(a,a,b); } test(1,2,3); // this will result in 2 2 3 since 2 is the last // value passed in for the "a" parameter |
Strict mode also prevents the ability to delete properties on objects that we shouldn’t be able to delete such as:
|
1 |
delete Object.prototype; |
this and controlling it
this is the object that the function is a property of
Four ways to control this
- function constructors and the use of “new”
- implicit binding (most common)
- explicit binding ( i.e. use of bind(), call() and apply() )
- arrow function to maintain lexical scope of this
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
//1. Use of new function Person(age, name) { this.age = age; // this in this case is the function constructor this.name = name; } let newPerson = new Person(10, 'jason'); // new operator will make the use of this // inside the function constructor refer to //it's self instead of the global scope(window). //2. implicit binding const person = { name: 'jason', age: 10, sayHello: function() { console.log(this.name + ' is ' + this.age + ' years old.'); } } //3. explicit binding // the use of bind for instance const person2 = { name: 'jason', age: 10, sayHello: function() { console.log(this.name + ' is ' + this.age + ' years old.'); }.bind(window) // instead of this refering to the person2 object // it refers to the window for "this" instead. } //4. arrow functions, arrow func will maintain the lexical scoping //normally if a function is declared in a object or another function.. this refers // to the inner function and not the surrounding object or function. if // you use arrow functions.. the inner function will maintain the outer object/function //as this... hence , keeping it's lexical scope const person3 = { name: 'jason', age: 10, sayHello: function() { console.log(this.name + ' is ' + this.age + ' years old.'); let innerFunction = () => { console.log('hello' + this.name) // because an arrow func was used.. //this still refers to the outer function's this which is the object person3. } } } |
Misc Notes
|
1 2 3 4 5 6 7 8 9 10 11 |
// inside of a IIFE (function(){ var x=200; y=200; }) console.log(y); // this will work as y is global since no var is included console.log(x); // this will show as undefined since outside of IIFE and // the variable used var so it is not in global scope. It is in function // scope only. |
Objects i.e. {} can only have properties as string types.
|
1 2 3 4 5 6 7 |
var obj1={ name:"Jason", "last name":"R", 1:"Middle Name" }; // name and "last name" are valid because they are a string // 1 as a property name is valid because it is turned in to a string |
If a property of an object is given another object.. Javascript will turn the object property in to a string of “[object object]”
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const a = {}; const b = { name: 'b' }; const c = { name: 'c' }; a[b] = 200; // a['[object Object]'] = 200 a[c] = 400; // a['[object Object]'] = 400 console.log(a[b]); // would show 400 since passing an object to // another objects property will result in the property being set in to a string // of '[object Object]' // console.log(a['[object Object]']); |
call() and apply() methods
Both are available for any function that is created. call() is another way to call a function and to give it different variables. You can also change the “this” context.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
// getCarDescription is defined in car1 but will be used // by call/apply to provide different a different brand variable // via providing a different "this" context. const car1 = { brand: 'Porsche', getCarDescription: function(cost, year, color) { console.log(`This car is a ${this.brand}. The price is $${cost}. The year is ${year}. The color is ${color}.\n`); } }; const car2 = { brand: 'Lamborghini' }; // function called via normal method where this is car1 // so brand will be Porche car1.getCarDescription(80000, 2010, 'blue'); // function called via call() where car2's brand is used // because 'this' is changed to car2. // then the rest of the functions parameters are provided. car1.getCarDescription.call(car2, 200000, 2013, 'yellow'); |
apply() is very similar except that it uses an array [] to input the remaining parameters.
For example:
|
1 2 3 4 5 |
const car3 = { brand: 'Ford' }; car1.getCarDescription.apply(car3, [35000, 2012, 'black']); |
Copy by value vs reference
If a variable has a primitive type ( number, string, boolean ) and is copied by another variable.. it is copied by value. So if the original variable’s value is changed, the new variable that was made when coping the original will not be changed.
|
1 2 3 4 |
var var1=1; // can be any primitive type, string, Boolean etc var var2=var1; // var2 = 1 at this point var1=3; console.log(var2) // will out put 1 still since it is copied by value. |
If a non-primitive type is copied – it is by reference. So if a variable is set to an array and another variable is set to that variable.. both will reference that array and if either variable pushes/pops a value out of the array.. both will reflect that same array.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var arr1=[1,2,3,4]; var arr2=arr1; arr1.push(3,5); console.log(arr2) // will show 1,2,3,4,3,5 since by reference. // if arr1 is set to a new array completely, then arr2 will still // point to the old array and if arr1 is altered - arr2 will not reflect it arr1=[4,5,6]; console.log(arr2) // will still show old array. 1,2,3,4,3,5 because // it still references the old array in memory console.log(arr1); // will show new array 4,5,6 |
One way to copy an array variable to another variable by value is to do the following:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
var arr1=[1,2,3,4]; //both methods below will create arr2 and arr3 with the same //array values as arr1 but by value only var arr2=arr1.slice(); var arr3=arr1.concat([]); arr1.push(6); console.log(arr1); // shows 1,2,3,4,6 console.log(arr2); // shows 1,2,3,4 console.log(arr3); // shows 1,2,3,4 // could use for loop on arr1 to push in to arr2 or arr3 // that unnecessary extra code |
Comparing two different identical objects (or arrays) will never result in true. One way to check however is to JSON.stringify both and than compare.
|
1 2 3 4 5 6 7 8 9 10 11 12 |
let obj1={ name:"Jason" }; let obj2={ name:"Jason" } console.log(obj1==obj2) // will always result in false since // each object is passed by reference so the different objects // point to different addresses in memory. // however, can JSON stringify to check if the same. console.log(JSON.stringify(obj1) == JSON.stringify(obj2)) // results in true |
Array Constructor
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
var arr1 = []; var arr2 = new Array(50); var arr3 = new Array(1, 2, "three", 4, "five"); var arr4 = new Array([1, 2, 3, 4, 5]); // arr1 results in an empty array - [] // arr2 results in an array with 50 empty items (length:50) // when passing a single number parameter in to Array(), you // get an array with that number's amount of empty items // arr3 will create an array with the enclosed parameters as // individual members of the array. i.e. [1,2,"three",4,"five"] // arr4 will return an array with one item in it that is a an // array so would look like // [0:[1, 2, 3, 4, 5]] |
JSON Notes
Double quotes have to be used , ” “, not single quotes.
All property names ( and on nested object properties ) are strings and so must be wrapped in double quotes. undefined and functions can not be used in JSON
|
1 2 3 4 5 6 7 8 9 10 11 |
//valid: { "somestring": "jason", "somenumber": 12, "mynull": null, "myarray": [1, 2, 3, 4], "myobject": { "name": "jason", "age": 2 } } |
Event Loop
The event loop is a event queue where callbacks are placed to be processed after the main thread of execution is done.
For Example:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
function someFunc(){ console.log(1); setTimeout(function(){console.log(2);},1000); setTimeout(function(){console.log(3);},0); console.log(4); } someFunc(); // result will be 1,4,3,2 // 1 and 4 are logged out immediately. // 2 and 3 are in setTimeout functions and so is placed in // the event loop which is processed after the main // thread is completed. Since 3 has a time out of 0 milliseconds // it is logged out before 2. But both 2 and 3 console logs // are moved to the end of the execution because they are placed // in the event loop. Any call back functions get placed in to the // eventloop i.e. setTimeout setInterval etc |
3 Ways to Create an Object in Javascript
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 |
// 1. Object Literal (preferred) const obj1={ name:"Jason", age:10, getInfo:function(){ console.log(this.name + " is of age: "+this.age); } } // 2. new Object syntax const obj2=new Object(); obj2.name="Jason"; obj2.age=10; obj2.getInfo=function(){ console.log(this.name + " is of age: "+this.age } // 3. constructor function function Person(name,age){ this.name=name; this.age=age; } Person.prototype.getInfo=function(){ console.log(this.name + " is of age: "+this.age }; const Jason=new Person("Jason",10); Jason.getInfo(); |
indexOf Method (String and Array)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
1. console.log([10, 20, 30, 40, 50].indexOf(30)); 2. console.log([{ name: 'Pam' }, { name: 'Kent' }].indexOf({ name: 'Kent' })); 3. console.log('hello world'.indexOf('o')); 4. console.log([[1], [2], [3], [4]].indexOf([2])); // 2 and 4 will return -1 (not found) because of objects and arrays // are passed by reference and are two separate places in memory despite // being the same values. // 1 will result in 2 because the array version of indexOf is 0 based // and so the indexes of arrays start at 1 // 3 will result in 4 as it is the string very of indexOf which // means the indexes start at 1. Also because it is the first // instance of 'o' in the string. |
Properly add & remove eventListeners
In order to remove an eventListener that was assigned, the handling function must be a named function variable and can not be just a anonymous function.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
const handleEvent=(e)=>{ // do whatever in the event return e.pageX; // returns x coordinate for this example } document.addEventListener('mousemove',handleEvent); // will add it // the above event listener can be removed by doing below document.removeEventListener('mousemove',handleEvent); // will work document.removeEventListener('mousemove',function(e){ return e.pageX; // this would not work, }); |
Copy objects and exclude selected properties
|
1 2 3 4 5 6 7 8 9 10 11 |
// Original CPU const CPU = { ram: '32gb', ssd: '64gb', micro: 'i7' }; // new CPU copy without the 64GB ssd const { ssd, ...newCPU } = CPU; console.log(newCPU); // results: { ram: '16gb', micro: 'i7' }; |
Object Destructuring and aliasing
Destructuring is a way to extract an objects property upon assignment.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
const object1={x:10}; // can destructur and assign x to the above objects property x const {x}=object1; console.log(x) // 10 // Aliasing allows us to rename the destructured property upon assignment const {x:newNameOfX}=object1; console.log(newNameOfX) // 10; // can also assign a default value to the destructured value/new name // in case the object that is being destructured does not contain // the named property. const {y:newNameOfY=2}=object1; console.log(newNameOfY); // 2 since no "y" is in object1, it uses the default |
String Functions
indexOf(wordToLookFor) – will find the starting position of the wordToLookFor and return the starting index. If nothing is found it will return -1
localeCompare() − Returns a number indicating whether a reference string comes before or after or is the same as the given string in sort order
|
1 2 3 4 5 6 7 8 |
// The letter "a" is before "c" yielding a negative value 'a'.localeCompare('c'); // -2 or -1 (or some other negative value) // Alphabetically the word "check" comes after "against" yielding a positive value 'check'.localeCompare('against'); // 2 or 1 (or some other positive value) // "a" and "a" are equivalent yielding a neutral value of zero 'a'.localeCompare('a'); // 0 |
prototype vs __proto__
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
function blah(){ // do something } console.log(blah.prototype); // blah{} returns the function it's self. this is because only functions have a prototype that isn't nested under __proto__ // an Object is typeof "function" and therefore also has a .prototype not nested under __proto__ // an Object is a typeof function since it is needed to create an object {} //it is a constructor function that creates objects and provides it it's prototype given methods etc console.log(blah.__proto__); // [Function] it points to the base function object console.log(blah.prototype.__proto__ ===Object.prototype); // the custom functions prototype's __proto__ is equal to the master base Object's prototype. to reach the master base object via blah.. you have to use it through prototype.__proto__ . Other wise, if using __proto__ directly it will not go up the chain as expected. |