Discover millions of audiobooks, ebooks, and so much more with a free trial

From $11.99/month after trial. Cancel anytime.

Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers
Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers
Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers
Ebook673 pages5 hours

Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers

Rating: 4 out of 5 stars

4/5

()

Read preview

About this ebook

ECMAScript 6 represents the biggest update to the core of JavaScript in the history of the language. In Understanding ECMAScript 6, expert developer Nicholas C. Zakas provides a complete guide to the object types, syntax, and other exciting changes that ECMAScript 6 brings to JavaScript. Every chapter is packed with example code that works in any JavaScript environment so you’ll be able to see new features in action.

You’ll learn:
–How ECMAScript 6 class syntax relates to more familiar JavaScript concepts
–What makes iterators and generators useful
–How arrow functions differ from regular functions
–Ways to store data with sets, maps, and more
–The power of inheritance
–How to improve asynchronous programming with promises
–How modules change the way you organize code


Whether you’re a web developer or a Node.js developer, you’ll find Understanding ECMAScript 6 indispensable on your journey from ECMAScript 5 to ECMAScript 6.
LanguageEnglish
PublisherNo Starch Press
Release dateAug 16, 2016
ISBN9781593277987
Understanding ECMAScript 6: The Definitive Guide for JavaScript Developers
Author

Nicholas C. Zakas

Nicholas C. Zakas is a front-end consultant, author, and speaker. He worked at Yahoo! for almost five years, where he was front-end tech lead for the Yahoo! homepage and a contributor to the YUI library. He is the author of Professional JavaScript for Web Developers (Wrox, 2012), Professional Ajax (Wrox, 2007), and High Performance JavaScript(O’Reilly, 2010). Nicholas is a strong advocate for development best practices including progressive enhancement, accessibility, performance, scalability, and maintainability. He blogs regularly at http://www.nczonline.net/ and can be found on Twitter via @slicknet.

Read more from Nicholas C. Zakas

Related to Understanding ECMAScript 6

Related ebooks

Programming For You

View More

Reviews for Understanding ECMAScript 6

Rating: 3.9 out of 5 stars
4/5

5 ratings0 reviews

What did you think?

Tap to rate

