Shortcut( Unsorted ) | Mac | Windows |
---|---|---|
Copy | Command + C | Ctrl + C |
Paste | Command + V | Ctrl + V |
Undo | Command + U | Ctrl + U |
Redo | Command + Shift + Z | Ctrl + Shift + Z |
Cut | Command + X | Ctrl + X |
New File | Command + N | Ctrl + N |
Open File | Command + O | Ctrl + O |
Close File | Command + W | Ctrl + W |
Save | Command + S | Ctrl + S |
Save As | Shift + Command + S | Shift + Ctrl + S |
Select All | Command + A | Ctrl + A |
Zoom In/Out | Command + +/- | Ctrl + +/- |
Switch Between Open Applications | Command + Tab | Alt + Tab |
Shortcut( Unsorted ) | Mac | Windows |
---|---|---|
Developer tools | Option + Command + I | Option + Ctrl + I |
JavaScript console | Option + Command + J | Option + Ctrl + J |
Inspect elements | Option + Command + C | Option + Ctrl + C |
Refresh page | Command + R | Ctrl + R |
Force refresh | Shift + Command + R | Ctrl + F5 or Ctrl + Click Browser Reload |
Open new window in Incognito Mode | Command + Shift + N | Ctrl + Shift + N |
Save current webpage as a bookmark | Command + D | Ctrl + D |
Traverse open tabs | Option + Command + ←/→ | Option + Ctrl + ←/→ |
Open new tab | Command + T | Ctrl + T |
Close tab | Command + W | Ctrl + W |
Jump to URL address bar | Command + L | Ctrl + L |
In addition to built-in shortcuts, you can also create your own shortcuts or override the built-in shortcuts by opening up the command palette and searching for and editing the keybindings.json
file in VS Code.
Shortcut( Unsorted ) | Mac | Windows |
---|---|---|
Add Selection to Next Match | Command + D | Ctrl + D |
Cut Line or Selection | Command + X | Ctrl + X |
Delete All Characters to the Left of the Cursor | Command + Delete | |
Delete Line | Command + Shift + K | Ctrl + Shift + K |
Delete by Word to the Left of Cursor | Option + Delete | Ctrl + Backspace |
Expand/Shrink Current Selection | Control + Shift + Command + ←/→ | Ctrl + Shift + Command + ←/→ |
Expand/Shrink Current Selection by Word | Shift + Alt + ←/→ | Shift + Alt + ←/→ |
Find in Project | Shift + Command + F | Shift + Ctrl + F |
Find & Replace in Current File | Option + Command + F | Alt + Ctrl + F |
Format Currently Selected Code | Command + K Command + F | Ctrl + K Ctrl + F |
Format Whole File | Shift + Option + F | Shift + Alt + F |
Delete All Characters After the Cursor | Control + K | Ctrl + K |
Delete by Character to the right of the cursor | Control + D or Fn + Delete | Delete |
Delete by Word to the Right of Cursor | Fn + Option + Delete | Fn + Alt + Backspace |
Go to File | Command + P | Ctrl + P |
Go to Line | Control + G | Ctrl + G |
Insert Line Above | Command + Shift + Enter | Ctrl + Shift + Enter |
Insert Line Below | Command + Enter | Ctrl + Enter |
Indent/Outdent Line or Selection | Command + ] / [ | Ctrl + ] / [ |
Jump to Matching Bracket | Command + Shift + \ | Ctrl + Shift + \ |
Move Cursor to End of Line | Command + → | Windows Key + → |
Move Cursor to Start of Line | Command + ← | Windows Key + ← |
Move Cursor to End of Next Word | Option + → | Alt + → |
Move Cursor to Start of Prior Word | Option + ← | Alt + ← |
Move Line Up/Down | Option + ↑/↓ | Alt + ↑/↓ |
Multi-Cursor Editing | Option + Click | Alt + Click |
Open Command Palette | Shift + Command + P | Shift + Crtl + P |
Open Keyboard Shortcuts Menu | Command + K Command + S | Ctrl + K Ctrl + S |
Open User Settings | Command + , | Crtl + , |
Select All Occurrences of Current Selection in Current File | Shift + Command + L | Shift + Ctrl + L |
Select Entire Line / Expand Current Line Selection Down | Command + L | Ctrl + L |
Toggle Code Comment | Command + ? | Ctrl + ? |
Toggle Terminal | Control + ~ | Ctrl + ~ |
Toggle Word Wrap in Current File | Option + G | Alt + G |
Traverse Left/Right Through Open Files/Editor Tabs | Option + Command + ←/→ | Ctrl + Page Up / Page Down |
VS Code IntelliSense provides intelligent code completions based on language semantics and an analysis of your source code. If a language service knows possible completions, the IntelliSense suggestions will pop up as you type. If you continue typing characters, the list of members (variables, methods, etc.) is filtered to only include members containing your typed characters. VS Code IntelliSense is provided for JavaScript, TypeScript, JSON, HTML, CSS, SCSS, and Less out of the box. VS Code supports word based completions for any programming language but can also be configured to have richer IntelliSense by installing a language extension. When using Intellisense, pressing Tab or Enter will insert the selected member. You can trigger IntelliSense in any editor window by typing Control + Space.
Snippets are predefined and customizable templates that allow you to generate repeating code patterns by only entering a short and unique series of text. There are predefined snippets that come with VS Code but you can also create and customize your own snippets or use popular snippet libraries that have been created for the VS Code marketplace.
Emmet provides you with many helpful shortcuts and patterns for generating groups of HTML and CSS code dynamically on the fly. For example, if you want to create a nav bar with a list of 5 links you can type "nav>ul>li*5>a" followed by the Tab key. Modern versions of VSCode include Emmet out-of-the-box.
There are many ways to customize your code editor with different preset syntax highlighting themes, or you can customize your own.
Helps you to navigate in your code, moving between important positions easily and quickly.
Helps you create more human-friendly comments in your code. Allows you to categorize and style your comments differently according to the category (e.g. TODOs, questions, important alerts, etc.).
Matching brackets have the same color, which makes it easier to determine where you are in your code.
Helps prevent bugs by identifying when you've misspelled words and it even works with camelCased words. It comes with built-in dictionary sets and you can also add your own custom words.
Colorizer is great for situations when you're using abstract values for CSS colors instead the actual name of the color. For instance, instead of using color names it's common to use values in units such as RGB, HEX, HSL, etc, but unless you're a CSS color guru it's not going to be immediately clear what colors these values correspond to. Colorizer helps you instantly visualize what colors these values corresponding by highlighting the value background in your code.
CSS Peek allows you to view and make edits to your CSS without having to actually open your CSS files and find the corresponding rule.
ESLint is a popular open source JavaScript linting utility. Code linting is a type of static analysis that is frequently used to find problematic code or code that doesn't adhere to certain style guidelines.
Live Server can launch a local development server with a live reload feature so that when you save your project any changes you've made will be reflected in the browser without you having to manually refresh it.
Material Design (a digital design system developed by Google) themed icons that will add some flair to your VSCode folder and file icons.
Prettier is an opinionated code formatter that saves you time and energy by automatically removing original user code styling and ensuring that outputted code conforms to a consistent style.
When you get to the point where you've added some VSCode extensions and have customized your VSCode experience you may want to use this extension to synchronize your VSCode settings when you work on multiple devices (e.g. one at home and one at the office). It syncs things like extenstions, settings, keybindings, and snippets.
A common convention for setting reminders in a codebase is to leave comments prefixed with "TODO:" or "FIXME:". This extension will highlight these comments to make them easier to identify and distinguish from normal code comments.
This extension is a rapid prototyping playground in your editor that allows you see the result of your programs being run right next to your code, as you type.
This is a list of some of the more commonly used commands but I haven't included examples or any of the available options/arguments/flags that you can add to fine-tune the settings and details of how the commands work.
Change the current directory (i.e. folder) you're in.
Add text to files. View contents of files. Create new files.
Clears the command line window of previous commands and responses. The history is typically still preserved and can be viewed by scrolling up with the arrow key.
Displays a list of all available commands.
Displays a list of all files in the current working directory and allows you to view information about each of the files.
Displays a user manual for a command.
Creates a new directory.
Move and/or rename files.
Displays a list of the currently running processes (e.g. instance of a computer program that is currently running) and information associated with those processes like Process ID (PID), which can be helpful when you'd like to force-close unresponsive programs, particularly command line programs with no GUI.
Displays the name and path of the current working directory that you're in.
Deletes files and directories.
Creates a new file.
Moves the cursor to the start/end of the previous/next word.
Moves the cursor to the end of the line.
Abort running command.
Moves the cursor to the start of the line.
Deletes all characters after the cursor.
Deletes all characters before the cursor.
This is a list of some of the more commonly used commands and definitions but I haven't included examples or any of the available options/arguments/flags that you can add to fine-tune the settings and details of how the commands work.
Places files into a status that allows changes to be committed. This status is often referred to as the "index" or the "staging area". Also allows you to start tracking new files introduced to your Git repository.
Switch branches, view prior commits, restore Working Directory files.
Switch branches, view prior commits, restore Working Directory files.
Creates a copy of a repository into a new local directory, starts tracking remote branches and creates and checks out a new branch that is linked to the cloned repository.
Record changes in the staging area to the repository. Before you push your saved changes to a remote repository you must commit the changes.
Displays differences between two inputs, such as different iterations of a file, commits, branches, working directory, etc. It's most commonly used to view changes made to a file since the last commit.
Download content from another repository, allowing you to view changes between your local repository and a remote repository since your last pull. Does not merge remote changes into your local repository (see git pull
).
Creates an empty, local Git repository that is ready to start tracking your project files.
Displays a log of commits made. By default it includes the commit ID, message, author and date.
Combine independent branches of development.
Fetches content from a remote repository and merges it with another repository or local branch.
Save local repository content that has been committed to a remote repository.
Create, view, and delete connections to other repositories.
A versatile and potentially dangerous command that is often used to undo changes introduced by a given commit by moving the tip of a branch to a prior commit or removing changed files from the Staging Area. You can use the command with different options that affect changes in the Working Directory and Staging Area differently, but all options can permanently remove changes you've made in some form or another so use reset with caution. It is generally advisable that you do not use reset to undo changes that have already been pushed to a public repository since other contributors could've already started working off those changes, which can later cause conflicts and confusion.
Undo the changes introduced by a specific commit and creates a new commit based on those reverted changes and keeps the project history intact. Since revert keeps the history you typically want to use it when undoing commits that have been pushed to a public repository.
Remove files from a Git repository (either from the Staging Area or the Staging Area and the Working Directory).
Take the dirty state of your Working Directory — i.e. your modified tracked files and staged changes — and temporarily store it on a stack of unfinished changes that you can reapply at any time (even on a different branch). This allows you to do things like work on another branch or pull remote changes without committing the unfinished changes.
Displays the status of the current git directory, including information like the files that are being tracked, changes not staged for commit and changes to be committed.
Branches represent independent lines of development, each with it\\'s own working directory, staging area and project history.
A local copy of a remote repository. You often clone a repository when you want to contribute to an group/organizational project. Note that cloning is similar to forking a repository but has important differences (see section links).
A snapshot of a project at a particular point in time. One of the reasons Git is so powerful is because it allows you to easily preserve, view and edit a project's history of changes.
When a specific commit is checked out instead of a branch. When you make changes and commit them in this state, these changes do NOT belong to any branch.
A fork is a copy of a repository and it's most often used when contributing to open source software. When you fork a repository it gives you your own remote copy, which you can then clone and work on locally before pushing changes back to your remote forked copy without affecting the original project. Once you've pushed your changes to your remote copy you can submit a pull request to the original project maintainer. Note that forking is similar to cloning a repository but has important differences (see section links).
A reference to the last commit in the currently checked-out branch.
Your local copy of a project repository that you can independently make changes to.
The default development branch. Whenever you create a git repository, Git creates a branch called "master" and checks it out for you.
A merge occurs when you combine multiple sequences of Git histories. Most frequently used to combine two branches or combining remote changes into your local repository.
An alias used for a remote repository's url. Typically it refers to the central repository that you are pushing and pulling from. It is most commonly named "origin" because that's what Git names it by default when you clone a remote repo for the first time, but you can also rename it.
Pull requests allow you to tell other project collaborators about changes you've pushed to a branch in a repository on GitHub. Once a pull request is opened you can discuss and review the potential changes with collaborators and add follow-up commits before your changes are merged into the base branch.
A version of your project that is hosted on the Internet or network somewhere, as opposed to your local working copy. Typically everybody involved on a project works from (git pull
) and saves to (git push
) a remote repository.
A local cache where changes to your Git-tracked files are stored before they can be committed. Changes are recorded to the staging area with the git add
command. You can determine if a file is in the Staging Area by running the git status
command.
Any files in your working directory that Git is aware of but have not been committed or staged for commit.
The checked-out state of a project's files and folders on your local machine. You must tell Git to track changes to files by running the git add
command. You can view the status of the Working Directory by running the git status
command.
Functions are reusable collections of code that allow programmers to limit repetitive code, group related functionality, and build-up the overall functionality of a larger program based on smaller and more managable units of functionality. A function must be "called" or "invoked" by code in order to have it's functionality activated. Functions in JavaScript can accept any number of inputs (referred to as parameters or arguments) from the invoking code (although usually you should try to keep inputs to a minimum) and then return some kind of useful output to the code that invoked it. If a function doesn't explicitly return an output to the invoking code it will just return undefined
. JavaScript functions are "first-class", which means that they generally have the same abilities as other built-in types of code in that they can be stored in variables, stored in data structures, passed to other functions, returned from other functions, and have properties attached to them. Technically, functions in JavaScript are objects, or to be more specific, they're a sub-type of objects because unlike normal objects, functions are callable. If you use the typeof
operator on a function it will return function
instead of object
. The sections below show some of the many ways functions can be declared and used.
A commonly used form of writing a function with a name.
1function doSomething() {2 return 'Something!';3}
A function without a name. Often used as callbacks or assigned to a variable in function expressions.
1// Example of an anonymous function being stored2// in a variable. This structure is often referred to3// as a "function expression":4const doSomething = function() {5 return 'Something!';6};78// Example of an anonymous function being used9// as a callback function that gets called after10// 5 seconds:11setTimeout(function() {12 console.log('5 seconds are up!');13}, 5000);
Since functions are "first-class" and can be treated like other types of values in JavaScript, you can assign a function to a variable that can then be used to call the function.
1const doSomething = function() {2 return 'Something!';3};45doSomething(); // Something!
Similar to a function expression but with a name instead of just an anonymous function. You probably won't use this form often but it can be helpful because it allows function expressions to be identified in stack-trace errors and for expressions to be called from within themselves when working with recursion.
1const doSomething = function something() {2 return 'Something!';3};
Introduced with ECMAScript 6, arrow functions are a modern and concise way of writing functions with lexical scope, which basically means that when you use the this
keyword it's more intuitive when determining what object this
refers to.
1const doSomethingNoParams = () => {2 return 'Something!';3};45// with only 1 parameter the parens are optional:6const doSomethingOneParam = thing => {7 return `Do this: ${thing}!`;8};910// with one line and implicit return you don't need curly brackets:11const doSomethingReturnImplicitly = () => 'Something!';
When an object property is set to a function it is often referred to as a "method".
1const person = {2 name: 'Jason',3 introduce: function() {4 return `Hello! My name is ${this.name}`;5 }6};
With ECMAScript 6 syntax you can omit the word "function" and place the parens directly after the function name.
1const person = {2 name: 'Jason',3 introduce() {4 return `Hello! My name is ${this.name}`;5 }6};
Pre-ECMAScript 6 way to use a function that acts as a "blueprint" for creating objects. The convention is that the name of the function should start with an upper-case letter so that it's easily reconizable as a constructor. The function parameters will often be named the same thing as the object properties inside the function but they don't have to be, as the example below shows.
1function Person(n, a) {2 this.name = n;3 this.age = a;4 // adding a function inside the constructor will5 // add the function to each object created by this6 // constructor, which is often unnecessary since7 // it takes up more memory8 this.sayHelloV1 = function() {9 return `Hello! My name is ${this.name} and I'm ${this.age} years young!`;10 };11}1213// by adding a function to Person.prototype you14// allow all Person objects access to it15Person.prototype.sayHelloV2 = function() {16 return `Hello! My name is ${this.name} and I'm ${this.age} years young!`;17};1819// create new Person object20const joeBlow = new Person('Joe Blow', 30);
1class Person {2 // built-in constructor function that comes with class3 constructor(n, a) {4 this.name = n;5 this.age = a;6 }78 // user-defined method that gets added to Person.prototype9 // so all Person objects can access it:10 sayHello() {11 return `Hello! My name is ${this.name} and I'm ${this.age} years young!`;12 }1314 // Adding the "static" keyword before a function name defines a15 // static method for a class. Static methods are called without16 // instantiating their class and cannot be called through a class instance.17 static staticMethodHere() {18 return "I'm a static method that can only be called from the Person class itself!";19 }20}2122// create new Person object:23const joeBlow = new Person('Joe Blow', 30);2425// call prototype method:26joeBlow.sayHello();2728// call static method29Person.staticMethodHere();
An anonymous function that is executed immediately (i.e. it is self-invoking). IIFEs were used more frequently in older versions of JavaScript as a way to create modules and keep code private and out of the global scope, but there are better ways to accomplish this now so you will probably mostly see IIFEs in legacy code.
1(function() {2 return 'Something!';3})();45// with ES6 arrow function6(() => {7 return 'Something!';8})();910// Note: There some other ways to write IIFEs11// but these are probably the most common
Gives you control over how the loop starts, runs, and ends. Most commonly used to loop over arrays and strings.
1// common form used to iterate through each value in an array or another iterable from start to end2for (let i = 0; i < iterable.length; i++) {3 // doSomething4}56// loop from end of iterable to start7for (let i = iterable.length - 1; i > -1; i--) {8 // doSomething9}1011// loop over every other item of a iterable starting from the third item12for (let i = 2; i < iterable.length; i += 2) {13 // doSomething14}1516// loops can be nested17for (let i = 0; i < iterableOne.length; i++) {18 for (let j = 0; j < iterableTwo.length; j++) {19 // doSomething20 }21}
Creates a loop iterating over iterable objects such as Array
, String
, array-like objects (e.g. HTMLCollection
, NodeList
, Map
, Set
, and user-defined iterables). Does not loop over normal JavaScript objects (see for-in loop, Object.keys
, Object.values
and Object.entries
).
1const technologies = ['JS', 'HTML', 'CSS'];2for (const val of technologies) {3 console.log(val); // logs 'JS', 'HTML', 'CSS'4}56// If you'll be reassigning/operating on the values7// you're looping over you can declare the variable with let instead of const8const numbers = [10, 20, 30];9for (let val of numbers) {10 val += 1;11 console.log(val); // logs 11, 21, 3112}
Iterates over all enumerable properties of an object, including inherited properties/methods from the prototype chain (see 2nd example below). Most object properties that you'll create will be enumerable, but it's possible to set properties to be non-enumerable so that they don't show up in for-in loops.
1const myObject = { a: 1, b: 2, c: 3 };2for (const property in myObject) {3 console.log(`${property}: ${myObject[property]}`); // logs "a: 1", "b: 2", "c: 3"4}56// Example showing that enumerable, prototype properties are iterated7function Person(first, last) {8 this.firstName = first;9 this.lastName = last;10}1112Person.prototype.sayHello = function() {13 return `Hello! My name is ${this.firstName} ${this.lastName}!`;14};1516const jason = new Person('jason', 'roundtree');1718for (const property in jason) {19 console.log(property); // logs 'jason', 'roundtree', 'sayHello'20}2122// NOTE: To check if a property exists on an object rather23// than being inherited from the prototype chain you can24// use the .hasOwnProperty method25// NOTE: prototype methods on ES6 classes are not enumerable26// and will not show up in for-in loops
Continues a loop as long as the conditional is true
.
1let i = 0;2while (i < 3) {3 console.log(i); // logs 0, 1, 24 i++;5}
Similar to a while loop but executes the statement at least once, even if the condition starts out as false
.
1let i = 0;2do {3 console.log(i); // logs 0, 1, 24 i++;5} while (i < 3 && i !== 0);
Executes a callback function once for each array element. Returns undefined
.
1const array = ['a', 'b', 'c'];2 array.forEach(item => {3 console.log(item); // logs 'a', 'b', 'c'4 doSomethingWithItem(item);5});
Creates a new array populated with the results of calling a provided callback function on every element in the calling array.
1const numbers = [1, 4, 9];2const squareRoot = number => Math.sqrt(number);3const roots = numbers.map(squareRoot);4console.log(roots); // [1, 2, 3]
"Falsy" values are any values or expressions that evaluate to the boolean value of false
.
1// Examples of falsy values2false304-05null6undefined7NaN8// (these are empty strings)9""10''
"Truthy" values are any values or expressions that evaluate to the boolean value of true
.
1// Examples of truthy values2true3{}4[]516-17"I'm a string"8"0"
1if (x === true) {2 // do something...3} else if (y === true) {4 // or do something else...5} else {6 // or if none of the above is true, do this...7}8// NOTE: You can have many different else-if statements but if you find yourself9// writing a lot of them you're probably better off using a switch statement.10// NOTE: You can nest if-else statements1112// instead of writing out "x === true" and "y === true" like in the13// example above, you can shorten it to this:14if (x) {15 // do something...16} else if (y) {17 // or do something else...18} else { /* ... */ }1920// An implicit format of if-else statements can be used in21// functions since when the condition is true the return22// keyword prevents the subsequent code from running:23if (valueIsTrue) {24 return doSomething();25}26doSomethingElse();
Similar to if / else-if / else statements but with a different syntax that makes it easier to write and read when working with multiple conditions to check.
1switch(expressionToEvalute) {2 case 'x':3 // do something...4 break;5 case 'z':6 // or do something else...7 break;8 case 'z':9 // or do something else...10 break;11 default:12 // or if none of the above is true, do this...13}1415// NOTE: If a case is true, the break keyword will prevent16// subsequent cases from being checked
A concise syntax for writing conditional statements.
1conditionToCheck ? doSomethingIfTrue() : doSomethingIfFalse();23// You can also break the clauses onto new lines if it4// helps make the code more readable5conditionToCheck6 ? doSomethingIfTrue()7 : doSomethingIfFalse();89// NOTE: You can nest and chain ternary statements but10// it's generally not recommended because it can make your code difficult to read and understand1112// Ternary statements are often helpful when rendering views with13// libraries like React.js:14{passwordEntered === usersPassword15 ? <p>You've been successfully logged in!</p>16 : <p>The password you entered does not match. Please try again.</p>17)}
In JavaScript (and many other programming languages) evaluation of logical expressions occurs from left to right and logical operators like &&
(AND) and ||
(OR) will "short-circuit", which is a way of preventing unnecessary work from being done. In the context of the OR operator this means that if code on the left side of the operator is true then code on the right side of the operator will not run since in order for an OR statement to be true, only one operand (i.e. value being evaluated) needs to be true. In the context of the AND operator this means that if the code on the left side of the operator is false, the code on right side will not execute since all operands need to be true. This allows you to some cool things like concisely writing if-then logic.
1// In this example the `doSomething` function will only run2// if the `conditionToCheck` variable evaluates to true3let conditionToCheck = true;4conditionToCheck && doSomething();5// so the code above is equivalent to this:6if (conditionToCheck === true) { doSomething(); }78// Short-circuiting with the && operator is often useful when9// rendering views with libraries like React.js:10conditionToCheck && (11 return <div>Render me if conditionToCheck is true</div>12)1314// In this example `doSomething` will only run15// if `conditionToCheck` is false16let conditionToCheck = false;17conditionToCheck || doSomething();18// so the code above is equivalent to this:19if (conditionToCheck === false) { doSomething(); }
Merges two or more arrays. This method does not change the existing array, but instead returns a new array.
Tests whether all elements in the array pass the test implemented by the provided function and returns a Boolean
value.
Creates a new array with all elements that pass the test implemented by the provided callback function.
Returns the value of the first element in the provided array that satisfies the provided callback function.
Returns the index of the first element in the array that satisfies the provided testing function. Otherwise, it returns -1, indicating that no element passed the test.
Executes a callback function once for each array element. Returns undefined
.
1const array = ['a', 'b', 'c'];2 array.forEach(item => {3 console.log(item); // logs 'a', 'b', 'c'4 doSomethingWithItem(item);5});
Determines whether an array includes a certain value among its entries, returning true
or false
according to the results.
Returns the first index at which a given element can be found in the array, or -1 if it is not present.
Creates and returns a new string by concatenating all of the elements in an array (or an array-like object), separated by commas or a specified separator string. If the array has only one item, then that item will be returned without using the separator.
Returns the last index at which a given element can be found in the array, or -1 if it is not present. The array is searched backwards from the last position by default.
Creates a new array populated with the results of calling a provided callback function on every element in the calling array.
1const numbers = [1, 4, 9];2const squareRoot = number => Math.sqrt(number);3const roots = numbers.map(squareRoot);4console.log(roots); // [1, 2, 3]
Removes the last element from an array and returns that element. This method changes the length of the array.
Adds one or more elements to the end of an array and returns the new length of the array.
Executes a reducer function (that you provide) on each element of the array, resulting in a single output value.
Reverses an array in place. The first array element becomes the last, and the last array element becomes the first.
Removes the first element from an array and returns that removed element. This method changes the length of the array.
Returns a shallow copy of a portion of an array into a new array selected from begin to end (end not included) where begin and end represent the index of items in that array. The original array will not be modified.
Sorts the elements of an array in place and returns the sorted array. The default sort order is ascending, built upon converting the elements into strings, then comparing their sequences of UTF-16 code units values.
Changes the contents of an array by removing or replacing existing elements and/or adding new elements in place.
Adds one or more elements to the beginning of an array and returns the new length of the array.
Creates a new, shallow-copied Array
instance from an array-like or iterable object (e.g. HTMLCollection
, NodeList
, Map
, Set
, etc.). NOTE: If you're using ES6 JavaScript you can also use the "spread operator" ( ...
) to achieve the same thing.
Creates a new Array
instance from a variable number of arguments, regardless of number or type of the arguments. The difference between Array.of
and the Array
constructor is in the handling of integer arguments: Array.of(7)
creates an array with a single element, 7, whereas new Array(7)
creates an empty array with a length property of 7 (Note: this implies an array of 7 empty slots, not slots with actual undefined
values).
Using an object literal to create an object is the easiest way to define an object. A blank object consists of two curly brackets and you can either add properties (aka keys) and values to the object at the time of creation or after creation, although it's easier to assign them at the time of creation when possible.
1// create empty object2const me = {};34// Add properties and values after object creation5me.name = 'Jason';6me.heightInches = 75;7me.sayHello = function() {8 console.log(`Hi, my name is ${this.name}`);9};1011// NOTE: If you add a property to an object without12// assigning a value the value will initially be "undefined"1314// Add properties and values at time of object creation15const newMe = {16 name: 'Jason',17 heightInches: 75,18 sayHello: function() {19 console.log(`Hi, my name is ${this.name}`);20 }21};2223// NOTE: functional properties such as "sayHello" are24// typically referred to as "methods"2526// You can nest objects27newMe.attributeValues = {28 strength: 7,29 empathy: 10,30 persuasion: -5,31 humor: 'Incalculable'32}
1class Person {2 constructor(n, a) {3 this.name = n;4 this.age = a;5 }6}7// create new Person object:8const joeBlow = new Person('Joe Blow', 30);
1function Person(first, last) {2 this.firstName = first;3 this.lastName = last;4}5// create new Person object:6const jason = new Person('Jason', 'Roundtree');
After object creation you can add properties and property values or retrieve property values using either dot notation or bracket notation. Dot notation is the more common route since it's less code, but bracket notation can be particularly handy and necessary if the property is being dynamically generated by your code or if the property name includes any non-allowable characters such as spaces and hyphens.
1const me = {};23// DOT NOTATION:45// set properties and values6me.firstName = 'Jason';7me.heightInches = 75;8me.sayHello = function() {9 console.log(`Hi, my name is ${this.name}`);10};1112// get value13console.log(me.name); // 'Jason'1415// BRACKET NOTATION:1617// set property and value dynamically18let propFromInput = 'lastName';19me[propFromInput] = 'Roundtree';20// NOTE: Don't use quotes around variables with bracket notation2122// get value23console.log(me['lastName']); // 'Roundtree'24console.log(me[propFromInput]); // 'Roundtree'
To delete a property from an object you can use the delete
keyword.
1const myObject = {2 name: 'Jason',3 sayHello: function() {4 console.log(`Hi, my name is ${this.name}`);5 }6};78delete myObject.sayHello;9console.log(myObject); // { name: 'Jason' }
Create a new object with an existing object as its prototype.
1const object1 = {2 a: 'Hello'3};4const object2 = Object.create(object1);5object2.b = 'World!';6console.log(object2.a + ' ' + object2.b); // Hello World!7console.log(object2); // { b: 'World!' }
JavaScript is largely considered an object-oriented language because most things in JavaScript are objects and JavaScript gives developers the ability to follow Object Oriented Programming (OOP) techniques, similarly to other popular programming languages like Java, C++, C#, and Python. One core principle of OOP where JavaScript does things quite differently than usual is that instead of using classical inheritance to allow a descendent object (e.g. a child is a descendent of both a parent and a great-great-grandparent) to inherit it's own copies of characteristics from their ancestral objects, JavaScript links objects and delegates the descendent's "inherited" characteristics to its ancestors. This is accomplished through the use of object prototypes and prototype chains. Pretty much all objects in JavaScript have a [[Prototype]]
property that references another object. When you attempt to access a given property of an object, JavaScript first starts with the object specified and if it doesn't find the property name on that object it follows the prototype chain from object to linked object until it finds the property, or otherwise returns undefined
if it doesn't find it. The very top of this chain ends with Object.prototype
. Object.prototype
is built-in to JavaScript and has a number of methods attached to it and because of the prototype chain you can use these built-in methods from objects that you create. There's also built-in prototype methods on other object types like Arrays. For instance, theArray.prototype
is what allows you to call built-in array methods like map()
and filter()
on your custom arrays. You can also define your own custom methods on prototypes (although you shouldn't add anything to Object.prototype
), which is helpful because it allows you to access and reuse that functionality without actually copying the functionality onto the objects that use it, therefore saving memory and keeping your code cleaner.
1// This example is shown using a traditional constructor2// function rather than the newer `class` syntax since3// classes in JavaScript aren't true classes like in other4// languages, but rather an abstraction that just allows5// JavaScript's prototypal-inheritance-based system to6// more closely resemble traditional classes.7function Parent(name, age) {8 this.name = name;9 this.age = age;10}1112// Sets up a custom method on the Parent prototype13Parent.prototype.introduce = function() {14 return `Hi! My name is ${this.name} and I'm ${this.age} years old.`;15};1617// Allows Child objects to use the characteristics normally18// passed to Parent when creating Parent objects but19// instead use those characteristics for creating Child objects20function Child(name, age) {21 Parent.call(this, name, age);22}2324// Sets Child's prototype to be set to Parent's prototype25Child.prototype = Object.create(Parent.prototype);2627// After the step above you need to reset Child's constructor28// function to be the constructor for creating Child objects29// otherwise any objects created whild the Child constructor30// will still be Parent-type objects31Child.prototype.constructor = Child;3233// create Child object34const johnny = new Child('Johnny', 5);3536// Even though the `introduce` method is on Parent.prototype37// and not on Child, Child objects still have access to it.38console.log(johnny.introduce()); // Hi! My name is Johnny and I'm 5 years old.394041// This example accomplishes the same thing as above but with42// ES6 classes. You can see the code is much cleaner and concise43// but JavaScript is still using more complex code "under the hood".44class ParentES6 {45 constructor(name, age) {46 this.name = name;47 this.age = age;48 }49 introduce() {50 return `Hi! My name is ${this.name} and I'm ${this.age} old.`;51 }52}5354class ChildES6 extends ParentES6 {55 constructor(name, age) {56 super(name, age);57 }58}5960const jessica = new ChildES6('Jessica', 7);61console.log(jessica.introduce()); // Hi! My name is Jessica and I'm 7 years old.62
When an object is created, it exists at a specific place in memory. If you were to create two objects with identical properties, the two objects will not be equal to eachother because they exist at different places in memory. One important implication of this is that when you make changes to an object's properties after passing it to a function or assigning it to a new variable, even though it may seem like you're making changes to a copy of the original object, you're actually changing the original object.
1// Creating a new variable and setting it to `obj`2// does not create a copy of `obj`3const obj = {4 a: 'Hello'5};6const objRef = obj;7objRef.a = 'Goodbye';8console.log(obj.a); // Goodbye910// Since arrays are objects the same thing applies11const arr = ['a', 'b', 'c'];12const arrRef = arr;13arrRef.push('d');14console.log(arr); // ['a', 'b', 'c', 'd']
Browser/DOM events are actions that typically occur as a result of a user interacting with a website. There are many different types of events that can occur, such as a web page loading or a user clicking on element, typing into an input and submitting a form (see MDN link below for more events). By adding event listeners to the DOM and utilizing the event-based APIs built into web browsers, developers can respond to events in a programmatic way.
Code typically in the form of functions attached to the DOM that listen for specific events to occur and then react to them in some way. The terms event listeners and event handlers are often used interchangeably to refer to the same thing, although listener could specifically be referring to the part of the code that listens for an event to occur, while handler could refer to the function that is called as a result of the listener being triggered. By those specific definitions you could have multiple listeners that call the same handler function.
Code that attaches to a specific part of the DOM, specifies what type of event to listen for and reacts to that event. The last parameter, referred to as useCapture
, is a boolean value that controls if the given event can be triggered during the Event Capturing phase and it's default value is false (this last parameter can also be an object that implements other options that are infrequently used and beyond the scope of this rudimentary description).
1const myForm = document.querySelector('form');2myForm.addEventListener('submit', function(event) {3 event.preventDefault();4 submitDataToServer();5});67// Or the function can be declared outside of the listener8function handleFormSubmission(event) {9 event.preventDefault();10 submitDataToServer();11}12myForm.addEventListener('submit', handleFormSubmission);1314// You may also add event listeners using the following methods,15// but `addEventListener` is the more modern and flexible approach:1617// This is known as a traditional DOM event handler18myButton.onclick = function () {19 doSomething();20};2122// If you call a named function you don't include parentheses:23myButton.onclick = doSomething;2425// You can add inline event handlers directly26// to HTML elements as attributes, assuming the27// handler function being called is in your JavaScript28// <button onclick=doSomething()>Click Me!</button>
Remove a previously declared event listener that you no longer need or want to react to. The parameters passed to the method must match the parameters used when the event listener was added.
When an event is triggered, the function that handles the event receives an Event object from the browser that contains different properties describing the event, which developers can then use to identify and appropriately respond to the event. The most commonly utilized properties of the Event object describe where in the DOM the event occurred.
1// You can name the event object anything you want but2// it's most common to use "event" or just "e":3function imAnEventHandler(event) { console.log(event) }4function imAlsoAnEventHandler(e) { console.log(e) }
Event Propagation is a general term for the different manners in which an event travels through the DOM once the event has occurred. Events can propagate inward, from the top of the DOM tree's Window object down to the event target element that registered the event, and outward from the event target back to the Window object. The inward propagation is known as Event Capturing or the Capturing Phase and outward propagation is known as Event Bubbling or the Bubbling Phase. The Capturing Phase occurs first and the Bubbling Phase occurs last, and in between these phases is a third phase referred to as the Target Phase, which is when the propagation reaches the event target where the event occurred. Not all event types propagate in both directions.
The target
property of the Event object is itself an object containing many helpful pieces of information about the element where an event was triggered, including information like the element's attributes, content, location and it's relation to other elements in the DOM.henry
The currentTarget
property of the Event object is similar to the target
property (see section above), but instead of being the element that triggered the event it's the ancestor element higher up in the DOM that the event listener is attached to. Since events propagate throughout the DOM, event listeners don't need to be on the actual element that triggered the event. This is particularly helpful because it allows us to do things like "event delegation" (see section below). NOTE: If you try to console.log
currentTarget
you will often see the logged value set to null
in the browser console but this is due to a weird quirk of how console.log
works. Typically, if your code is correct, currentTarget
is actually set to the element where the event listener exists and if you want to verify that you can first set currentTarget
equal to a variable and then console.log
the variable.
Event delegation is when you add an event listener to a parent element of a child element where the event occurred. It's particularly helpful in that it prevents you from having to add event listeners to each child element when a long list of children elements exists and it also allows you to respond to events that occur on child elements that are dynamically added to the DOM after the page initially loads.
Events have a default behavior in the browser that you'll sometimes want to override. For instance, the default behavior for a form upon being submitted is to send form data directly from the client-side form to a back-end server and refresh the page, but with more modern websites we often want to do some other processing of the data instead of submitting directly to the server. Another common situation to use it is with anchor tag links when instead of letting the browser follow the URL value in the href
attribute you can perform some other action.
Returns the first element that is a descendant of the element on which it is invoked that matches the specified group of selectors.
Returns a static (not live) NodeList
representing a list of elements matching the specified group of selectors which are descendants of the element on which the method was called.
Returns a live HTMLCollection
of elements with the given tag name. All descendants of the specified element are searched, but not the element itself. The returned list is live, which means it updates itself with the DOM tree automatically.
Returns a live HTMLCollection
which contains every descendant element that has the specified class name or names.
Returns the element whose id
property matches the specified string.
Read-only property that returns a node's first child in the tree, or null
if the node has no children.
Read-only property that returns the last child of a node. If its parent is an element, then the child is generally an element node, a text node, or a comment node. It returns null
if there are no child elements.
Read-only property returns the object's first child element, or null
if there are no child elements.
Read-only property returns the object's last child element or null if there are no child elements.
Read-only property that returns a live NodeList of child nodes of the given element. The first child node is assigned index 0.
Read-only property that returns a live HTMLCollection
, which contains all of the child elements of the node upon which it was called.
Read-only property that returns the parent of the specified node in the DOM tree.
Read-only property returns a DOM node's parent Element, or null
if the node either has no parent, or its parent isn't a DOM Element.
Read-only property that returns the node immediately preceding the specified one in its parent's childNodes list, or null
if the specified node is the first in that list.
Read-only property that returns the node immediately following the specified one in their parent's childNodes, or returns null
if the specified node is the last child in the parent element.
Starting with the target element itself it traverses parents (heading toward the document root) of the element until it finds a node that matches the provided selectorString. Will return itself or the matching ancestor. If no such element exists, it returns null
.
Inserts a set of Node
objects or DOMString
objects after the last child of the ParentNode
.
Inserts a set of Node
objects or DOMString
objects before the first child of the ParentNode
.
Adds a node to the end of the list of children of a specified parent node. If the given child is a reference to an existing node in the document, appendChild()
moves it from its current position to the new position (there is no requirement to remove the node from its parent node before appending it to some other node).
Inserts an element node at a given position relative to the element it is invoked upon.
Inserts a given text node at a given position relative to the element it is invoked upon.
Parses the specified text as HTML and inserts the resulting nodes into the DOM tree at a specified position. It does not reparse the element it is being used on, and thus it does not corrupt the existing elements inside that element. This avoids the extra step of serialization, making it much faster than direct innerHTML
manipulation.
Inserts a node before a reference node as a child of a specified parent node. If the given node already exists in the document, insertBefore()
moves it from its current position to the new position (i.e. it will automatically be removed from its existing parent before appending it to the specified new parent).
Gets or sets the text content of the specified node, and all its descendants. As a getter, it approximates the text the user would get if they highlighted the contents of the element with the cursor and then copied it to the clipboard.
Creates a new Text node. This method can be used to escape HTML characters.
Sets the value of an attribute on the specified element. If the attribute already exists, the value is updated; otherwise a new attribute is added with the specified name and value.
Returns the value of a specified attribute on the element. If the given attribute does not exist, the value returned will either be null
or an empty string.
Gets and sets the value of the class attribute of the specified element. If there are multiple classes on the element then the returned value will be a string of space-separated class names.
Read-only property that returns a DOMTokenList
, which is a live collection of the class attributes of the element (e.g using classList
on an element with class="one two three"
will return a list similar to the following format: { 0: 'one', 1: 'two', 2: 'three' }
). This can then be used to manipulate the class list using built-in methods that are inherited from the DOMTokenList
object (see link below for the available methods). Using classList
is a convenient alternative to accessing an element's list of classes as a space-delimited string via element.className.
Returns a Boolean value indicating whether a node is a descendant of a given node, i.e. the node itself, one of its direct children (childNodes
), one of the children's direct children, and so on.
Read-only property that returns the tag name of the element on which it's called. For example, if the element is an its tagName
property is IMG
.
Read-only property that returns an integer that identifies what type of node something is. It distinguishes different kind of nodes from each other, such as elements, text and comments.
Global scope is when you have a variable or function that exists at the top level of your program (e.g. the window
in the browser) so it can be accessed from anywhere in your program, which may seem powerful but it’s usually undesirable because it can cause clashes with other global uses of the same name (e.g. separate variables in a completely different areas of your app, variables declared and used in external libraries that you’re using in your app) and make your program more difficult to reason about.
Function scope means that variables and functions declared inside of a function can only be accessed by other code inside of that function and not by any code that exists outside that function.
1function greetings() {2 var a = 'hello';3 console.log('function scoped var: ', a);4 function sayGreeting() {5 console.log('function scoped function: ', `${a}, friendo!`);6 }7 sayGreeting(); // function scoped function: hello, friendo!8}9greetings(); // function scope: hello10console.log(a); // ReferenceError: a is not defined11sayGreeting(); // ReferenceError: sayGreeting is not defined
ES6 JavaScript introduced the let
and const
forms of declaring variables, which give us the ability to use block scope, which means that the scope is contained to the nearest set of enclosing curly brackets ( { }
). That means that you can access block-scoped variables from anywhere within a set of brackets but not from outside of those brackets.
1const a = 'hello';2if (a === 'hello') {3 const a = 'goodbye';4 console.log(a); // goodbye5 // Note: this example shows how you can declare6 // variables with the same name in different scopes,7 // but keep in mind that you can't declare the same8 // variable or function names inside of the same scope9}10console.log(a); // hello1112// Example showing that the `i` variable is confined to the corresponding13// block of the for loop because let is block-scoped14for (let i = 1; i <= 5; i++) {15 console.log(i); // 1 2 3 4 516}17console.log(i); // ReferenceError: i is not defined18// Note: if you used var instead of let in the example above19// then the variable `i` would be scoped to outside of the for loop
JavaScript manages scope based on the principle of lexical scope, which means that scope is statically set when you write your code (or to be more accurate, when the code is compiled just before being executed, as opposed to potentially changing dynamically when your code is executed) and it determines how outer scopes are accessed from within nested scopes. Variables that are used inside of nested functions have access to variables of the same name that are declared in any outer functions and scopes. If you use a variable in a nested function but the variable isn't declared inside of that function then JavaScript will check in any parent functions to determine where it was declared, ultimately stopping at the first place where it was declared or all the way up to the global scope otherwise. This means that if the same variable name is declared more than once at different levels of lexical scope, then any declarations in lower-level functions will block or shadow the outer variable declarations from being accessed.
1let a = 'hello';2let b = 'konnichiwa';34function outer() {5 a = 'hola';6 console.log(a); // hola78 function inner() {9 // Note: `a` hasn’t been reassigned to ‘bonjour’ yet10 console.log(a); // hola11 a = 'bonjour';12 console.log(a); // bonjour1314 function furtherInner() {15 console.log(a); // bonjour16 console.log(b); // konnichiwa17 }18 furtherInner();19 }20 inner();21}2223outer();242526// Example of arrow functions lexically binding to27// the object context (assume this code is at the top-level28// of a javascript file):29const person = {30 name: ‘Jason’,3132 // this function is bound to `obj`:33 greetings: function() {34 console.log(this.a); // hello3536 // when you have a normal function that is nested inside37 // of a method, the nested function will not be directly38 // associated with the object it’s inside of, so this39 // function is bound to the global object (window in browsers)40 // where the `a` variable doesn’t exist:41 setTimeout(function() {42 console.log(this.a); // undefined43 }, 1000);4445 // when you use an arrow function inside of a nested function46 // then the `this` keyword is lexically bound to the object it’s47 // inside of:48 setTimeout(() => {49 console.log(this.a); // hello50 }, 2000);51 }52};
Hoisting is a term that describes how JavaScript parses a program and associates variables and functions with the top part of the scope in which they exist, before executing the program. This can allow you to do some unusual things like call functions before they are declared. Hoisting is usually something that you don’t need to consciously think about but it can manifest itself in some funky behavior in certain circumstances so it’s good to be aware of it. You can avoid weird issues caused by hoisting by calling functions and using variables lower in the program than the lines where they are defined and assigned values. Hoisting behaves slightly differently on different forms of functions and with the type of keyword you use when declaring variables.
1// variables declared with `var` are hoisted and initialized2// with a value of `undefined`.3console.log(greeting1); // undefined4var greeting1;56console.log(greeting2); // undefined7var greeting2 = 'Hello world!';89// variables declared with `const` and `let` are hoisted but not10// initialized, which means that you can’t use these variables11// before they are assigned a value.12console.log(greeting3); // ReferenceError: Cannot access 'greeting' before initialization13let greeting3 = 'Hello world!';1415// Side note - variables declared with `const` must be initialized when declared16const greeting4; // SyntaxError: Missing initializer in const declaration1718// function declartions are hoisted along with the function body,19// which allows you to call a function before it’s defined (but20// you should probably just call functions after they’re defined)21funcDeclaration('hello world!'); // 'hello world!22function funcDeclaration(str) {23 console.log(str);24}2526// function expressions and Class functions are similar to27// `let` and `const` in that they’re technically hoisted but not28// initialized so there’s no reason to try and call a function29// expression or Class before they have been declared.30funcExpression('hello world!'); // ReferenceError: Cannot access 'funcExpression' before initialization31const funcExpression = function(str) {32 console.log(str);33};3435const jason = Person('Jason', 'hello world!'); // ReferenceError: Cannot access 'Person' before initialization36class Person {37 constructor(name, greeting) {38 this.name = name;39 this.greeting = greeting;40 }41}
The principle of closure in JavaScript is a behavior of functions that enables them to remember the value of variables within a function’s lexical scope (i.e. where the function is physically defined in the code and the area around that function that it has access to), even when that function is executed outside of its lexical scope. This allows you to keep data private and predictable. Without closure you would have to write more code to explicitly pass variables around to different parts of your program.
1// In this example the `powerOf` function closes over the parameters2// `base` and `exponent`. Each time the `baseOf` function is called3// it creates a new context where the value of the `base` parameter4// is newly created to whatever number is passed in as the argument.5function baseOf(base) {6 return function powerOf(exponent) {7 return base ** exponent;8 };9}1011const base2ToThePowerOf = baseOf(2);12const base3ToThePowerOf = baseOf(3);13console.log(base2ToThePowerOf(8)); // 25614console.log(base3ToThePowerOf(4)); // 81151617// in this example the `inner` function closes over variable `a`18// and a reference to `a` is kept alive in the variable `b`19// even after the `outer` function has been executed.20function outer() {21 let a = 0;22 return function inner() {23 a++;24 console.log(a);25 };26}2728const b = outer();29b(); // 130b(); // 231b(); // 3
The this
keyword in JavaScript is a mechanism for referring to the object that a property or function references or applies to. It is one of the more confusing aspects of JavaScript and it is often incorrectly thought of as a reference to the function this
resides in or the scope of that function, and while these scenarios can sometimes be true, it’s more accurate to say that what this
refers to is a product of the context in which the function is invoked/called. There are a handful of different ways of invoking a function that determine what context this
refers to (see below).
The most basic example of how to determine what this
refers to is when a function is invoked by a plain, stand-alone function in the global scope.
1var name = 'Mason';2function logName() {3 var name = 'Jason';45 // this logs `window` in browser (unless this function is6 // running in `strict mode`, in which case `this` from7 // within a function will refer to `undefined`)8 console.log(this);910 // this logs `Mason` because `this` refers to11 // global scope not function scope:12 console.log(this.name);1314 this.name = name;15 // this logs ‘Jason’ because the global variable16 // has been changed on the line above17 // to the `name` variable declared within18 // this function:19 console.log(this.name);20}2122logName();2324// this logs ‘Jason’ since the variable declared25// on line 1 has been changed on line 11:26console.log(name);
When a function exists as a property of an object it is often referred to as a "method". When a function is invoked as a method, this
, by default, will refer to the object that the function refers to (i.e. the first object to the left of the period prior to the property name).
1function sayHello() {2 console.log(this.firstName + ' ' + this.lastName);3}45var firstName = 'Mason';6var lastName = 'Poundtree';78const jason = {9 firstName: 'Jason',10 lastName: 'Roundtree',11 // this sayHello object property now refers to12 // the `sayHello` function above:13 sayHello: sayHello14};1516jason.sayHello(); // Jason Roundtree17window.sayHello(); // Mason Poundtree
JavaScript functions have built-in utility methods named call
, apply
and bind
that to allow you to explicitly use an object as the this
context for a given function. call
and apply
operate almost identically, except that call
accepts a list of comma-separated values as arguments while apply
accepts an array of arguments. A form of explicit binding known as hard binding can be achieved by using the bind
method. bind
creates a new function with the passed-in object set as the function’s this
value. This is similar to what call
and apply
do except bind
returns a function to a variable that you call later instead of calling the bound function immediately.
1// call & apply:23const plainJason = { name: 'Jason 🙂' };4const coolJason = { name: 'Cool Jason 😎️' };56function greet(greeting) {7 return `${greeting} My name is ${this.name}.`;8}910console.log(greet.call(plainJason, 'Hello.'));11// Hello. My name is Jason 🙂.12console.log(greet.apply(coolJason, ['Sup, bruh?!']));13// Sup, bruh?! My name is Cool Jason 😎️.1415// bind:1617var myLight = { brightness: 10 };1819var brightness = 5;2021function shineLight() {22 return '💡'.repeat(this.brightness);23}2425console.log(shineLight()); // 💡💡💡💡💡2627var bindedByMyLight = shineLight.bind(myLight);28// above we've used `bind` to force `shineLight` to refer to29// `myLight.brightness` instead of `window.brightness`30console.log(bindedByMyLight()); // 💡💡💡💡💡💡💡💡💡💡31
When you instantiate a function using new
and a class/constructor function, this
references the object created. Any methods from the constructor function are accessed by this
via the prototype chain.
1class Person {2 constructor(name, age) {3 this.name = name;4 this.age = age;5 }6 greet() {7 return `8 Hello, my name is ${ this.name } and I’m ${ this.age } years old.9 `;10 }11}12const jason = new Person(‘Jason’, 36);1314console.log(jason.name); // Jason15console.log(jason.greet()); // Hello, my name is Jason and I’m 36 years old.
ES6 arrow functions are unique in that instead of following any of the rules above, the this keyword will “lexically” reference the containing scope from where the arrow function is defined.
1var mySurprisingObject = {2 someProptery: 'i am property',3 outer: function() {4 console.log('outer this: ', this.someProptery);5 function inner() {6 console.log('inner this: ', this.someProptery);7 }8 inner();9 }10};11mySurprisingObject.outer();12// outer this: i am property13// inner this: undefined1415// It’s natural and tempting to think that `this` in16// the `inner` function will still refer to `myObject`17// but it actually isn’t associated with the object at all,18// so it is effectively defined on the global scope.19// ES6 arrow functions fix this issue:2021var myMoreIntuitiveObject = {22 someProptery: 'i am property',23 outer: function() {24 console.log('outer this: ', this.someProptery);25 // an arrow function enforces that `this` refers to26 // the expected object it's defined in:27 const inner = () => {28 console.log('inner this: ', this.someProptery);29 };30 inner();31 }32};33myMoreIntuitiveObject.outer();34// outer this: i am property35// inner this: i am property3637// Prior to ES6, JavaScript developers devised the38// following hack to allow nested functions to access39// the proper `this` access by reassigning it to a new40// variable in the outer method’s scope:4142var myHackedObject = {43 someProptery: 'i am property',44 outer: function() {45 // Here we create a variable arbitrarily called `_this` to46 // capture the myObject scope from the outer function so that47 // the `inner` function can use it (it's common to see variable48 // names like `self` or `that` used instead of `_this`)49 var _this = this;50 console.log('outer this: ', this.someProptery);51 function inner() {52 console.log('inner _this: ', _this.someProptery);53 }54 inner();55 }56};57myHackedObject.outer();58// outer this: i am property59// inner _this: i am property6061// Note that arrow functions don’t have their own copy62// of this so you gernally don’t want to use them for63// object methods or prototype methods because the64// lexical scope will refer to the global scope since65// that’s where the object is lexically defined:6667// object method:68var myObject = {69 someProptery: 'i am property',70 outer: () => {71 console.log('outer this: ', this.someProptery);72 }73};7475// prototype method76function Person(fullName) {77 this.fullName = fullName;78}79Person.prototype.sayHello = () => {80 console.log(`Hello, my name is ${this.fullName}`);81};82const jason = new Person('Jason');83jason.sayHello(); // Hello, my name is undefined8485// Also note that you can’t use arrow functions for contructor86// functions like this example, which will throw an error when you87// try to use the constructor:88const PersonBad = (name) => {89 this.name = name;90};91