JavaScript Cheat Sheet
1018 |Based off of Learn X in Y Minutes.
1019 |JavaScript (JS) is a dynamic interpreted language that powers the web. It is widely used in browsers (where JS scripts are interpreted by JavaScript engines like Chrome’s V8) and increasingly on servers (on a Node.js runtime environment).
1020 |JS is a prototype-based scripting language with first-class functions and dynamic typing. Because of its super flexibility, JS supports multiple styles of programming including imperative, object-oriented and functional.
1021 |Here’s what all those big words above mean:
1022 | - Interpreted Language: a language (eg. JS, Python) in which most of its implementations execute instructions directly, without previously compiling a program into machine-language instructions like compiled languages do (eg. C++)
1023 | - JavaScript Engine: a virtual machine that interprets and executes JS
1024 | - Prototype-Based: unlike classical OOP with classes and objects, in JS, objects are cloned from other objects, and all objects have prototypes (kinda like the template they inherit from)
1025 | - First-Class Functions: JS supports passing functions as arguments to other functions, returning them as the values from other functions, and assigning them to variables or storing them in data structures
1026 | - Dynamically Typed: The “type” of all variables is only interpreted at run-time unlike statically typed languages where all variables have a type at compile-time
1027 | - Imperative Programming: Statement based programming
1028 | - Object-Oriented Programming: Object based programming
1029 | - Functional Programming: Function based programming
Quick Access Links
1031 |-
1032 |
- Basics
-
1033 |
- Primitives 1034 |
- Operators 1035 |
1037 | - More Basic Syntax
-
1038 |
- Variables 1039 |
- Arrays 1040 |
- Logic and Control Structures 1041 |
1043 | - Objects and Functions
-
1044 |
- Objects 1045 |
- Functions 1046 |
- Bind, Call and Apply 1047 |
1049 | - Function Execution, Variable Scope, Closures & Callbacks
-
1050 |
- Hoisting 1051 |
- Scope Chain 1052 |
- Closures 1053 |
- Callbacks 1054 |
1056 | - Object-Oriented JS and Prototypal Inheritance
-
1057 |
- Constructors 1058 |
- Prototypes 1059 |
- Prototypal Inheritance 1060 |
- Built-In Constructors 1061 |
1063 | - Bugs and Error Handling 1064 |
- New ES6 stuff 1065 |
TODO: Add 8. Useful Libraries (LoDash, jQuery), 9. Javascript in the browser, 10. NodeJS
1067 | 1068 |1. Basics
1069 |Everything in JS is either an object or a primitive.
1070 |
1071 | // This is a single line comment,
1072 | /* and this is a
1073 | multiline comment */
1074 |
1075 | // Semicolons (;) to terminate lines are optional
1076 | // However, the JS engine will (usually) automatically insert semicolons upon seeing '\n'
1077 | // This can cause some weird behaviour so ALWAYS use semicolons
1078 | doStuff();
1079 |
1080 | 1081 |
i. Primitives: Number, String, Boolean (and some special ones)
1082 |// JavaScript has one number type (which is a 64-bit IEEE 754 double).
1083 | // Doubles have a 52-bit mantissa, which is enough to store integers
1084 | // up to about 9✕10¹⁵ precisely.
1085 | 3; // = 3
1086 | 1.5; // = 1.5
1087 |
1088 | // Some basic arithmetic works as you'd expect.
1089 | 1 + 1; // = 2
1090 | 0.1 + 0.2; // = 0.30000000000000004 (funky floating point arithmetic--be careful!)
1091 | 8 - 1; // = 7
1092 | 10 * 2; // = 20
1093 | 35 / 5; // = 7
1094 |
1095 | // Including uneven division.
1096 | 5 / 2; // = 2.5
1097 |
1098 | // Bitwise operations also work; when you perform a bitwise operation your float
1099 | // is converted to a signed int *up to* 32 bits.
1100 | 1 << 2; // = 4
1101 |
1102 | // Precedence is enforced with parentheses.
1103 | (1 + 3) * 2; // = 8
1104 |
1105 | // There are special primitive values:
1106 | Infinity; // result of e.g. 1/0
1107 | -Infinity; // result of e.g. -1/0
1108 | NaN; // result of e.g. 0/0
1109 | undefined; // never use this yourself. This is the default value for "not assigned"
1110 | null; // use this instead. This is the programmer setting a var to "not assigned"
1111 |
1112 | // There's also a boolean type.
1113 | true;
1114 | false;
1115 |
1116 | // Strings are created with single quotes (') or double quotes (").
1117 | 'abc';
1118 | "Hello, world";
1119 |
1120 | // You can access characters in a string with `charAt`
1121 | "This is a string".charAt(0); // = 'T'
1122 |
1123 | // ...or use `substring` to get larger pieces.
1124 | "Hello world".substring(0, 5); // = "Hello"
1125 | "Hello world".slice(0, 5); // does the same thing
1126 | "Hello world".substr(0, 5); // yet again
1127 |
1128 | // `length` is a property, so don't use ().
1129 | "Hello".length; // = 5
1130 |
1131 | // Searching strings
1132 | "Mary had a little lamb".search("had"); // returns 5
1133 | "Mary had a little lamb".indexOf("zebra"); // returns -1
1134 |
1135 | // String to a character array
1136 | "one two three four".split(" "); // ['one', 'two', 'three', 'four']
1137 |
1138 | // String replace
1139 | "happy birthday henry!".replace("h", "H"); // "Happy birthday Henry!"
1140 |
1141 | // ES6 also introduces Symbol as a new primitive type
1142 | // But I'll add that on here once I actually figure out what it is
1143 |
1144 | 1145 |
ii. Operators aka weirdly written functions
1146 |// Operators have both a precedence (order of importance, like * before +)
1147 | // and an associativity (order of evaluation, like left-to-right)
1148 | // A table of operators can be found here
1149 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_Precedence)
1150 |
1151 | // Negation uses the ! symbol
1152 | !true; // = false
1153 | !false; // = true
1154 |
1155 | // There's shorthand operators for performing math operations on variables:
1156 | someVar += 5; // equivalent to someVar = someVar + 5;
1157 | someVar *= 10; // someVar = someVar * 10;
1158 |
1159 | // and an even-shorter-hand operators for adding or subtracting 1
1160 | someVar++;
1161 | someVar--;
1162 |
1163 | // Strings are concatenated with +
1164 | "Hello " + "world!"; // = "Hello world!"
1165 |
1166 | // Comparison Operators
1167 | 1 < 10; // = true
1168 | 1 > 10; // = false
1169 | 2 <= 2; // = true
1170 | 2 >= 2; // = true
1171 |
1172 | // and are compared with < and >
1173 | "a" < "b"; // = true
1174 |
1175 | // Strict Equality is ===
1176 | // Strict meaning both type AND value are the same
1177 | 1 === 1; // = true
1178 | 2 === 1; // = false
1179 |
1180 | // Strict Inequality is !==
1181 | 1 !== 1; // = false
1182 | 2 !== 1; // = true
1183 |
1184 | // == allows for type coercion (conversion) and only checks if the values are equal after coercion
1185 | "5" == 5; // = true
1186 | null == undefined; // = true
1187 |
1188 | // ...which can result in some weird behaviour...so use === whenever possible
1189 | 13 + !0; // 14
1190 | "13" + !0; // '13true'
1191 |
1192 | // false, null, undefined, NaN, 0 and "" are falsy; everything else is truthy.
1193 | // Note that 0 is falsy and "0" is truthy, even though 0 == "0".
1194 |
1195 | // We can use this to our advantage when checking for existence
1196 | if (x) { //doSomething };
1197 |
1198 | // Or to set default values
1199 | x = x || "default"
1200 | // if x exists, do nothing and short-circuit, else set x to a default
1201 |
1202 | // but a problem arises if x = 0. It exists, but will coerce to false
1203 | // be wary of this
1204 |
1205 | // figuring out types of literals and vars
1206 | typeof "Hello"; // = "string"
1207 | typeof 42; // = "number"
1208 | typeof undefined // = "undefined"
1209 | typeof null // = 'object' THIS IS A JS BUG!
1210 |
1211 | // figuring out if an object is an instance of another object
1212 | // checks all the way down the prototype chain
1213 | var x = {}
1214 | x instanceof Object // = true
1215 | x instanceof Function // = false
1216 |
1217 |
1218 |
1219 |
1220 | 2. More Basic Syntax
1221 | 1222 |i. Variables
1223 |// Variables are declared with the `var` keyword. JavaScript is dynamically
1224 | // typed, so you don't need to specify type. Assignment uses a single `=`
1225 | // character.
1226 | var someVar = 5;
1227 |
1228 | // if you leave the var keyword off, you won't get an error...
1229 | someOtherVar = 10;
1230 |
1231 | // ...but your variable will be created in the global scope, not in the scope
1232 | // you defined it in.
1233 |
1234 | // Variables declared without being assigned to are set to undefined.
1235 | var someThirdVar; // = undefined
1236 |
1237 |
1238 |
1239 | ii. Arrays
1240 |// Arrays are ordered lists of values, of any type.
1241 | var myArray = ["Hello", 45, true];
1242 |
1243 | // Their members can be accessed using the square-brackets subscript syntax.
1244 | // Array indices start at zero.
1245 | myArray[1]; // = 45
1246 |
1247 | // Arrays are mutable and of variable length (dynamically sized arrays)
1248 | myArray.push("World"); // adds to the end
1249 | myArray.length; // = 4
1250 |
1251 | // Add/Modify at specific index
1252 | myArray[3] = "Hello";
1253 |
1254 |
1255 |
1256 | iii. Logic and Control Structures
1257 |// The `if` structure works as you'd expect.
1258 | var count = 1;
1259 | if (count === 3){
1260 | // evaluated if count is 3
1261 | } else if (count === 4){
1262 | // evaluated if count is 4
1263 | } else {
1264 | // evaluated if it's not either 3 or 4
1265 | }
1266 |
1267 | // As does `while`.
1268 | while (true){
1269 | // An infinite loop!
1270 | }
1271 |
1272 | // Do-while loops are like while loops, except they always run at least once.
1273 | var input;
1274 | do {
1275 | input = getInput();
1276 | } while (!isValid(input))
1277 |
1278 | // The `for` loop is the same as C++ and Java:
1279 | // initialisation; continue condition; iteration.
1280 | for (var i = 0; i < 5; i++){
1281 | // will run 5 times
1282 | }
1283 |
1284 | // && is logical AND, || is logical OR
1285 | if (house.size === "big" && house.colour === "blue"){
1286 | house.contains = "bear";
1287 | }
1288 | if (colour === "red" || colour === "blue"){
1289 | // colour is either red or blue
1290 | }
1291 |
1292 | // The `switch` statement checks for equality with `===`.
1293 | // use 'break' after each case
1294 | // or the cases after the correct one will be executed too.
1295 | grade = 'B';
1296 | switch (grade) {
1297 | case 'A':
1298 | console.log("Great job");
1299 | break;
1300 | case 'B':
1301 | console.log("OK job");
1302 | break;
1303 | case 'C':
1304 | console.log("You can do better");
1305 | break;
1306 | default:
1307 | console.log("Oy vey");
1308 | break;
1309 | }
1310 |
1311 |
1312 |
1313 |
1314 | 3. Objects and Functions
1315 | 1316 |i. Objects
1317 |An object is simply an unordered collection of key-value pairs.
1318 |
// They can be made literally:
1319 | var myObj = {key1: "Hello", key2: "World"};
1320 | // or using the Object constructor:
1321 | var myObj = new Object();
1322 |
1323 | // Keys are strings, but quotes aren't required if they're a valid
1324 | // JavaScript identifier. Values can be any type including other objects.
1325 | var myObj = {myKey: "myValue", "my other key": 4};
1326 |
1327 | // Objects can even contain functions (called methods)
1328 | // When functions attached to an object are called, they can access the object
1329 | // they're attached to using the `this` keyword.
1330 | var myObj = {
1331 | name: "Destiny's Child",
1332 | sayMyName: function() {
1333 | console.log(this.name);
1334 | }
1335 | }
1336 | myObj.sayMyName(); // outputs "Destiny's Child"
1337 |
1338 | // Object attributes can also be accessed using the subscript syntax,
1339 | myObj["my other key"]; // = 4
1340 |
1341 | // ... or using the dot syntax, provided the key is a valid identifier.
1342 | myObj.myKey; // = "myValue"
1343 |
1344 | // Objects are mutable; values can be changed and new keys added.
1345 | myObj.myThirdKey = true;
1346 |
1347 | // If you try to access a value that's not yet set, you'll get undefined.
1348 | myObj.myFourthKey; // = undefined
1349 |
1350 | // iterating through objects
1351 | for(var property in myObj) { // do something }
1352 |
1353 | // JSON (JavaScript Object Notation) is just a special case of Object literal notation
1354 | // where the keys are strings wrapped in quotes
1355 | var json_stuff = {
1356 | "firstName": "John",
1357 | "lastName": "Doe",
1358 | "Age": 25
1359 | }
1360 |
1361 | // JS Object => JSON
1362 | JSON.stringify(myObj);
1363 |
1364 | // JSON => JS Object
1365 | JSON.parse(json_stuff);
1366 |
1367 |
1368 | ii. Functions
1369 |Functions are special kinds of objects! Functions can have their own methods and properties just like other objects, but they’re rarely used in that way.
1370 |Remember, functions in JS are first-class. Meaning they can be assigned and passed just like any other variable can.
1371 |Functions are special in that they have an optional name property and a code property (which is the body of the function that actually does stuff). The function’s code is executed by the invocation operator ()
.
// JavaScript functions are declared with the `function` keyword.
1373 | // This is a function statement
1374 | function myFunction(thing){
1375 | return thing.toUpperCase();
1376 | }
1377 |
1378 | // This is a function expression
1379 | var makeUpperCase = function() {
1380 | return think.toUpperCase();
1381 | }
1382 |
1383 | // Note that the value to be returned must start on the same line as the
1384 | // `return` keyword, otherwise you'll always return `undefined` due to
1385 | // automatic semicolon insertion. Watch out for this when using Allman style.
1386 | function myFunction()
1387 | {
1388 | return // <- semicolon automatically inserted here
1389 | {
1390 | thisIsAn: 'object literal'
1391 | }
1392 | }
1393 | myFunction(); // = undefined
1394 |
1395 | // JavaScript functions are first class objects, so they can be reassigned to
1396 | // different variable names and passed to other functions as arguments - for
1397 | // example, when supplying an event handler:
1398 | function myFunction(){
1399 | // this code will be called in 5 seconds' time
1400 | }
1401 | setTimeout(myFunction, 5000);
1402 | // Note: setTimeout isn't part of the JS language, but is provided by browsers
1403 | // and Node.js.
1404 |
1405 | Function objects don’t even have to be declared with a name - you can write an anonymous function definition directly into the arguments of another. 1406 |
setTimeout(function(){
1407 | console.log("It's been 5 seconds!");
1408 | // this code will be called in 5 seconds time
1409 | }, 5000);
1410 |
1411 |
1412 | This has led to a common pattern of “immediately-executing anonymous functions”, which prevent temporary variables from leaking into the global scope. The function expression is wrapped in parenthesis and then is invoked using ()
(function(){
1414 | var temporary = 5;
1415 | })();
1416 | temporary; // raises ReferenceError
1417 | permanent; // = 10
1418 |
1419 |
1420 | An important distinction: primitives Pass by Value while objects Pass by Reference
1421 |
// Primitives are passed by value
1422 | var i = 2;
1423 | function double(i){ i*2; } // another i is created with the same value in a different execution context
1424 | double(i);
1425 | console.log(i); // still 2
1426 |
1427 | // Objects (including functions) are passed by reference
1428 | var obj = { hero: "Superman" };
1429 | function bestSuperhero(obj){
1430 | obj.hero = "Batman";
1431 | }
1432 | bestSuperhero(obj);
1433 | console.log(obj.hero); // = "Batman"
1434 |
1435 | The
this
keyword within methods, always refers to the object that the method is tied to. However, if the method has an inner function, its this
refers to the global object. Some regard this as a bug in JS, so the good practice is to create and use a variable called self
.
1436 | var c = {
1437 | name: 'The c object',
1438 | log: function() {
1439 | var self = this;
1440 |
1441 | self.name = 'Updated c object';
1442 | console.log(self);
1443 |
1444 | var setname = function(newname) {
1445 | self.name = newname;
1446 | }
1447 | setname('Updated again! The c object');
1448 | console.log(self);
1449 | }
1450 | }
1451 | c.log(); // outputs "Updated again! The c object"
1452 |
1453 |
1454 |
1455 | iii. Bind, Call and Apply
1456 |Functions that aren’t tied to objects can use this
and still be useful. Consider this example.
1457 |
var cow = { says: "moo" };
1458 | var dog = { says: "woof" };
1459 | var pig = { says: "oink" };
1460 |
1461 | function speak(times) {
1462 | for(i = 0; i < times; i++) {
1463 | console.log(this.says);
1464 | }
1465 | }
1466 | speak(4); // error because this is the global object which doesn't have a 'says' property
1467 |
1468 | To use speak, we need to use the .bind, .call or .apply methods, which are available to all functions. The first parameter of these functions is the object which becomes
this
within the function.
1469 | // bind creates a copy of the function it's being called on
1470 | var cowSpeak = speak.bind(cow);
1471 | cowSpeak(4); // outputs "moo moo"
1472 |
1473 | // call directly executes the function with the first parameter being 'this'
1474 | // and all the other parameters being the function's parameters
1475 | speak.call(dog, 3); // outputs "woof woof woof"
1476 |
1477 | // apply directly executes the function with the first parameter being 'this'
1478 | // and all the other function parameters being passed in as an array
1479 | speak.apply(pig, [1]); // outputs "oink"
1480 |
1481 | The call and apply methods allow us to do something called Function Borrowing.
1482 |
var darthVader = {
1483 | son: "Luke",
1484 | saying: function(){
1485 | console.log(this.son + ", I am your father");
1486 | }
1487 | };
1488 | var luke = { son: "Ben" };
1489 |
1490 | darthVader.saying.call(luke);
1491 | // borrowing Darth Vader's saying
1492 | // outputs "Ben, I am your father"
1493 |
1494 | The bind method allows us to do Function Currying.
1495 |
// Creating a copy of a function with preset parameters
1496 | function multiply(a,b){ return a*b }
1497 |
1498 | // first parameter can be 'this' or null or anything--doesn't matter since 'this' is not used
1499 | // the second parameter (a) is permanently set to 2
1500 | var double = multiply.bind(this, 2);
1501 | double(16); // outputs 32
1502 |
1503 |
1504 |
1505 | 4. Function Execution, Variable Scope, Closures & Callbacks
1506 |A few important concepts:
1507 | - Global means not inside a function. The global object is ‘window’ in browsers.
1508 | - The Lexical Environment is where something sits physically in the code
1509 | - ‘this’ is a reference to the object that the currently running method is tied to (by default it’s tied to the global object)
1510 | - The Execution Context consists of the environment (state of variables) of the function currently being evaluated. It also includes ‘this’ and a reference to the outer environment (aka what object is sitting outside this function lexically)
1511 | - The Execution Stack or Call Stack is the “stack” of execution contexts with the global execution context being the bottommost. When the program flow enters a function, a new execution context is popped onto the call stack, and when the function returns, it is popped off.
i. Hoisting
1514 |Before actually executing any of the code, the JS engine first looks at all the variable declarations and function statements and sets aside some memory space for them effectively moving them to the top of the code. This is known as hoisting.
1515 |
// Variable example
1516 |
1517 | function a(){
1518 | console.log(x);
1519 | var x = 2;
1520 | console.log(x);
1521 | }
1522 | a(); // outputs 'undefined' then 2
1523 |
1524 | // Function a is essentially equivalent to:
1525 | function a(){
1526 | var x; // the var declaration is hoisted up to the top and is set to undefined
1527 | console.log(x); // outputs undefined
1528 | x = 2; // the variable assignment stays. It is NOT hoisted.
1529 | console.log(x); // outputs 2
1530 | }
1531 |
1532 | // Function example
1533 |
1534 | a(); // will run properly
1535 | b(); // will fail with TypeError because b isn't assigned until line 4
1536 | function a() { }
1537 | var b = function() { }
1538 |
1539 | The above is equivalent to:
1540 | function a() {} // the function statement is hoisted
1541 | var b;
1542 | a();
1543 | b(); // = undefined(); invoking undefined raises an error
1544 | b = function() {}
1545 |
1546 | JS is always synchronous (executing code 1 line at a time and in-order) and single-threaded (only 1 command at a time). However, jQuery, event handlers and AJAX calls make use of callbacks which appear to run asynchronously. AJAX calls are delegated off to a different part of the browser (outside the JS engine) which is why they are run asynchronously. When the call returns, or if there’s a user click, then these events fill up the Event Queue. The JS Engine only handles the Event Queue when the Execution Stack is empty.
1547 | 1548 |ii. Scope Chain
1549 |To find a variable when functions are running, JS looks further than just the variable environment of the currently executing context, it also looks at the outer environment (the environment to which this function is lexically attached). This process continues looking all the way down to the global environment in a process known as the __scope chain_.
1550 |function b() {
1551 | console.log(myVar);
1552 | }
1553 |
1554 | function a() {
1555 | var myVar = 2;
1556 | b();
1557 | }
1558 |
1559 | var myVar = 1;
1560 | a();
1561 |
1562 | // function b does not have a myVar variable so it looks to its outer environment
1563 | // here, b is lexically attached to the global object, and myVar exists in the global environment
1564 | // therefore, it logs '1'
1565 |
1566 |
1567 | // JavaScript has function scope; functions get their own scope but other blocks
1568 | // do not.
1569 | if (true){
1570 | var i = 5;
1571 | }
1572 | i; // = 5 - not undefined as you'd expect in a block-scoped language
1573 |
1574 |
1575 |
1576 | iii. Closures
1577 |One of JS’s most powerful features is closures. Whenever a function is nested within another function, the inner function has access to all the outer function’s variables even after the outer function exits.
1578 | After the outer function exits, it is popped off the Execution Stack, however if any of its variables are referenced in the inner function, then those variables are “closed into” the inner function’s Execution Context and are accessible by the inner function.
// Example 1
1580 |
1581 | function sayHelloInFiveSeconds(name){
1582 | var prompt = "Hello, " + name + "!";
1583 | // Inner functions are put in the local scope by default, as if they were
1584 | // declared with `var`.
1585 | function inner(){
1586 | alert(prompt);
1587 | }
1588 | setTimeout(inner, 5000);
1589 | // setTimeout is asynchronous, so the sayHelloInFiveSeconds function will
1590 | // exit immediately, and setTimeout will call inner afterwards. However,
1591 | // because inner is "closed over" sayHelloInFiveSeconds, inner still has
1592 | // access to the `prompt` variable when it is finally called.
1593 | }
1594 | sayHelloInFiveSeconds("Adam"); // will open a popup with "Hello, Adam!" in 5s
1595 |
1596 |
1597 | // Example 2
1598 |
1599 | function buildFunctions() {
1600 | var arr = [];
1601 | for (var i = 0; i < 3; i++) {
1602 | arr.push(
1603 | function() {
1604 | console.log(i);
1605 | }
1606 | )
1607 | }
1608 | return arr;
1609 | }
1610 |
1611 | var fs = buildFunctions();
1612 | fs[0]();
1613 | fs[1]();
1614 | fs[2]();
1615 | // all 3 of these will log '3' because after buildFunctions finishes, i = 3
1616 | // when fs[0..2] are invoked, they look for the value of i and they all see 3
1617 |
1618 | // Avoid creating functions in loops. It will lead to bad behaviour.
1619 |
1620 |
1621 |
1622 | iv. Callbacks
1623 |Callbacks are simply functions passed as arguments to other functions to be run when the other functions are finished.
1624 |function alertWhenDone(callback){
1625 | // do some work
1626 | callback(); // invoke the callback right before exiting
1627 | }
1628 |
1629 | alertWhenDone(function(){
1630 | alert("I am done!");
1631 | });
1632 |
1633 | // Callback making use of the JavaScript Timer
1634 | setTimeout(function(){
1635 | alert("3 seconds have passed.");
1636 | }, 3000);
1637 |
1638 |
1639 |
1640 | 5. Object-Oriented JS and Prototypal Inheritance
1641 | 1642 |i. Function Constructors
1643 |When you call a function with the new
keyword, a new object is created in memory, and is made available to the function via the this
keyword. Functions designed to be called like that are called constructors.
1644 |
var MyConstructor = function(){
1645 | // public variables are declared using this
1646 | this.myNumber = 5;
1647 | // private variables are declared using var
1648 | var secretNum = 4;
1649 | // public getter for the private variable
1650 | this.getSecret = function(){ return secretNum };
1651 | }
1652 | myNewObj = new MyConstructor(); // = {myNumber: 5, secretNum: 4}
1653 | myNewObj.myNumber; // = 5
1654 | myNewObj.secretNum; // undefined
1655 | myNewObj.getSecret(); // = 4
1656 |
1657 |
1658 |
1659 | ii. Prototypes
1660 |Every JavaScript object has a ‘prototype’ property, which is simply a reference to another object. When you go to access a property that doesn’t exist on the actual object, the interpreter will look at its prototype. If it doesn’t exist on the prototype, it’ll look at the prototype’s prototype. It will keep looking down this prototype chain until it hits the base object Object, which doesn’t have a prototype.
1661 |
// Some JS implementations let you access an object's prototype on the magic
1662 | // property `__proto__`. While this is useful for explaining prototypes it's not
1663 | // part of the standard; we'll get to standard ways of using prototypes later.
1664 | var myObj = {
1665 | myString: "Hello world!"
1666 | };
1667 | var myPrototype = {
1668 | meaningOfLife: 42,
1669 | myFunc: function(){
1670 | return this.myString.toLowerCase()
1671 | }
1672 | };
1673 |
1674 | myObj.__proto__ = myPrototype;
1675 | myObj.meaningOfLife; // = 42
1676 |
1677 | // This works for functions, too.
1678 | myObj.myFunc(); // = "hello world!"
1679 |
1680 | // Of course, if your property isn't on your prototype, the prototype's
1681 | // prototype is searched, and so on.
1682 | myPrototype.__proto__ = {
1683 | myBoolean: true
1684 | };
1685 | myObj.myBoolean; // = true
1686 |
1687 | // There's no copying involved here; each object stores a reference to its
1688 | // prototype. This means we can alter the prototype and our changes will be
1689 | // reflected everywhere.
1690 | myPrototype.meaningOfLife = 43;
1691 | myObj.meaningOfLife; // = 43
1692 |
1693 |
1694 | iii. Prototypal Inheritance aka setting prototypes of new objects
1695 |Accessing __proto__
is non-standard, and there are no standard ways to change the prototype of an existing object. However, there are two ways to create a new object with a given prototype.
1696 |
// The first is Object.create, which is a recent addition to JS, and therefore
1697 | // not available in all implementations yet.
1698 | var myObj = Object.create(myPrototype);
1699 | myObj.meaningOfLife; // = 43
1700 |
1701 | Every JS function also has a property called ‘prototype’. When used as a normal function, the ‘prototype’ property is not used. Only when functions are used as constructors with the
new
keyword, the ‘prototype’ sets the prototype of the object being created.
1702 | // Constructors have a property called prototype. This is *not* the prototype of
1703 | // the constructor function itself; instead, it's the prototype that new objects
1704 | // are given when they're created with that constructor and the new keyword.
1705 | MyConstructor.prototype = {
1706 | myNumber: 5,
1707 | getMyNumber: function(){
1708 | return this.myNumber;
1709 | }
1710 | };
1711 | var myNewObj2 = new MyConstructor();
1712 | myNewObj2.getMyNumber(); // = 5
1713 | myNewObj2.myNumber = 6
1714 | myNewObj2.getMyNumber(); // = 6
1715 |
1716 |
1717 |
1718 | iv. Built-In Constructors
1719 |// Built-in types like strings and numbers also have constructors that create
1720 | // equivalent wrapper objects.
1721 | var myNumber = 12;
1722 | var myNumberObj = new Number(12);
1723 | myNumber == myNumberObj; // = true
1724 |
1725 | // Except, they aren't exactly equivalent.
1726 | typeof myNumber; // = 'number'
1727 | typeof myNumberObj; // = 'object'
1728 | myNumber === myNumberObj; // = false
1729 | if (0){
1730 | // This code won't execute, because 0 is falsy.
1731 | }
1732 | if (Number(0)){
1733 | // This code *will* execute, because Number(0) is truthy.
1734 | }
1735 |
1736 | // However, the wrapper objects and the regular builtins share a prototype, so
1737 | // you can actually add functionality to a string, for instance.
1738 | String.prototype.firstCharacter = function(){
1739 | return this.charAt(0);
1740 | }
1741 | "abc".firstCharacter(); // = "a"
1742 |
1743 | Polyfilling takes advantage of the fact that we can modify the built-in prototypes to implement newer features of JavaScript in an older subset of JavaScript, so that they can be used in older environments such as outdated browsers.
1744 |
// For instance, Object.create isn't yet available in all
1745 | // implementations, but we can still use it with this polyfill:
1746 | if (Object.create === undefined){ // don't overwrite it if it exists
1747 | Object.create = function(proto){
1748 | // make a temporary constructor with the right prototype
1749 | var Constructor = function(){};
1750 | Constructor.prototype = proto;
1751 | // then use it to create a new, appropriately-prototyped object
1752 | return new Constructor();
1753 | }
1754 | }
1755 |
1756 |
1757 |
1758 | 6. Bugs and Error Handling
1759 |// You can opt in to tell the JS engine to be very strict in its interpretation
1760 | // It must go at the top of the file to interpret the whole file in strict mode
1761 | // Or at the top of a function, to make just that function strict
1762 | "use strict"
1763 |
1764 |
1765 |
1766 | 7. New ES6 stuff
1767 |Arrows
1768 |Arrows are a function shorthands for anonymous functions used with the =>
syntax. They pass the outside lexical scope (ie. this
) to the function.
1769 |
// Expression bodies
1770 | var odds = evens.map(v => v + 1);
1771 | var nums = evens.map((v, i) => v + i);
1772 |
1773 | // Statement bodies
1774 | nums.forEach(v => {
1775 | if (v % 5 === 0)
1776 | fives.push(v);
1777 | });
1778 |
1779 | // Lexical this
1780 | var bob = {
1781 | _name: "Bob",
1782 | _friends: [],
1783 | printFriends() {
1784 | this._friends.forEach(f =>
1785 | console.log(this._name + " knows " + f));
1786 | }
1787 | }
1788 |
1789 | Classes
1790 |Object-oriented syntactic sugar for the prototypal inheritance pattern.
1791 |class SkinnedMesh extends THREE.Mesh {
1792 | constructor(geometry, materials) {
1793 | super(geometry, materials);
1794 |
1795 | this.idMatrix = SkinnedMesh.defaultMatrix();
1796 | this.bones = [];
1797 | this.boneMatrices = [];
1798 | //...
1799 | }
1800 | update(camera) {
1801 | //...
1802 | super.update();
1803 | }
1804 | get boneCount() {
1805 | return this.bones.length;
1806 | }
1807 | set matrixType(matrixType) {
1808 | this.idMatrix = SkinnedMesh[matrixType]();
1809 | }
1810 | static defaultMatrix() {
1811 | return new THREE.Matrix4();
1812 | }
1813 | }
1814 |
1815 |
1816 | String Interpolation
1817 |var name = "Bob", time = "today";
1818 | `Hello ${name}, how are you ${time}?`
1819 |
1820 |
1821 | let
and const
1822 | let
is like var
except it is block-scoped. Variables declared with const
can only be assigned once.
1823 |
if (1 < 2) {
1824 | let i = 4;
1825 | const name = 'Jon Snow'
1826 | }
1827 | var i = 5; // error, i is already defined
1828 | name = 'Samwell Tarly' // error, const can only be defined once
1829 |
1830 | Generator
1831 |Functions that can be paused using the yield
keyword and restarted from the outside. yield _____
is called a “yield expression” which gets evaluated with whatever value we send in when we restart the generator. yield
is making a request for a value.
function* fibonacci() {
1833 | let a = 0, b = 1;
1834 |
1835 | while(true) {
1836 | yield a;
1837 | [a, b] = [b, a + b];
1838 | }
1839 | }
1840 |
1841 | // Enumerates the Fibonacci numbers
1842 | for(let value of fibonacci()) {
1843 | console.log(value);
1844 | }
1845 |
1846 | Generators are useful because they return (i.e. create) iterators. In turn, an iterator, an object with a
next
method, actually executes the body of generators. The next
method, when repeatedly called, partially executes the corresponding generator, gradually advancing through the body until a yield
keyword is hit.
1847 | function* argumentsGenerator() {
1848 | for (let i = 0; i < arguments.length; i += 1) {
1849 | yield arguments[i];
1850 | }
1851 | }
1852 |
1853 | var argumentsIterator = argumentsGenerator('a', 'b', 'c');
1854 |
1855 | // Prints "a b c"
1856 | console.log(
1857 | argumentsIterator.next().value,
1858 | argumentsIterator.next().value,
1859 | argumentsIterator.next().value
1860 | );
1861 |
1862 | // ES6 has syntactic sugar for iteration.
1863 | // Prints "a", "b", "c"
1864 | for(let value of argumentsIterator) {
1865 | console.log(value);
1866 | }
1867 |
1868 | The
next
method of an iterator returns an object with a value
property and a done
property, as long as the body of the corresponding generator has not return
ed. The value
property refers the value yield
ed or return
ed. The done
property is false
up until the generator body return
s, at which point it is true
. If the next
method is called after done
is true
, an error is thrown.
1869 | Maps, Sets, WeakMap, WeakSet
1870 |A Map is an object for which the keys can be any arbitrary object. A Set is a data structure which contains a finite set of elements, each occurring only once. WeakMaps and WeakSets provide leak-free object-key’d side tables. The JavaScript virtual machine periodically frees memory allocated to objects no longer in scope. An object is no longer in scope if there is no chain of references from the current scope leading to it.
1871 |
// Sets
1872 | var s = new Set();
1873 | s.add("hello").add("goodbye").add("hello");
1874 | s.size === 2;
1875 | s.has("hello") === true;
1876 |
1877 | // Maps
1878 | var m = new Map();
1879 | m.set("hello", 42);
1880 | m.set(s, 34);
1881 | m.get(s) == 34;
1882 |
1883 | // Weak Maps
1884 | var wm = new WeakMap();
1885 | wm.set(s, { extra: 42 });
1886 | wm.size === undefined
1887 |
1888 | // Weak Sets
1889 | var ws = new WeakSet();
1890 | ws.add({ data: 42 });
1891 | // Because the added object has no other references, it will not be held in the set
1892 |
1893 | Promises
1894 |Promises are a library for asynchronous programming. Promises are a first class representation of a value that may be made available in the future. A Promise is in one of these states:
1895 | - pending: initial state, not fulfilled or rejected.
1896 | - fulfilled: successful operation
1897 | - rejected: failed operation.
1898 | - settled: the Promise is either fulfilled or rejected, but not pending.
var someAsyncThing = function() {
1900 | return new Promise(function(resolve, reject) {
1901 | // this will throw, x does not exist
1902 | resolve(x + 2);
1903 | });
1904 | };
1905 |
1906 | someAsyncThing().then(function() {
1907 | console.log('everything is great');
1908 | }).catch(function(error) {
1909 | console.log('oh no', error);
1910 | });
1911 |
1912 |
1913 | Modules
1914 |// lib/math.js
1915 | export function sum(x, y) {
1916 | return x + y;
1917 | }
1918 | export var pi = 3.141593;
1919 |
1920 |
// app.js
1921 | import * as math from "lib/math";
1922 | alert("2π = " + math.sum(math.pi, math.pi));
1923 |
1924 |
// otherApp.js
1925 | import {sum, pi} from "lib/math";
1926 | alert("2π = " + sum(pi, pi));
1927 |
1928 | TODO: Proxies, Symbol