Review must be at least 10 words

    Book preview

    Understanding ECMAScript 6 - Nicholas C. Zakas

    BRIEF CONTENTS

    Foreword by Dan Abramov

    Acknowledgments

    Introduction

    Chapter 1: Block Bindings

    Chapter 2: Strings and Regular Expressions

    Chapter 3: Functions

    Chapter 4: Expanded Object Functionality

    Chapter 5: Destructuring for Easier Data Access

    Chapter 6: Symbols and Symbol Properties

    Chapter 7: Sets and Maps

    Chapter 8: Iterators and Generators

    Chapter 9: Introducing JavaScript Classes

    Chapter 10: Improved Array Capabilities

    Chapter 11: Promises and Asynchronous Programming

    Chapter 12: Proxies and the Reflection API

    Chapter 13: Encapsulating Code with Modules

    Appendix A: Minor Changes in ECMAScript 6

    Appendix B: Understanding ECMAScript 7 (2016)

    Index

    CONTENTS IN DETAIL

    FOREWORD by Dan Abramov

    ACKNOWLEDGMENTS

    INTRODUCTION

    The Road to ECMAScript 6

    About This Book

    Browser and Node.js Compatibility

    Who This Book Is For

    Overview

    Conventions Used

    Help and Support

    1

    BLOCK BINDINGS

    var Declarations and Hoisting

    Block-Level Declarations

    let Declarations

    No Redeclaration

    const Declarations

    The Temporal Dead Zone

    Block Bindings in Loops

    Functions in Loops

    let Declarations in Loops

    const Declarations in Loops

    Global Block Bindings

    Emerging Best Practices for Block Bindings

    Summary

    2

    STRINGS AND REGULAR EXPRESSIONS

    Better Unicode Support

    UTF-16 Code Points

    The codePointAt() Method

    The String.fromCodePoint() Method

    The normalize() Method

    The Regular Expression u Flag

    Other String Changes

    Methods for Identifying Substrings

    The repeat() Method

    Other Regular Expression Changes

    The Regular Expression y Flag

    Duplicating Regular Expressions

    The flags Property

    Template Literals

    Basic Syntax

    Multiline Strings

    Making Substitutions

    Tagged Templates

    Summary

    3

    FUNCTIONS

    Functions with Default Parameter Values

    Simulating Default Parameter Values in ECMAScript 5

    Default Parameter Values in ECMAScript 6

    How Default Parameter Values Affect the arguments Object

    Default Parameter Expressions

    Default Parameter TDZ

    Working with Unnamed Parameters

    Unnamed Parameters in ECMAScript 5

    Rest Parameters

    Increased Capabilities of the Function Constructor

    The Spread Operator

    The name Property

    Choosing Appropriate Names

    Special Cases of the name Property

    Clarifying the Dual Purpose of Functions

    Determining How a Function Was Called in ECMAScript 5

    The new.target Metaproperty

    Block-Level Functions

    Deciding When to Use Block-Level Functions

    Block-Level Functions in Non-Strict Mode

    Arrow Functions

    Arrow Function Syntax

    Creating Immediately Invoked Function Expressions

    No this Binding

    Arrow Functions and Arrays

    No arguments Binding

    Identifying Arrow Functions

    Tail Call Optimization

    How Tail Calls Are Different in ECMAScript 6

    How to Harness Tail Call Optimization

    Summary

    4

    EXPANDED OBJECT FUNCTIONALITY

    Object Categories

    Object Literal Syntax Extensions

    Property Initializer Shorthand

    Concise Methods

    Computed Property Names

    New Methods

    The Object.is() Method

    The Object.assign() Method

    Duplicate Object Literal Properties

    Own Property Enumeration Order

    Enhancements for Prototypes

    Changing an Object’s Prototype

    Easy Prototype Access with Super References

    A Formal Method Definition

    Summary

    5

    DESTRUCTURING FOR EASIER DATA ACCESS

    Why Is Destructuring Useful?

    Object Destructuring

    Destructuring Assignment

    Default Values

    Assigning to Different Local Variable Names

    Nested Object Destructuring

    Array Destructuring

    Destructuring Assignment

    Default Values

    Nested Array Destructuring

    Rest Items

    Mixed Destructuring

    Destructured Parameters

    Destructured Parameters Are Required

    Default Values for Destructured Parameters

    Summary

    6

    SYMBOLS AND SYMBOL PROPERTIES

    Creating Symbols

    Using Symbols

    Sharing Symbols

    Symbol Coercion

    Retrieving Symbol Properties

    Exposing Internal Operations with Well-Known Symbols

    The Symbol.hasInstance Method

    The Symbol.isConcatSpreadable Property

    The Symbol.match, Symbol.replace, Symbol.search, and Symbol.split Properties

    The Symbol.toPrimitive Method

    The Symbol.toStringTag Property

    The Symbol.unscopables Property

    Summary

    7

    SETS AND MAPS

    Sets and Maps in ECMAScript 5

    Problems with Workarounds

    Sets in ECMAScript 6

    Creating Sets and Adding Items

    Removing Items

    The forEach() Method for Sets

    Converting a Set to an Array

    Weak Sets

    Maps in ECMAScript 6

    Map Methods

    Map Initialization

    The forEach() Method for Maps

    Weak Maps

    Summary

    8

    ITERATORS AND GENERATORS

    The Loop Problem

    What Are Iterators?

    What Are Generators?

    Generator Function Expressions

    Generator Object Methods

    Iterables and for-of Loops

    Accessing the Default Iterator

    Creating Iterables

    Built-In Iterators

    Collection Iterators

    String Iterators

    NodeList Iterators

    The Spread Operator and Nonarray Iterables

    Advanced Iterator Functionality

    Passing Arguments to Iterators

    Throwing Errors in Iterators

    Generator Return Statements

    Delegating Generators

    Asynchronous Task Running

    A Simple Task Runner

    Task Running with Data

    An Asynchronous Task Runner

    Summary

    9

    INTRODUCING JAVASCRIPT CLASSES

    Class-Like Structures in ECMAScript 5

    Class Declarations

    A Basic Class Declaration

    Why Use the Class Syntax?

    Class Expressions

    A Basic Class Expression

    Named Class Expressions

    Classes as First-Class Citizens

    Accessor Properties

    Computed Member Names

    Generator Methods

    Static Members

    Inheritance with Derived Classes

    Shadowing Class Methods

    Inherited Static Members

    Derived Classes from Expressions

    Inheriting from Built-Ins

    The Symbol.species Property

    Using new.target in Class Constructors

    Summary

    10

    IMPROVED ARRAY CAPABILITIES

    Creating Arrays

    The Array.of() Method

    The Array.from() Method

    New Methods on All Arrays

    The find() and findIndex() Methods

    The fill() Method

    The copyWithin() Method

    Typed Arrays

    Numeric Data Types

    Array Buffers

    Manipulating Array Buffers with Views

    Similarities Between Typed and Regular Arrays

    Common Methods

    The Same Iterators

    The of() and from() Methods

    Differences Between Typed and Regular Arrays

    Behavioral Differences

    Missing Methods

    Additional Methods

    Summary

    11

    PROMISES AND ASYNCHRONOUS PROGRAMMING

    Asynchronous Programming Background

    The Event Model

    The Callback Pattern

    Promise Basics

    The Promise Life Cycle

    Creating Unsettled Promises

    Creating Settled Promises

    Executor Errors

    Global Promise Rejection Handling

    Node.js Rejection Handling

    Browser Rejection Handling

    Chaining Promises

    Catching Errors

    Returning Values in Promise Chains

    Returning Promises in Promise Chains

    Responding to Multiple Promises

    The Promise.all() Method

    The Promise.race() Method

    Inheriting from Promises

    Promise-Based Asynchronous Task Running

    Summary

    12

    PROXIES AND THE REFLECTION API

    The Array Problem

    Introducing Proxies and Reflection

    Creating a Simple Proxy

    Validating Properties Using the set Trap

    Object Shape Validation Using the get Trap

    Hiding Property Existence Using the has Trap

    Preventing Property Deletion with the deleteProperty Trap

    Prototype Proxy Traps

    How Prototype Proxy Traps Work

    Why Two Sets of Methods?

    Object Extensibility Traps

    Two Basic Examples

    Duplicate Extensibility Methods

    Property Descriptor Traps

    Blocking Object.defineProperty()

    Descriptor Object Restrictions

    Duplicate Descriptor Methods

    The ownKeys Trap

    Function Proxies with the apply and construct Traps

    Validating Function Parameters

    Calling Constructors Without new

    Overriding Abstract Base Class Constructors

    Callable Class Constructors

    Revocable Proxies

    Solving the Array Problem

    Detecting Array Indexes

    Increasing length When Adding New Elements

    Deleting Elements When Reducing length

    Implementing the MyArray Class

    Using a Proxy as a Prototype

    Using the get Trap on a Prototype

    Using the set Trap on a Prototype

    Using the has Trap on a Prototype

    Proxies as Prototypes on Classes

    Summary

    13

    ENCAPSULATING CODE WITH MODULES

    What Are Modules?

    Basic Exporting

    Basic Importing

    Importing a Single Binding

    Importing Multiple Bindings

    Importing an Entire Module

    A Subtle Quirk of Imported Bindings

    Renaming Exports and Imports

    Default Values in Modules

    Exporting Default Values

    Importing Default Values

    Re-exporting a Binding

    Importing Without Bindings

    Loading Modules

    Using Modules in Web Browsers

    Browser Module Specifier Resolution

    Summary

    A

    MINOR CHANGES IN ECMASCRIPT 6

    Working with Integers

    Identifying Integers

    Safe Integers

    New Math Methods

    Unicode Identifiers

    Formalizing the __proto__ Property

    B

    UNDERSTANDING ECMASCRIPT 7 (2016)

    The Exponentiation Operator

    Order of Operations

    Operand Restriction

    The Array.prototype.includes() Method

    How to Use Array.prototype.includes()

    Value Comparison

    A Change to Function-Scoped Strict Mode

    INDEX

    FOREWORD

    ECMAScript 6 has taken the world by storm. It came long after people stopped waiting for it, and then it spread faster than most people could learn it. Everybody has a different story about it. Here is mine.

    In 2013, I worked at a startup that pivoted from iOS to the web. It was before I co-created Redux or participated in the JavaScript open source community. At the time, I was struggling to learn web development, and I was terrified. My team had to build a web version of our product from scratch in just a few months. In JavaScript.

    At first I scoffed at the idea of writing something large in JavaScript. But a new team member persuaded me that JavaScript was not a toy language. I agreed to give it a try. I set my prejudices aside, opened MDN and StackOverflow, and learned JavaScript in depth for the first time. The simplicity I discovered enchanted me. My colleague also taught me how to use tools such as a linter and a bundler. In a few weeks, I woke up and realized that I enjoyed writing JavaScript.

    But no language is perfect. I missed the frequent updates that I’d come to expect after working with other languages. The only substantial update to JavaScript in a decade, ECMAScript 5, was a mere cleanup that nevertheless took years for browsers to fully support. At the time, the upcoming ECMAScript 6 (ES6) specification, codenamed Harmony, was far from finished and seemed like a distant future. Maybe in 10 years I’ll get to write some ES6 code, I thought.

    There were some experimental transpilers like Google Traceur that translated code from ES6 into ES5. Most of them were very limited or hard to plug into an existing JavaScript build pipeline. But then a new transpiler called 6to5 came along and changed everything. It was easy to install, integrated well with the existing tools, and produced readable code. It spread like wildfire. Now called Babel, 6to5 brought ES6 features to a mainstream audience even before the specification was finalized. In a matter of months, ES6 was everywhere.

    ES6 has divided the community for a number of reasons. As this book goes to press, it is still not fully implemented in many major browsers. Having a build step can be intimidating when you’re just learning the language. Some libraries have documentation and examples in ES6, and you might wonder if it is possible to use those libraries in ES5 at all. This contributes to the confusion. Many people didn’t expect any new features in the language because it had almost never changed before. Others anxiously awaited the new features’ arrival and used all of them together—in some cases beyond what was necessary.

    Just as I was becoming proficient with JavaScript, I felt that somebody pulled the rug from under my feet, and now I had to learn a new language. I felt bad about this for a few months. Finally, on Christmas Eve, I started reading a draft of this book. I couldn’t put it down. Next thing I knew, it was 3 AM, everybody at the party was asleep, and I understood ES6!

    Nicholas is an incredibly gifted teacher. He conveys deep details in a straightforward way so they don’t go over your head. Apart from this book, he is also known for creating ESLint, a JavaScript code analyzer that has been downloaded millions of times.

    Nicholas knows JavaScript like very few people do. Don’t miss the chance to soak up some of his knowledge. Read this book, and you, too, will become confident in your understanding of ES6.

    Dan Abramov

    React core team member and creator of Redux

    ACKNOWLEDGMENTS

    Thanks to Jennifer Griffith-Delgado, Alison Law, and everyone at No Starch Press for their support and help with this book. Their understanding and patience as my productivity slowed to a crawl during my extended illness is something I will never forget.

    I’m grateful for the watchful eye of Juriy Zaytsev as technical editor and to Dr. Axel Rauschmayer for his feedback and several conversations that helped to clarify some of the concepts discussed in this book.

    Thanks to everyone who submitted fixes to the version of this book that is hosted on GitHub: 404, alexyans, Ahmad Ali, Raj Anand, Arjunkumar, Pahlevi Fikri Auliya, Mohsen Azimi, Peter Bakondy, Sarbbottam Bandyopadhyay, blacktail, Philip Borisov, Nick Bottomley, Ethan Brown, Jeremy Caney, Jake Champion, David Chang, Carlo Costantini, Aaron Dandy, Niels Dequeker, Aleksandar Djindjic, Joe Eames, Lewis Ellis, Ronen Elster, Jamund Ferguson, Steven Foote, Ross Gerbasi, Shaun Hickson, Darren Huskie, jakub-g, kavun, Navaneeth Kesavan, Dan Kielp, Roy Ling, Roman Lo, Lonniebiz, Kevin Lozandier, Josh Lubaway, Mallory, Jakub Narębski, Robin Pokorný, Kyle Pollock, Francesco Pongiluppi, Nikolas Poniros, AbdulFattah Popoola, Ben Regenspan, Adam Richeimer, robertd, Marián Rusnák, Paul Salaets, Shidhin, ShMcK, Kyle Simpson, Igor Skuhar, Yang Su, Erik Sundahl, Dmitri Suvorov, Kevin Sweeney, Prayag Verma, Rick Waldron, Kale Worsley, Juriy Zaytsev, and Eugene Zubarev.

    Also, thanks to Casey Visco, who supported this book on Patreon.

    INTRODUCTION

    The JavaScript core language features are defined in the ECMA-262 standard. The language defined in this standard is called ECMAScript. What you know as JavaScript in browsers and in Node.js is actually a superset of ECMAScript. Browsers and Node.js add more functionality through additional objects and methods, but the core of JavaScript remains as defined in ECMAScript. The ongoing development of ECMA-262 is vital to the success of JavaScript as a whole, and this book covers the changes brought about by the most recent major update to the language: ECMAScript 6.

    The Road to ECMAScript 6

    In 2007, JavaScript was at a crossroads. The popularity of Ajax was ushering in a new age of dynamic web applications, whereas JavaScript hadn’t changed since the third edition of ECMA-262 was published in 1999. TC-39, the committee responsible for driving the ECMAScript development process, put together a large draft specification for ECMAScript 4. ECMAScript 4 was massive in scope, introducing both small and large changes to the language. Updated features included new syntax, modules, classes, classical inheritance, private object members, optional type annotations, and more.

    The scope of the ECMAScript 4 changes caused a rift to form in TC-39: some members felt that the fourth edition was trying to accomplish too much. A group of leaders from Yahoo!, Google, and Microsoft created an alternate proposal for the next version of ECMAScript that the group initially called ECMAScript 3.1. The 3.1 designation was intended to show that this version was an incremental change to the existing standard.

    ECMAScript 3.1 introduced very few syntax changes; instead, it focused on property attributes, native JSON support, and adding methods to already existing objects. Although an early attempt was made to reconcile ECMAScript 3.1 and ECMAScript 4, the effort ultimately failed because the two camps had difficulty resolving the very different perspectives on how the language should grow.

    In 2008, Brendan Eich, the creator of JavaScript, announced that TC-39 would focus its efforts on standardizing ECMAScript 3.1. It would table the major syntax and feature changes of ECMAScript 4 until after the next version of ECMAScript was standardized, and all members of the committee would work to bring the best pieces of ECMAScript 3.1 and 4 together after that point into an effort initially nicknamed ECMAScript Harmony.

    ECMAScript 3.1 was eventually standardized as the fifth edition of ECMA-262, also described as ECMAScript 5. The committee never released an ECMAScript 4 standard to avoid confusion with the now-defunct effort of the same name. Work then began on ECMAScript Harmony, with ECMAScript 6 being the first standard released in this new harmonious spirit.

    ECMAScript 6 reached feature complete status in 2015 and was formally dubbed ECMAScript 2015. (But this text still refers to it as ECMAScript 6, the name most familiar to developers.) The features vary widely from completely new objects and patterns to syntax changes and new methods on existing objects. The exciting aspect of ECMAScript 6 is that all of its changes are geared toward solving problems that developers actually face.

    About This Book

    A good understanding of ECMAScript 6 features is critical for all JavaScript developers going forward. The language features introduced in ECMAScript 6 represent the foundation upon which JavaScript applications will be built for the foreseeable future. That’s where this book comes in. My hope is that you’ll read this book to learn about ECMAScript 6 features so you’ll be ready to start using them as soon as you need to.

    Browser and Node.js Compatibility

    Many JavaScript environments, such as web browsers and Node.js, are actively working on implementing ECMAScript 6. This book doesn’t attempt to address the inconsistencies between implementations; instead, it focuses on what the specification defines as the correct behavior. As such, it’s possible that your JavaScript environment may not conform to the behavior described in this book.

    Who This Book Is For

    This book is intended as a guide for those who are already familiar with JavaScript and ECMAScript 5. Although a deep understanding of the language isn’t necessary to use this book, it will help you understand the differences between ECMAScript 5 and 6. In particular, this book is aimed at intermediate-to-advanced JavaScript developers programming for a browser or Node.js environment who want to learn about the latest developments in the language.

    This book is not for beginners who have never written JavaScript. You’ll need to have a good basic understanding of the language to use this book.

    Overview

    Each chapter and appendix in this book covers a different aspect of ECMAScript 6. Many chapters start by discussing problems that ECMAScript 6 changes were made to solve to give you a broader context for those changes. All chapters include code examples to help you learn new syntax and concepts.

    Chapter 1: Block Bindings talks about let and const, the block-level replacement for var.

    Chapter 2: Strings and Regular Expressions covers additional functionality for string manipulation and inspection as well as the introduction of template strings.

    Chapter 3: Functions discusses the various changes to functions, including the arrow function form, default parameters, rest parameters, and a few other features.

    Chapter 4: Expanded Object Functionality explains the changes to how objects are created, modified, and used. Topics include changes to object literal syntax and new reflection methods.

    Chapter 5: Destructuring for Easier Data Access introduces object and array destructuring, which allow you to decompose objects and arrays using a concise syntax.

    Chapter 6: Symbols and Symbol Properties introduces the concept of symbols, a new way to define properties. Symbols are a new primitive type that you can use to obscure (but not hide) object properties and methods.

    Chapter 7: Sets and Maps details the new collection types of Set, WeakSet, Map, and WeakMap. These types expand on the usefulness of arrays by adding semantics, de-duping, and memory management designed specifically for JavaScript.

    Chapter 8: Iterators and Generators discusses the addition of iterators and generators to the language. These features allow you to work with collections of data in powerful ways that were not possible in previous versions of JavaScript.

    Chapter 9: Introducing JavaScript Classes introduces the first formal concept of classes in JavaScript. Often a point of confusion for those coming from other languages, the addition of class syntax in JavaScript makes the language more approachable to others and more concise for enthusiasts.

    Chapter 10: Improved Array Capabilities details the changes to native arrays and the useful new ways you can use them in JavaScript.

    Chapter 11: Promises and Asynchronous Programming introduces promises as a new part of the language. Promises were a grassroots effort that eventually took off and gained popularity due to extensive library support. ECMAScript 6 formalizes promises and makes them available by default.

    Chapter 12: Proxies and the Reflection API introduces the formalized reflection API for JavaScript and the new proxy object that allows you to intercept every operation performed on an object. Proxies give developers unprecedented control over objects and, as such, unlimited possibilities for defining new interaction patterns.

    Chapter 13: Encapsulating Code with Modules details the official module format for JavaScript. The intent is that these modules can replace the numerous ad hoc module definition formats that have appeared over the years.

    Appendix A: Minor Changes in ECMAScript 6 covers other changes implemented in ECMAScript 6 that you’ll use less frequently or that didn’t quite fit into the broader major topics covered in each chapter.

    Appendix B: Understanding ECMAScript 7 (2016) describes the three additions to the standard that were implemented in ECMAScript 7, which didn’t impact JavaScript nearly as much as ECMAScript 6.

    Conventions Used

    The following typographical conventions are used in this book:

    Italics are used for new terms and filenames.

    • Constant width indicates a code term within the text.

    Additionally, longer code examples are contained in constant width code blocks, such as the following:

    function doSomething() {

        // empty

    }

    Within a code block, comments to the right of a console.log() statement indicate the output you’ll see in the browser or Node.js console when the code is executed; for example:

    console.log(Hi);      // Hi

    If a line of code in a code block throws an error, it is also indicated to the right of the code:

    doSomething();          // throws an error

    Help and Support

    If you have questions as you read this book, please send a message to my mailing list at http://groups.google.com/group/zakasbooks.

    1

    BLOCK BINDINGS

    Traditionally, the way variable declarations work has been one tricky part of programming in JavaScript. In most C-based languages, variables (more formally known as bindings, as a name is bound to a value inside a scope) are created at the spot where the declaration occurs. In JavaScript, however, this is not the case. Where your variables are actually created depends on how you declare them, and ECMAScript 6 offers options to make controlling scope easier. This chapter demonstrates why classic var declarations can be confusing, introduces block-level bindings in ECMAScript 6, and then offers some best practices for using them.

    var Declarations and Hoisting

    Variable declarations using var are treated as if they’re at the top of the function (or in the global scope, if declared outside of a function) regardless of where the actual declaration occurs; this is called hoisting. For a demonstration of what hoisting does, consider the following function definition:

    function getValue(condition) {

        if (condition) {

            var value = blue;

            // other code

            return value;

        } else {

            // value exists here with a value of undefined

            return null;

        }

        // value exists here with a value of undefined

    }

    If you are unfamiliar with JavaScript, you might expect the variable value to be created only if condition evaluates to true. In fact, the variable value is created regardless. Behind the scenes, the JavaScript engine changes the getValue function to look like this:

    function getValue(condition) {

        var value;

        if (condition) {

            value = blue;

            // other code

            return value;

        } else {

            return null;

        }

    }

    The declaration of value is hoisted to the top, and the initialization remains in the same spot. That means the variable value is still accessible from within the else clause. If accessed from the else clause, the variable would just have a value of undefined because it hasn’t been initialized in the else block.

    It often takes new JavaScript developers some time to get used to declaration hoisting, and misunderstanding this unique behavior can end up causing bugs. For this reason, ECMAScript 6 introduces block-level scoping options to give developers more control over a variable’s life cycle.

    Block-Level Declarations

    Block-level declarations declare bindings that are inaccessible outside a given block scope. Block scopes, also called lexical scopes, are created in the following places:

    • Inside a function

    • Inside a block (indicated by the { and } characters)

    Block scoping is how many C-based languages work, and the introduction of block-level declarations in ECMAScript 6 is intended to provide that same flexibility (and uniformity) to JavaScript.

    let Declarations

    The let declaration syntax is the same as the syntax for var. You can basically replace var with let to declare a variable but limit the variable’s scope to only the current code block (there are a few other subtle differences, which are discussed in "The Temporal Dead Zone" on page 6). Because let declarations are not hoisted to the top of the enclosing block, it’s best to place let declarations first in the block so they’re available to the entire block. Here’s an example:

    function getValue(condition) {

        if (condition) {

            let value = blue;

            // other code

            return value;

        } else {

            // value doesn't exist here

            return null;

        }

        // value doesn't exist here

    }

    This version of the getValue function behaves more similarly to how you’d expect it to in other C-based languages. Because the variable value is declared using let instead of var, the declaration isn’t hoisted to the top of the function definition, and the variable value is no longer accessible once execution flows out of the if block. If condition evaluates to false, then value is never declared or initialized.

    No Redeclaration

    If an identifier has already been defined in a scope, using the identifier in a let declaration inside that scope causes an error to be thrown. For example:

    var count = 30;

    // throws an error

    let count = 40;

    In this example, count is declared twice: once with var and once with let. Because let will not redefine an identifier that already exists in the same scope, the let declaration will throw an error. Conversely, no error is thrown if a let declaration creates a new variable with the same name as a variable in its containing scope, as demonstrated in the following code:

    var count = 30;

    if (condition) {

        // doesn't throw an error

        let count = 40;

        // more code

    }

    This let declaration doesn’t throw an error because it creates a new variable called count within the if statement instead of creating count in the surrounding block. Inside the if block, this new variable shadows the global count, preventing access to it until execution exits the block.

    const Declarations

    You can also define bindings in ECMAScript 6 with the const declaration syntax. Bindings declared using const are considered constants, meaning their values cannot be changed once set. For this reason, every const binding must be initialized on declaration, as shown in this example:

    // valid constant

    const maxItems = 30;

    // syntax error: missing initialization

    const name;

    The maxItems binding is initialized, so its const declaration will work without a problem. However, the name binding would cause a syntax error if you tried to run the program containing this code because name is not initialized.

    Constants vs. let Declarations

    Constants, like let declarations, are block-level declarations. That means constants are no longer accessible once execution flows out of the block in which they were declared, and declarations are not hoisted, as demonstrated in this example:

    if (condition) {

        const maxItems = 5;

        // more code

    }

    // maxItems isn't accessible here

    In this code, the constant maxItems is declared within an if statement. After the statement finishes executing, maxItems is not accessible outside that block.

    In another similarity to let, a const declaration throws an error when made with an identifier for an already defined variable in the same scope. It doesn’t matter whether that variable was declared using var (for global or function scope) or let (for block scope). For example, consider this code:

    var message = Hello!;

    let age = 25;

    // each of these throws an error

    const message = Goodbye!;

    const age = 30;

    The two const declarations would be valid alone, but given the previous var and let declarations in this case, they are syntax errors.

    Despite those similarities, there is one significant difference between let and const. Attempting to assign a const to a previously defined constant will throw an error in both strict and non-strict modes:

    const maxItems = 5;

    // throws an error

    maxItems = 6;

    Much like constants in other languages, the maxItems variable can’t be assigned a new value later on. However, unlike constants in other languages, the value a constant

    Enjoying the preview?
    Page 1 of 1