100% found this document useful (1 vote)
25K views

Javascript Grammar

Uploaded by

xavierl_1
Copyright
© © All Rights Reserved
Available Formats
Download as PDF or read online on Scribd
100% found this document useful (1 vote)
25K views

Javascript Grammar

Uploaded by

xavierl_1
Copyright
© © All Rights Reserved
Available Formats
Download as PDF or read online on Scribd
You are on page 1/ 246
JAVASCRIPT GRAMMAR JAVASCRIPT GRAMMAR JavaScript Grammar - Edition | - March 23, 2019 JavaScript Grammar I= March 23, 2019 Genre: Software Development Publisher: Learning Curve Books Imprint: Independently published ISB 9781091212169 Author: Greg Sidelnikov (greg [email protected]) Editors, volunteers, contributors: Grace Neufeld. Primary purpose of Learning Curve Books publishing company is to provide effective education for web designers, software engineers and all readers who are interested in being edified in the area of web development. This edition of JavaScript Grammar was created to speed up the learning process of JavaScript — the language for programming websites, applications and robots! For questions and comments about the book you may contact the author or send an email directly to our office at the email address mentioned below Special Offers & Discounts Available Schools, libraries and educational organizations may qualify for special prices. Get in touch with our distribution department at [email protected] . nm Learning Curve Books Learning Curve Books is a registered trademark of Learning Curve Books, LLC License is required to distribute this volume in any form regardless of format or price. All graphics and content is copyright of Learning Curve Books, LLC. unless where otherwise stated ©2018 - 2019 Learning Curve Books, LLC. JavaScript Grammar 0.1 Foreword 1 Presentation Format 1.1 Creative Communication 11.1 Theory 1.1.2 Practical Examples 1.1.3 Source Code . 1.1.4 Color-Coded Diagrams 1.1.5 Dos and Dont’s 2 Chrome Console 2.0.1 Beyond Console Log 2.0.2 console.dir 2.0.3 console.error 2.0.4 console.time() and console.timeEnd() 2.0.5 console.clear . 3 > Welcome To JavaScript 3.1. Entry Point 3.1.1 Dos and Dont's CAAA AGH © 10 lL iL 12 13 13 14 3.1.2 Dynamic Import 3.2 Strict Mode 3.3 Literal Values 3.4 Variables 3.5. Passing Values By Reference 3.6 Scope Quirks 4 Statements 4.0.1 4.0.2 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.0.10 Executing Methods On Primitive Types . Evaluating Statements Expressions boolean null undefined number bigint typeof string Template Strings Symbol 6 Type Coercion Madness 6.0.1 Examples of Type Coercion 19 19 21 23 25 26 29 29 31 33 35 35 35 36 37 38 39 40 42 48 49 50 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 7 Scope 7.0.1 Adding Multiple Values Operator Precedence String To Number Comparison Operator Precedence & Associativity Table Lvalue and R-value mull vs undef ined Scope 7.1 Variable Definitions Tl 7.1.2 713 714 715 71.6 8 Operators 8.0.1 8.0.2 8.0.3 8.0.4 8.05 8.0.6 8.0.7 8.0.8 Variable Types Scope Visibility Differences const . const and Arrays const and Object Literals Dos and Dont's Arithmetic Assignment String Comparison Logical Bitwise typeof Ternary (?:) 55 55 56 58 60 61 63 64 64 2 72 78 78 78 79 81 81 83 83 84 84 85 86 87 8.0.9 delete 8.0.10 in 9 ...rest and ...spread 9.0.1 Rest Properties 9.0.2 Spread Properties 9.0.3. ...rest and ...spread 9.1. Destructuring Assignment 10 Closure 10.0.1 Arity 10.0.2. Currying 11 Loops 11.0.1 Types of loops in JavaScript 11.1 for loops 11.1.1 O-index based counter 11.1.2 The Infinite for Loop 11.1.3 Multiple Statements 11.2 for...of Loop 11.2.1 for...of and Generators 11.2.2 for...of and Strings . 11.2.3. for...of and Arrays 11.2.4 for...of and Objects 11.2.5 for...of loops and objects converted to iterables 11.3 for...in Loops 11.4 While Loops 87 87 89 89 91 91 96 101 109 109 lil 1 114 114 114 115 120 120 122 122 123 124 125 125 11.4.1 While and continue 12 Arrays 12.0.1 Array.prototype.sort() 12.0.2 Array.forEach 12.0.3 Array.every 12.0.4 Array.some 12.0.5 Array-filter 12.0.6 Array.map 12.0.7 Array.reduce . 12.0.8 Practical Reducer Ideas 12.0.9 Dos and Dont's 12.0.10 Array flat() 12.0.11 Array.flatMap() 12.0.12 String. prototype.matchAlll() 12.0.13 Dos and Dont's 12.0.14 Comparing Two Objects . 12.0.15 Writing arremp 12.0.16 Improving objcmp 12.0.17 Testing objcmp on a more complex object 13 Functions 13.1 Functions 13.1.1 Function Anatomy . 126 129 129 131 132 133 133 134 134 135 136 138 138 139 143 144 146 147 148 151 151 152 13.1.2 Anonymous Functions 13.1.3 Assigning Functions To Variables 13.2 Origin of this keyword 14 Higher-order Functions 14.0.1 Theory 14.0.2 Definition 14.03 Abstract 14.0.4 Iterators 14.0.5 Dos and Dont’s 15 Arrow Functions 15.0.1 Arrow Function Anatomy 16 Creating HTML Elements Dynamically 16.0.1 Setting CSS Style 16.0.2 Adding Elements To DOM with .appendChild method 16.0.3 Writing A Function To Create Elements . . 16.0.4 Creating objects using function constructors 17 Prototype 17.0.1 Prototype 17.0.2 Prototype on Object Literal 17.0.3. Prototype Link 17.0.4 Prototype Chain 17.0.5 Method look-up. 17.0.6 Array methods 153 153 158 159 159 161 161 162 166 167 170 179 180 181 182 186 187 188 189 190 191 192 192 17.1 Parenting 194 17.1.1 Extending Your Own Objects bese e 194 17.1.2. constructor property 195 17.1.3 Function 196 17.2 Prototype In Practice... .. bees 197 17.2.1 Object Literal 197 17.2.2 Using Function Constructor 199 17.23 Prototype ........... bee 200 17.2.4 Creating objects using Object.create : 201 17.2.5 Back To The Future 202 17.2.6 Function Constructor. . amas 203 17.2.7 Along came new operator 205 17.28 The class keyword 206 18 Object Oriented Programming 207 18.1 Ingredient. er sass 207 18.2 FoodFactory .............. Bais 3 208 18.3 Vessel 208 18.4 Burner bee bee 209 18.5 Range Type and The Polymorphic Oven bee 210 18.6 Class Definitions 211 18.6.1 printjs.... 2.0.0... bee 211 18.6.2 Ingredient .. 2... bee eee e 212 18.6.3 FoodFactory 212 18.6.4 Fridge w a = “ « « 213 18.6.5 convert.energy to-heat 18.6.6 Vessel 18.6.7 Burner 18.6.8 Range one 18.6.9 Putting It All Together 19 Event Loop 20 Call Stack 20.1 Execution Context 20.2 Execution Context In Code 20.2.1 Window / Global Scope 20.2.2 The Call Stack 20.2.3 .call(), .bind(), .apply() 20.2.4 Stack Overflow 214 215 2u7 218 221 225 229 231 232 233 233 236 237 0.1 Foreword We often think of the word " feature” as something that belongs to software prod- ucts and services. Modern apps such as Instagram and Twitter have a " Follow” feature, for example. Uploading a photo to your account is another feature! But computer languages have features too. A function is a feature. A for loop is a feature. So is the class keyword ~ all are computer language features. In JavaScript some of these features are borrowed from other languages, while many remain unique to its own design. Features such as this, class and const may appear similar to their original C++ implementation, but in many cases they are used in a completely unique way to JavaScript. JavaScript is an evolving language. When EcmaScript 6 came out in June 2015 the language experienced a Cambrian explosion of new features that radically changed how JavaScript code should be written New features like ...rest and ...spread syntax, arrow functions, template strings, object destructuring are commonplace in modern JavaScript code. But just a few years ago, even seasoned JavaScript developers with over a decade experience with the language couldn't conceive of such concepts. Functional Programming started to creep into JavaScript community seemingly at the speed of light and higher-order functions (.map, .filter, reduce) tied to Array methods, that remained dormant for many years, have gained increased popularity, But JavaScript is a multi-paradigm language. Programmers who come from tra- ditional Object Oriented Programming background will find themselves at home after induction of the class keyword and a separate constructor function that provides an alternative to the classic JavaScript object-function constructors. The ES6 specification triggered a whole new breed of coders who have developed more respect for a language that once was used to write primitive DOM scripts. JavaScript engines that run in browsers (Chrome browser's V8, for example) have matured and JavaScript is no longer looked at as a simple scripting language. It's a whole new era of JavaScript development. Today, you may often stumble upon a video titled Build a robot with JavaScript on YouTube. It is even possible to build desktop applications for Windows 10 almost entirely in JavaScript. 2 JavaScript frameworks and libraries like React and Vue abstract away some of the classic JavaScript principles, making it quicker to build modular applications. But this often comes at the expense of never having to understand vanilla JavaScript at the beginner level — its common grammar. JavaScript Grammar was written to solve this problem by using carefully chosen subjects that, hopefully, match a natural learning experience. Content of this book will try to remain faithful to dynamic nature of JavaScript specification Finally, it is hoped that this book will encourage the reader to take the next step in the direction of more advanced subjects in the future. Chapter 1 Presentation Format This book was structured with continuity in mind: it is meant to be read from first to last page in a consecutive order. However, it can also be used as a desk reference for looking up isolated examples when you need them. JavaScript Grammar is not a complete JavaScript reference or manual. But, this is probably a good thing, The subjects were reduced to only what's important in modern-day JavaScript environment. Namely: imports, classes, constructors, key principles behind functional program- ming, including many features ranging from ES5 - ES10 are covered in this book. The distinction between "ES" specifications has become less relevant. Al of it is JavaScript. But just to give the reader a bit of perspective... Sometimes you will see labels like this one. This simply means that this feature was added to JavaScript as part of the Ec- maScript’s ES10 specification. 1.1. Creative Communication Some of JavaScript is easy, some of it is difficult. Not everything can be explained by source code alone. Some things are based on intangible ideas or principles. 5 Throughout this tutorial book you will come across many creative communication devices, designed to make the learning process a bit easier and perhaps more fun. One example of that is color-coded diagrams. 1.1.1 Theory Not all subjects require extensive theory. On the other hand, some things won't make any sense without it. Additional discussion will be included, where it becomes absolutely necessary, in order to fully understand a particular concept 1.1.2 Practical Examples A practical example follows the theoretical discussion, so we can actually see the plementation. It will usually be explained by a source code listing, 1.1.3. Source Code Source code listings will be provided to cement the foundational principles from preceding text. 054| // Create (instantiate) a sparrow from class Bird 055 let sparrow = new Bird("sparrow", "gray"); 056 sparrow. fly()3 057 Sparrow.walk() ; 058 sparrow. lay_egg(); 059 Sparrow.talk(); // Error, only Parrot can talk This is an example of instantiating sparrow object from Bird class and using some of its methods. 1.1.4 Color-Coded Diagrams A significant amount of effort went into creating diagrams describing fundamental ideas behind JavaScript. They were designed for communicative value, hopefully 6 they will speed up the learning process in places where hard to grasp abstract ideas need to be explained visually. ‘There are two types of diagrams in this book: abstract ideas and source code close ins Abstract ideas Sometimes there isn’t a way to explain an abstract idea or its structure without a diagram. In places where that's the case, a diagram will be shown f Function Class.constructor Figure 1.1: Class constructor is an object-function of type Function. Here is another diagram visualizing anatomy of a JavaScript function: arguments name C, 0 default parameter function update (a,b,¢,d = parameters {—a37 bf ost 3 hi" arguments; array-like object of arguments [7,[],{},"hi"] this; context: window or abject instance return true; return value Figure 1.2: JavaScript function anatomy. 7 Code close Most of the source code is accompanied by source code listings. But when we need to close in on a particular important subject, a slightly larger diagram with source code and additional color-coded highlighting will be shown For example, here is exploration of an anonymous function when used in the context of a event callback function setTimeout(function() { console.log("Print something in 1 second. console. log (arguments) ; 3, 1000); Figure 1.3: Anonymous function used as a set Timeout event callback In this case the source code will be missing line numbers because it's not important. Content We won't spend much book space or your time on countless listings of functions and available methods on every single object. This type of information can be easily looked up and practiced online on demand from Mozilla's MDN web docs, W3Schools and StackOverflow. Much of content of this book is tailored to modern JavaScript development, which leans toward >= EcmaScript6 specification, functional programming: the use of higher-order Array functions, arrow functions and understanding execution context. 1.1.5 Dos and Dont’s An occasional Dos and Donts section will appear with insightful tips. Chapter 2 Chrome Console 2.0.1 Beyond Console Log Many programmers only know Chrome’s console. log but the console API con- tains few other methods that have practical use, especially when time is of essence. copy(obj) function Copying JSON representation of an existing object to your copy buffer: > let x = { property: 1, propi: 2, method: function(){} }5 > copy(x)s >| Now the JSON is in your copy-paste buffer, you can paste it into any text editor. In this example x is a simple self-created object. But imagine a situation where a much more complex object is returned from a database API Note: Only JSON is returned, this means that methods will not make it to the copy buffer. (JSON string format does not support methods, only properties.) 9 2.0.2 _console.dir If you want to take a look at all object's properties and methods, you can print it out directly into the console using console.dir method > console. din(x); vobject > method: £ () propi: 2 property: 1 > __proto_: Object >| What's fantastic is that you can even output DOM elements: > console. dir (document. body) ; accesskey: assignedSlot: null » attributestyleMap: StylePropertyMap {size: 0} > attributes: NamedNodeMap {length: o} autocapitalize: "" background: "" baseURI: “http: //localhost/experiments/ javascript .html" bgcolor: "" 10 2.0.3 console.error 001 let fuel = 995 002 function launch_rocket() { 003 function warning_msg() { 004 console.error("Not enough fuel." 005} 006 if (fuel >= 100) { 007 // looks Like everything's ok 00g =} else 009 warning_msg()5 o10 } 011 012 launch_rocket(); The great thing about console. error is that it also provides the stack trace: © vNot enough fuel. warning_msg @ javascript-x.html:9 launch_rocket @ javascript-x.html:14 (anonymous) @ javascript-x. htm]:17 >| 2.0.4 console.time() and console.timeEnd() You can track the amount of time between function calls. This can be helpful when optimizing code 002 let arr = new Array(16000) ; 003 for (let 1 = 0; 1 < arr.length; i++) { 004) arr{i] = new Object()5 005| } Console output: : 2.51708984375ms 2.0.5 console.clear Console was cleared undefined >| Printing Objects In JavaScript all objects have .toString() method. When providing an object to console. log(value) it can print it either as an object, or as a string 001 let obj = {35 002 console. log (obj) ; J obj 003 console. log("object = " + obj); // [object Object] 004 console. log(* ${obj}"); // [object Object] 12 Chapter 3 Welcome To JavaScript 3.1 Entry Point Every computer program has an entry point. You can start writing your code directly into 010° 011, 012) Figure 3.1: Here the entry point is your own custom function load(). This is a good place for initializing your application objects You can rename the load function to start, ready or initialize — it doesn't matter. What matters is that at this entry point we're 100% guaranteed that all DOM elements have been successfully loaded into memory and trying to access them with JavaScript will not produce an error. 3.1.1 Dos and Dont’s Do not write your code just in 015, 016 017) Figure 3.2: Check document .readyState DOM vs Media We've just created a safe place for initializing our application. But because DOM is simply a tree-like structure of all HTML elements on the page, it usually becomes available before the rest of the media such as images and various embeds. Even though is a DOM element, the URL con- tent specified in image's src attribute might take more time to load. To check if any non-DOM media content has finished downloading we can overload the native window.onload event as shown in the following example. 15 window.onload With window.onload method, you can wait until all images and similar media have been fully downloaded: 001) 002 003 Window Media Loaded. 004 009 010 o1z| Including External Scripts Let's say we have the following definitions in my-script.. js file 001) let variable = 15 002 function myfunction() { return 2; } Then you can add them into your main application file as follows: 002| 002, 003 Include External Script 00a ous 010 011, 012| Main JavaScript application file - index.html, for example 16 Import Starting from ES6 we should use import (and export) keyword to import variables, functions and classes from an external file. Let's say we have a file mouse . js and it has following definition of a Mouse class. 001| export function Mouse() { this.x = 0; this.y = 6; } In order to make a variable, object or a function available for export, the export keyword must be prepended to its definition. But that's not enough! The Mouse constructor function will be exported as long as a matching import is available in main application file Not everything in a module will be exported. Some of the items will (and should) remain private to it. Be sure to prepend export keyword to anything you want to export from the file. This can be any named definition. script type = "module” In order to export the Mouse class and start using it in the application, we must make sure the script tag's type attribute is changed to" module” (this is required.) ao1| 002 003 Import Module 04 008 009, 010) Figure 3.3: Now we can safely access Mouse class, instantiate a new object from it and access its properties and methods. 17 Importing And Exp ig Multiple Definitions It's uncommon for a complex program to import only one class, function or variable. Here is an example of how to port multiple items from two imaginary files. 001) import { Mouse, Keyboard } from "./input. js"; 002 import { add, subtract, divide, multiply } from ". /math.j 003 004 // Initialize mouse object and access mouse position 005 let mouse = new Mouse(); 006 mouse.x; // 256 007 mouse.y; /f 128 008 009| // Initialize Keyboard class and check if shift is pressed 010 let keyboard = new Keyboard(); 011 keyboard.shiftIsPressed; // false 012 013| // Use math functions from math library file o1a add(2, 5); wt 015 subtract(10, 5); // 5 o16 divide(1o, 5)3 // 2 017 multiply(4, 2); // 8 The Mouse and Keyboard classes were imported together (separated by comma) from input,js file. They were instantiated as separate objects then and their properties were accessed to grab some data We've also imported some math functions add, subtract, divide and multiply from math.js. The math library file source code is shown below. After defining 4 functions we can export multiple definitions as follows: 002) // A collection of math functions 002 function add(a,b) { return a + b; } 003 function subtract(a,b) { return a - b; } 004 function divide(a,b) { return a / b; } 005 function multiply(a,b) { return a + b; } 006 007 // Export multiple items 00a export { add, subtract, divide, multiply } Figure 3.4: Exporting multiple definitions from math. js 18 3.1.2 Dynamic Import Imports can be assigned to a variable since EcmaScript 10 (may not be available in your browser yet, at the time of this writing.) 001) element. addEventListener(‘click', async () => { 002, const module = await import('./api-scripts/click. js"); 003 module.clickEvent() ; 004 #)3 3.2 Strict Mode The strict mode is a feature available since ECMAScript 5 that allows you to place your entire program, or an isolated scope, in a “strict” operating context. This strict context prevents certain actions from being taken and throws an exception. For example, in strict mode you cannot use undeclared variables. Without strict mode, using an undeclared variable will automatically create that variable. Without strict mode, certain statements might not generate an error at all ~ even if they are not allowed — but you wouldn't know something was wrong. 001 var variable = 1; 002 003 delete variable; // false Figure 3.5: You cannot use delete keyword to delete variables in JavaScript Without strict mode on, code above will fail silently, variable will not be deleted, and delete variable will return false but your program will continue to run But what will happen in strict mode? 19 001| "use strict"; 002 003 var variable = 1 004 005 delete variable; // syntaxkrror Figure 3.6: In this example strict mode is enabled for entire global scope © Uncaught SyntaxError: Delete of an unqualified identifier in strict mode. >| Figure 3.7: In strict mode you will generally become aware of more errors. For example, the line delete variable can be removed completely without having any impact on the program. Limiting "strict mode” To A Scope The strict mode doesn't have to be enabled globally. It is possible to isolate a single block (or function) scope to strict mode: Final Words In a professional environment, it is common to have strict mode on, because it can potentially prevent many bugs from happening and generally supports better software practice. 20 3.3 Literal Values The literal representation of a number can be the digit 1, 25, 100 and so on. A string literal can be "some text"; You can combine literals using operators (+,-,/,#, etc.) to produce a single result. For example, to perform a 5 + 2 operation, you will simply use the literal number values 5 and 2 001| // Add two numberic Literals to produce 7: 002 5 + 2; 7 Combine two strings to produce a single sentence: 001) // Add two strings to produce a sentence: 002 "Hello" +" there."5 "Hello there." Add two literal values of different types to produce a coerced value 001 // Adding string to number to produce coerced value 002 “username” + 25747315 "username2574731" There is a literal value for just about everything in JavaScript: 13 // numeric Literal “some text."5 1/ string literal 03 // array literal ths // object Literal true; 7/ boolean literal function() {}5 // function is a value There is an array literal (] and object literal {} You can add {} + (J without breaking the program, but the results will not be meaningful. These types of cases are usually non-existent. Note that a JavaScript function can be used as a value. You can even pass them into other functions as an argument. We don't usually refer to them as function literals, however, but rather function expressions. at Each literal value usually has a constructor function associated with it. value typeof constructor 1 “number Number() 3.14 number" Number() some text. ‘string’ ‘String() >O ‘object’ Array() 7 “object’ object() true "boolean" Boolean ) £ FOO ‘function’ Function() The typeof function can be used to determine type of the literal. For exam- ple typeof 1 will return string "number", and typeof {} will return string "object". This doesn't mean, however that its an object-literal (for example typeof new Array also returns "object" as does typeof new Number.) It's a bit unfortunate that there is no "array" (you will get "object" instead), but there is a classic workaround. To check if a value is an array, check if its typeof returns "object", but also check for presence of length property — because it exists only on objects of type Array. You can instantiate a value using its constructor function. But that's rather un- common practice. Most of the time you will define basic values using their literal notation. aa 3.4 Variables Value Placeholders Variables are placeholder names for different types of values. Definition Figure 3.8: Variable declaration is definition + assignment. a Assignment Keywords for defining variables include: var, let and const: but they don't determine variables type, only how they can be used. We'll go over the rules i more detail at a later time. Here are some examples: 002 002 003 004 005 006 007 008 009 010 our 012 013 014 var legacy = 13 let let let let let let let let let let let let let numb stri arra\ obje json json; bool inf func uW er = 13 MW ng "Hello."5 Mt y = 5 i ct = fa:dds i (tamsa}5 i 2 = {Mahid}s WW ean = true; WW = Infinity; VW function(a) {return a}3// (a) => a}; if a> as WW new Number (1) ; " new Object() 5 "W using legacy var keyword assign assign assign assign assign assign assign assign assign assign assign assign assign a number a string an array literal object literal ISONA (object) ISON2 (string) boolean ‘infinity (number) a function arrow function arrow expression number object blank object Figure 3.9: Here are some of the most common assignments you will come across When you assign 1 to a variable name the type of that variable automatically becomes" number”. If the value were a string, the variable type would be “string” 23 Dynamic Typing JavaScript is a dynamically-typed language. It means that variables created using var or let keywords can be dynamically re-assigned to a value of another type at some point later in your JavaScript program In statically-typed languages doing that would generate an error. Definition Or Declaration? In the previous diagram we looked at a JavaScript variable declaration Some will argue that the definition is the declaration. But this type of logic comes from statically typed languages, of which JavaScript is not. In statically typed languages the declaration determines the type of the variable ~ it's what the compiler needs to allocate memory for the variable type (left hand side). But JavaScript is a dynamically typed language — the variable type is determined by the the type of value itself (right hand side). Hence, the confusion. Is the left side the declaration, definition or both? These types of details are more relevant in statically typed languages, but in JavaScript it might not make much sense. 24 3.5 Passing Values By Reference Copying data from place to place is a commen operation in computing. It is natural to think that when we assign a value to a variable from another variable, a copy is made. But JavaScript assigns values by reference without actually making a copy of the original value. Here is an example: oor tet x = { ps 1}; // create new variable x 002 let y = x; // y is a reference to x 003 x.p = 27 // change original value in x 004 console.log(y-p); M2 Here we created a variable x and assigned object literal {p: 1} to it This means that from now on the value of x.p will be equal 1; We then created a new variable called y, and assigned x to it. Now x has become a reference to y, not a copy. From now on, any changes made to x will be also reflected in y. This is why when we changed value of x.p to 2, y.p was also changed You can say that now y "points" to the original object-literal defined in x. Only one copy of {p: 1} existed in computer memory all along from start to finish of this code block. Multiple assignments are chained by reference: oor let a= { pt 1}; // create new variable a 002 // » is a reference to a 003 ova 005 006 007 008 009 o10 011 console.log(g.p) + // § now also in g // change original value in a Figure 3.10: A chain of references without a single copy of original value. 25 3.6 Scope Quirks JavaScript has two known quirks when it comes to scope rules, that you might want to know about to save debugging time later. Quirk 1 — let and const inside function vs. global variable A variable defined using let or const keywords inside a function cannot coexist with global variable of the same name. 001/let a = "global a"; 002 let b = "global b"; 003 004 function x(){ 005, console. log("x(): global b 006 console. log("x(): global a 007) let a = 13 // doesn't hoist 008 } 009 010, x()5 +b); // "global b" + a); // Referencetrror Figure 3.11: ReferenceError will happen if local variable a is defined inside the function body using either let or const keywords. The let keyword doesn't hoist definitions, and we have a global variable a, so logically, inside function x() variable a should be taken from global scope, before it is defined later with let a = 1 but that's not what happens. If variable a already exists inside a function (and it's defined using let or const keywords) then using a, prior its definition within the function will produce Refer- enceError, even if global variable a exists! 26 Quirk 2 — var latches onto idow/this object, let and const don’t In global scope this reference points to instance of window object / global context. When variables are defined using var keyword they become attached to window object, but variables defined using let (and const) are not. oor 002 003 004 005 006 007 008 009 010 our 012 console. var ¢ let d = console. console. console. console. console. console. log(this window); // window "M5 // latches on to window ("this in global scope) "a"; // exists separately from "this" log(c) 5 Jj see log(this.c); 1/7 "ce" og(window.c); // "c" log(d) 5 // "a" log(this.d); // undefined log(window.d); // undefined 27 28 Chapter 4 Statements 4.0.1 Evaluating Statements A statement is the smallest building block of a computer program. In this chapter we will explore a few common cases Definitions made with var, let or const keywords return undef ined because they behave only as value assignments: the value is simply stored in the variable name: 001 let a= 15 // undefined Figure 4.1: The assignments statement itself produces undefined, while the value is stored in variable a If, however, the assigned variable a is used as a stand-alone statement afterwards, it will produce value of 1: 002 a; Wr Figure 4.2: A statement that produces a single value other than undefined can be referred to as an expression. 29 Statements usually produce a value. But when there isn’t anything to return, a statements will evaluate to undefined, which can be interpreted as "no value.” ‘Statement. Evaluates to ool 5 // undefined 02 1; 1 003 "text"; ff "text" oo4 [15 wu oos {35 /{ undefined 006 let as // undefined 007 let as // undefined 008 let c = {t; /f undefined 009 let d = new String("text"); // undefined 010 let e = new Number (125); // undefined 011 new String("text") 5 11 "text" 012 new Number (125); 7/125 013 let f = function() { return 1 }; /{ undefined 014 f(); Wi. 015 let o = (a, b) => a + b; // undefined 016 0(1, 2)5 1/3 017 function name() {} // undefined Figure 4.3: An empty statement with semicolon evaluates to undefined. Any statement that doesn’t produce a value will evaluate to undefined — variable assignments (006-010) or function definitions (017), for example. Some evaluation rules make sense, but special cases should probably be just mem- orized. For example, what would it mean to evaluate an empty object /iteral? According to JavaScript it should evaluate to undef ined. Yet, empty array brackets [] (a close relative to empty object literal) evaluate to an empty array: [], and not undefined. 30 4.0.2 Expressions Here is an expression: 1 + 1 that produces the value of 2: oo3|1 + 15 ES Figure 4.4: Expressions don't have to be variable definitions. You can create them by simply using some literal values in combination with operators. There is another distinct types of an expression in JavaScript: 013 let f = function() { return 1 }; // undefined 01a ()5 Wa Function £() evaluates to value 4, because it returns 1. This is why £() is often referred to as a function expression. at 32 Chapter 5 Primitive Types 33 Primitive Types JavaScript has 7 primitive types: null, undefined, number, bigint, string, boolean and symbol. Primitives helps us work with simple values such as strings, numbers and booleans. Let's take a look at some of their possible values type values constructor function null null none undefined undefined none number 123 3.14 Number () bigint 123n 256n BigInt() string "Hello" string() boolean true false Boolean() symbol none Some of the primitives have a constructor function associated Here's a number of primitives assigned to several variable names: 001) let a = undefined; // undefined o02 let b = null; 7/ mutt 003, let ¢ = 12; // integer number 004 let d = 4.13; // floating point number 005 let e = 160n; // big integer (values over 2%) 006 let f = "Hello."; // text string 007 let g = Symbol (); // create symbol 008 console. log(typeof f); 7f "symbol" Numbers, strings and booleans are basic value units. You can write them out in literal form: a number can be 123 or 3.14, a string can be "string", or a template string: ‘I have {$number} apples.‘ (note the back-tick quotes, which allow you to embed variables into the string dynamically.) A boolean can only be either true or false. You can combine primitive types using operators, pass them to functions or assign them as values to object properties. Number(), Bigint(), String() and Boolean() are primitive constructor func- tions. We'll explore constructor functions and classes at a proper time in the book. First, let's briefly go over each primitive individually. 34 5.0.1 boolean possible values true false The boolean primitive can be assigned either true or false value. typeof constructor "boolean" string new Boolean(value) 5.0.2 null typeof constructor "object" strin none Running typeof operator on nulll will say it's an “object”. Some believe this is a bug in JavaScript because null is not an object since it doesn't have a constructor. And they are probably right... 5.0.3 undefined typeof constructor "undefined" string none Undefined is a type of its own. It's not an object. Just a value JavaScript will use when you named a variable but don't assign a value to it. Your hoisted variables will also be automatically assigned a value of undefined. 35 5.0.4 number possible values -1 5 7 1.14 9,66e+0 Infinity -Infinity NaN The number primitive helps us work with values in the numeric domain. You can define negative and positive values, decimals (more commonly known as floating-point numbers.) There is even a negative and positive Infinity value This makes more sense if you have some background in math NaN is technically a non-numeric value a statement can evaluate to. It’s available directly from the Number. NaN But literally, it is exactly what it says it is: neither "number" primitive nor Number () object. (It could be a "string", for example.) typeof constructor "number" string new Number (value) Using typeof operator on a numeric value will produce "number" (It helps to note that the return value is in string format.) 001) // The typeof operator returns value type in string format 002 typeot -15 “number” 003 typeof 5; “number” 004 typeof 7} “number” 005 006 //Using Number constructor function to create a number 007 let number = new Number(7); "object" 008 typeof number; "object" 009) typeof number. valuedf(); "number" This example shows distinction between primitive /iteral value (-1, 5, 7, etc.) and the Number object. Once instantiated, the value is no longer exactly a literal but an object of that type. To get "number” type from the object use typeof on the value0f method as seen in the previous example typeof number .valueOf () ; 36, 5.0.5 bigint value In 32000n 9007199254740991n 9007199254740993 BigInt was added in EcmaScript10 and wasn’t available until Summer 2019. In the past the maximum value of a number created using a number literal or the Number() constructor was stored in Number .MAX_SAFE_INTEGER and was equal to 9007199254740991. A bigint type allows you to specify numbers greater than Number . MAX SAFE_INTEGER typeof constructor "bigint" string new BigInt (value) 001| const Limit = Number .MAX_SAFE_INTEGER; 002 // 9807199254740991 003 004 Limit + 15 005 // 9007199254740992 006 007 Limit + 25 oo8 // Still 9007199254740992 (exceeded MAX_SAFE_INTEGER + 1) 009 010 const small = 1n; // In 011 const larger = 9007199254740991n; // 9007199254740991n o12 013 const integer = BigInt(9@07199254749991); // init as number 014 // 9007199254740991n o1s 016 const big = BigInt("9007199254740991"); // init as string 017 // 9007199254749991n os o19 big + 1; 020 // 9007199254740993n - exceeds older numeric Limit 37 5.0.6 typeof Difference between numeric types: 001 typeof 10; // 'number' 002) typeof 10n; // 'bigint! Equality operators can be used between the two types 001| 1en 002 16n = Bigint(10); // true 105 // true Math operators only work within their own type 001 20@n / 10n; // 26n 002) 266n / 26; // Uncaught TypeError: 003, // Cannot mix BigInt and other types, 04 /{ use explicit conversions Leading - works, but + doesn’t 001| -100n // -10n 002 +4100n // Uncaught TypeError: 003 // Cannot convert a BigInt value to a number 38 5.0.7 string value "text" ‘text’ “text> “Cat "Felix" knows best* The string value is defined using any of the available quote characters: double quotes, single quotes, and back-tick quotes (Located on tilde key.) You can nest double quotes inside single quotes, and the other way around. typeof constructor Ustring" string new String(value) Running typeof on a string value returns "string" 001| // The typeof operator returns value type in string format 002 typeof "text"; "string" 003 typeof "JavaScript Grammar"; “string” 004 typeof "username" + 25; "string" You can also use String constructor function to build an object of string type 001) // Using Number constructor creates an object of that type 002 let string = new String("hi."); "object" 003 typeof string; “object” 004, typeof string. valueof(); "string" Note that the first typeof returns "object", because at this point the object is instantiated (this is different from the primitive’s literal value which is still just a "string" primitive). To get the value of the instantiated object use valueOf () method and use typeof string. valueOf() to determine the object’s type 39 5.0.8 Template Strings Strings defined using the backtick quotes have special function You can use them to create Template Strings (also known as Template Literals) to embed dynamic variable values inside the string: Define a variable: let apples = 10; Embed variable inside template string: “There are ${apples} apples in the basket.” Result: There are 10 apples in the basket. The back-tick cannot be used to define an object-literal property name (You still have to use either single or double quotes.) JSON format requires double quotes around object's property names (back-ticks won't do any good here either, without generating an error) 001) // Attempt creating an object literal 002 let object_literal = {\a° : 1}; // Unexpected token error 003 004 // Attempt creating a well-formed JSON format string: 005 let jsoni = ’{*a° : 1}? // malformed json(back-tick quotes) 006 let json2 = *{ a : 1}? // malformed json(no quotes) 007/ let json3 = "{’a’ : 1}"; // malformed json(single quotes) :1}3 // correct json (? + double quotes) 008 let jsona = *{"a" 009 let jsons = *{"a" : 1}"3 // correct json (* + double quotes) We'll take a look at JSON in greater detail in a later chapter. Creative Use Case Template strings can be used to solve the problem of forming a message that has proper language form, based on a dynamic number, One of the classic cases is forming an alert message sentence. 40

You might also like