One place for hosting & domains

      Understanding

      Understanding Relational Databases


      Introduction

      Database management systems (DBMS) are computer programs that allow users to interact with a database. A DBMS allows users to control access to a database, write data, run queries, and perform any other tasks related to database management.

      In order to perform any of these tasks, though, the DBMS must have some kind of underlying model that defines how the data are organized. The relational model is one approach for organizing data that has found wide use in database software since it was first devised in the late 1960s, so much so that, as of this writing, four of the top five most popular DBMSs are relational.

      This conceptual article outlines the history of the relational model, how relational databases organize data, and how they’re used today.

      History of the Relational Model

      Databases are logically modelled clusters of information, or data. Any collection of data is a database, regardless of how or where it is stored. Even a file cabinet containing payroll information is a database, as is a stack of hospital patient forms, or a company’s collection of customer information spread across multiple locations. Before storing and managing data with computers was common practice, physical databases like these were the only ones available to government and business organizations that needed to store information.

      Around the middle of the 20th century, developments in computer science led to machines with more processing power, as well as greater local and external storage capacity. These advancements led computer scientists to start recognizing the potential these machines had for storing and managing ever larger amounts of data.

      However, there weren’t any theories for how computers could organize data in meaningful, logical ways. It’s one thing to store unsorted data on a machine, but it’s much more complicated to design systems that allow you to add, retrieve, sort, and otherwise manage that data in consistent, practical ways. The need for a logical framework for storing and organizing data led to a number of proposals for how to harness computers for data management.

      One early database model was the hierarchical model, in which data are organized in a tree-like structure, similar to modern-day filesystems. The following example shows how the layout of part of a hierarchical database used to categorize animals might look:

      Example Hierarchical Database: Animal categorization

      The hierarchical model was widely implemented in early database management systems, but it also proved to be somewhat inflexible. In this model, even though individual records can have multiple “children,” each record can only have one “parent” in the hierarchy. Because of this, these earlier hierarchical databases were limited to representing only “one-to-one” and “one-to-many” relationships. This lack of “many-to-many” relationships could lead to problems when you’re working with data points that you’d like to associate with more than one parent.

      In the late 1960s, Edgar F. Codd, a computer scientist working at IBM, devised the relational model of database management. Codd’s relational model allowed individual records to be associated with more than one table, thereby enabling “many-to-many” relationships between data points in addition to “one-to-many” relationships. This provided more flexibility than other existing models when it came to designing database structures, and meant that relational database management systems (RDBMSs) could meet a much wider range of business needs.

      Codd proposed a language for managing relational data, known as Alpha, which influenced the development of later database languages. Two of Codd’s colleagues at IBM, Donald Chamberlin and Raymond Boyce, created one such language inspired by Alpha. They called their language SEQUEL, short for Structured English Query Language, but because of an existing trademark they shortened the name of their language to SQL (referred to more formally as Structured Query Language).

      Due to hardware constraints, early relational databases were still prohibitively slow, and it took some time before the technology became widespread. But by the mid-1980s, Codd’s relational model had been implemented in a number of commercial database management products from both IBM and its competitors. These vendors also followed IBM’s lead by developing and implementing their own dialects of SQL. By 1987, both the American National Standards Institute and the International Organization for Standardization had ratified and published standards for SQL, solidifying its status as the accepted language for managing RDBMSs.

      The relational model’s wide use across multiple industries led to it becoming recognized as the standard model for data management. Even with the rise of various NoSQL databases in more recent years, relational databases remain the dominant tools for storing and organizing data.

      How Relational Databases Organize Data

      Now that you have a general understanding of the relational model’s history, let’s take a closer look at how the model organizes data.

      The most fundamental elements in the relational model are relations, which users and modern RDBMSs recognize as tables. A relation is a set of tuples, or rows in a table, with each tuple sharing a set of attributes, or columns:

      Diagram example of how relations, tuples, and attributes relate to one another

      A column is the smallest organizational structure of a relational database, and represents the various facets that define the records in the table. Hence their more formal name, attributes. You can think of each tuple as a unique instance of whatever type of people, objects, events, or associations the table holds. These instances might be things like employees at a company, sales from an online business, or lab test results. For example, in a table that holds employee records of teachers at a school, the tuples might have attributes like name, subjects, start_date, and so on.

      When creating columns, you specify a data type that dictates what kind of entries are allowed in that column. RDBMSs often implement their own unique data types, which may not be directly interchangeable with similar data types in other systems. Some common data types include dates, strings, integers, and Booleans.

      In the relational model, each table contains at least one column that can be used to uniquely identify each row, called a primary key. This is important, because it means that users don’t need to know where their data is physically stored on a machine; instead, their DBMS can keep track of each record and return them on an ad hoc basis. In turn, this means that records have no defined logical order, and users have the ability to return their data in whatever order or through whatever filters they wish.

      If you have two tables that you’d like to associate with one another, one way you can do so is with a foreign key. A foreign key is essentially a copy of one table’s (the “parent” table) primary key inserted into a column in another table (the “child”). The following example highlights the relationship between two tables, one used to record information about employees at a company and another used to track the company’s sales. In this example, the primary key of the EMPLOYEES table is used as the foreign key of the SALES table:

      Diagram example of how the EMPLOYEE table's primary key acts as the SALES table's foreign key

      If you try to add a record to the child table and the value entered into the foreign key column doesn’t exist in the parent table’s primary key, the insertion statement will be invalid. This helps to maintain relationship-level integrity, as the rows in both tables will always be related correctly.

      The relational model’s structural elements help to keep data stored in an organized way, but storing data is only useful if you can retrieve it. To retrieve information from an RDBMS, you can issue a query, or a structured request for a set of information. As mentioned previously, most relational databases use SQL to manage and query data. SQL allows you to filter and manipulate query results with a variety of clauses, predicates, and expressions, giving you fine control over what data will appear in the result set.

      Advantages and Limitations of Relational Databases

      With the underlying organizational structure of relational databases in mind, let’s consider some of their advantages and disadvantages.

      Today, both SQL and the databases that implement it deviate from Codd’s relational model in several ways. For instance, Codd’s model dictates that each row in a table should be unique while, for reasons of practicality, most modern relational databases do allow for duplicate rows. There are some that don’t consider SQL databases to be true relational databases if they fail to adhere to each of Codd’s specifications for the relational model. In practical terms, though, any DBMS that uses SQL and at least somewhat adheres to the relational model is likely to be referred to as a relational database management system.

      Although relational databases quickly grew in popularity, a few of the relational model’s shortcomings started to become apparent as data became more valuable and businesses began storing more of it. For one thing, it can be difficult to scale a relational database horizontally. Horizontal scaling, or scaling out, is the practice of adding more machines to an existing stack in order to spread out the load and allow for more traffic and faster processing. This is often contrasted with vertical scaling which involves upgrading the hardware of an existing server, usually by adding more RAM or CPU.

      The reason it’s difficult to scale a relational database horizontally has to do with the fact that the relational model is designed to ensure consistency, meaning clients querying the same database will always retrieve the same data. If you were to scale a relational database horizontally across multiple machines, it becomes difficult to ensure consistency since clients may write data to one node but not the others. There would likely be a delay between the initial write and the time when the other nodes are updated to reflect the changes, resulting in inconsistencies between them.

      Another limitation presented by RDBMSs is that the relational model was designed to manage structured data, or data that aligns with a predefined data type or is at least organized in some predetermined way, making it easily sortable and searchable. With the spread of personal computing and the rise of the internet in the early 1990s, however, unstructured data — such as email messages, photos, videos, etc. — became more common.

      None of this is to say that relational databases aren’t useful. Quite the contrary, the relational model is still the dominant framework for data management after over 40 years. Their prevalence and longevity mean that relational databases are a mature technology, which is itself one of their major advantages. There are many applications designed to work with the relational model, as well as many career database administrators who are experts when it comes to relational databases. There’s also a wide array of resources available in print and online for those looking to get started with relational databases.

      Another advantage of relational databases is that almost every RDBMS supports transactions. A transaction consists of one or more individual SQL statements performed in sequence as a single unit of work. Transactions present an all-or-nothing approach, meaning that every SQL statement in the transaction must be valid; otherwise, the entire transaction will fail. This is very helpful for ensuring data integrity when making changes to multiple rows or tables.

      Lastly, relational databases are extremely flexible. They’ve been used to build a wide variety of different applications, and continue working efficiently even with very large amounts of data. SQL is also extremely powerful, allowing you to add and change data on the fly, as well as alter the structure of database schemas and tables without impacting existing data.

      Conclusion

      Thanks to their flexibility and design for data integrity, relational databases are still the primary way data are managed and stored more than fifty years after they were first conceived of. Even with the rise of various NoSQL databases in recent years, understanding the relational model and how to work with RDBMSs are key for anyone who wants to build applications that harness the power of data.

      To learn more about a few popular open-source RDBMSs, we encourage you to check out our comparison of various open-source relational SQL databases. If you’re interested in learning more about databases generally, we encourage you to check out our complete library of database-related content.



      Source link

      Understanding Template Literals in JavaScript


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      Introduction

      The 2015 edition of the ECMAScript specification (ES6) added template literals to the JavaScript language. Template literals are a new form of making strings in JavaScript that add a lot of powerful new capabilities, such as creating multi-line strings more easily and using placeholders to embed expressions in a string. In addition, an advanced feature called tagged template literals allows you to perform operations on the expressions within a string. All of these capabilities increase your options for string manipulation as a developer, letting you generate dynamic strings that could be used for URLs or functions that customize HTML elements.

      In this article, you will go over the differences between single/double-quoted strings and template literals, running through the various ways to declare strings of different shape, including multi-line strings and dynamic strings that change depending on the value of a variable or expression. You will then learn about tagged templates and see some real-world examples of projects using them.

      Declaring Strings

      This section will review how to declare strings with single quotes and double quotes, and will then show you how to do the same with template literals.

      In JavaScript, a string can be written with single quotes (' '):

      const single="Every day is a good day when you paint."
      

      A string can also be written with double quotes (" "):

      const double = "Be so very light. Be a gentle whisper."
      

      There is no major difference in JavaScript between single- or double-quoted strings, unlike other languages that might allow interpolation in one type of string but not the other. In this context, interpolation refers to the evaluation of a placeholder as a dynamic part of a string.

      The use of single- or double-quoted strings mostly comes down to personal preference and convention, but used in conjunction, each type of string only needs to escape its own type of quote:

      // Escaping a single quote in a single-quoted string
      const single=""We don"t make mistakes. We just have happy accidents." - Bob Ross'
      
      // Escaping a double quote in a double-quoted string
      const double = ""We don't make mistakes. We just have happy accidents." - Bob Ross"
      
      console.log(single);
      console.log(double);
      

      The result of the log() method here will print the same two strings to the console:

      Output

      "We don't make mistakes. We just have happy accidents." - Bob Ross "We don't make mistakes. We just have happy accidents." - Bob Ross

      Template literals, on the other hand, are written by surrounding the string with the backtick character, or grave accent (`):

      const template = `Find freedom on this canvas.`
      

      They do not need to escape single or double quotes:

      const template = `"We don't make mistakes. We just have happy accidents." - Bob Ross`
      

      However, they do still need to escape backticks:

      const template = `Template literals use the ` character.`
      

      Template literals can do everything that regular strings can, so you could possibly replace all strings in your project with them and have the same functionality. However, the most common convention in codebases is to only use template literals when using the additional capabilities of template literals, and consistently using the single or double quotes for all other simple strings. Following this standard will make your code easier to read if examined by another developer.

      Now that you’ve seen how to declare strings with single quotes, double quotes, and backticks, you can move on to the first advantage of template literals: writing multi-line strings.

      Multi-line Strings

      In this section, you will first run through the way strings with multiple lines were declared before ES6, then see how template literals make this easier.

      Originally, if you wanted to write a string that spans multiple lines in your text editor, you would use the concatenation operator. However, this was not always a straight-forward process. The following string concatenation seemed to run over multiple lines:

      const address="Homer J. Simpson" + 
        '742 Evergreen Terrace' + 
        'Springfield'
      

      This might allow you to break up the string into smaller lines and include it over multiple lines in the text editor, but it has no effect on the output of the string. In this case, the strings will all be on one line and not separated by newlines or spaces. If you logged address to the console, you would get the following:

      Output

      Homer J. Simpson742 Evergreen TerraceSpringfield

      You can use the backslash character () to continue the string onto multiple lines:

      const address="Homer J. Simpson
        742 Evergreen Terrace
        Springfield"
      

      This will retain any indentation as whitespace, but the string will still be on one line in the output:

      Output

      Homer J. Simpson 742 Evergreen Terrace Springfield

      Using the newline character (n), you can create a true multi-line string:

      const address="Homer J. Simpsonn" + 
        '742 Evergreen Terracen' + 
        'Springfield'
      

      When logged to the console, this will display the following:

      Output

      Homer J. Simpson 742 Evergreen Terrace Springfield

      Using newline characters to designate multi-line strings can be counterintuitive, however. In contrast, creating a multi-line string with template literals can be much more straight-forward. There is no need to concatenate, use newline characters, or use backslashes. Just pressing ENTER and writing the string across multiple lines works by default:

      const address = `Homer J. Simpson
      742 Evergreen Terrace
      Springfield`
      

      The output of logging this to the console is the same as the input:

      Output

      Homer J. Simpson 742 Evergreen Terrace Springfield

      Any indentation will be preserved, so it’s important not to indent any additional lines in the string if that is not desired. For example, consider the following:

      const address = `Homer J. Simpson
                       742 Evergreen Terrace
                       Springfield`
      

      Although this style of writing the line might make the code more human readable, the output will not be:

      Output

      Homer J. Simpson 742 Evergreen Terrace Springfield

      With multi-line strings now covered, the next section will deal with how expressions are interpolated into their values with the different string declarations.

      Expression Interpolation

      In strings before ES6, concatenation was used to create a dynamic string with variables or expressions:

      const method = 'concatenation'
      const dynamicString = 'This string is using ' + method + '.'
      

      When logged to the console, this will yield the following:

      Output

      This string is using concatenation.

      With template literals, an expression can be embedded in a placeholder. A placeholder is represented by ${}, with anything within the curly brackets treated as JavaScript and anything outside the brackets treated as a string:

      const method = 'interpolation'
      const dynamicString = `This string is using ${method}.`
      

      When dynamicString is logged to the console, the console will show the following:

      Output

      This string is using interpolation.

      One common example of embedding values in a string might be for creating dynamic URLs. With concatenation, this can be cumbersome. For example, the following declares a function to generate an OAuth access string:

      function createOAuthString(host, clientId, scope) {
        return host + '/login/oauth/authorize?client_id=' + clientId + '&scope=" + scope
      }
      
      createOAuthString("https://github.com', 'abc123', 'repo,user')
      

      Logging this function will yield the following URL to the console:

      Output

      https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user

      Using string interpolation, you no longer have to keep track of opening and closing strings and concatenation operator placement. Here is the same example with template literals:

      function createOAuthString(host, clientId, scope) {
        return `${host}/login/oauth/authorize?client_id=${clientId}&scope=${scope}`
      }
      
      createOAuthString('https://github.com', 'abc123', 'repo,user')
      

      This will have the same output as the concatenation example:

      Output

      https://github.com/login/oauth/authorize?client_id=abc123&scope=repo,user

      You can also use the trim() method on a template literal to remove any whitespace at the beginning or end of the string. For example, the following uses an arrow function to create an HTML <li> element with a customized link:

      const menuItem = (url, link) =>
        `
      <li>
        <a href="https://www.digitalocean.com/${url}">${link}</a>
      </li>
      `.trim()
      
      menuItem('https://google.com', 'Google')
      

      The result will be trimmed of all the whitespace, ensuring that the element will be rendered correctly:

      Output

      <li> <a href="https://google.com">Google</a> </li>

      Entire expressions can be interpolated, not just variables, such as in this example of the sum of two numbers:

      const sum = (x, y) => x + y
      const x = 5
      const y = 100
      const string = `The sum of ${x} and ${y} is ${sum(x, y)}.`
      
      console.log(string)
      

      This code defines the sum function and the variables x and y, then uses both the function and the variables in a string. The logged result will show the following:

      Output

      The sum of 5 and 100 is 105.

      This can be particularly useful with ternary operators, which allow conditionals within a string:

      const age = 19
      const message = `You can ${age < 21 ? 'not' : ''} view this page`
      console.log(message)
      

      The logged message here will change depnding on whether the value of age is over or under 21. Since it is 19 in this example, the following output will be logged:

      Output

      You can not view this page

      Now you have an idea of how template literals can be useful when used to interpolate expressions. The next section will take this a step further by examining tagged template literals to work with the expressions passed into placeholders.

      Tagged Template Literals

      An advanced feature of template literals is the use of tagged template literals, sometimes referred to as template tags. A tagged template starts with a tag function that parses a template literal, allowing you more control over manipulating and returning a dynamic string.

      In this example, you’ll create a tag function to use as the function operating on a tagged template. The string literals are the first parameter of the function, named strings here, and any expressions interpolated into the string are packed into the second parameter using rest parameters. You can console out the parameter to see what they will contain:

      function tag(strings, ...expressions) {
        console.log(strings)
        console.log(expressions)
      }
      

      Use the tag function as the tagged template function and parse the string as follows:

      const string = tag`This is a string with ${true} and ${false} and ${100} interpolated inside.`
      

      Since you’re console logging strings and expressions, this will be the output:

      Output

      (4) ["This is a string with ", " and ", " and ", " interpolated inside." (3) [true, false, 100]

      The first parameter, strings, is an array containing all the string literals:

      • "This is a string with "
      • " and "
      • " and "
      • " interpolated inside."

      There is also a raw property available on this argument at strings.raw, which contains the strings without any escape sequences being processed. For example, /n would just be the character /n and not be escaped into a newline.

      The second parameter, ...expressions, is a rest parameter array consisting of all the expressions:

      The string literals and expressions are passed as parameters to the tagged template function tag. Note that the tagged template does not need to return a string; it can operate on those values and return any type of value. For example, we can have the function ignore everything and return null, as in this returnsNull function:

      function returnsNull(strings, ...expressions) {
        return null
      }
      
      const string = returnsNull`Does this work?`
      console.log(string)
      

      Logging the string variable will return:

      Output

      null

      An example of an action that can be performed in tagged templates is applying some change to both sides of each expression, such as if you wanted to wrap each expression in an HTML tag. Create a bold function that will add <strong> and </strong> to each expression:

      function bold(strings, ...expressions) {
        let finalString = ''
      
        // Loop through all expressions
        expressions.forEach((value, i) => {
          finalString += `${strings[i]}<strong>${value}</strong>`
        })
      
        // Add the last string literal
        finalString += strings[strings.length - 1]
      
        return finalString
      }
      
      const string = bold`This is a string with ${true} and ${false} and ${100} interpolated inside.`
      
      console.log(string)
      

      This code uses the forEach method to loop over the expressions array and add the bolding element:

      Output

      This is a string with <strong>true</strong> and <strong>false</strong> and <strong>100</strong> interpolated inside.

      There are a few examples of tagged template literals in popular JavaScript libraries. The graphql-tag library uses the gql tagged template to parse GraphQL query strings into the abstract syntax tree (AST) that GraphQL understands:

      import gql from 'graphql-tag'
      
      // A query to retrieve the first and last name from user 5
      const query = gql`
        {
          user(id: 5) {
            firstName
            lastName
          }
        }
      `
      

      Another library that uses tagged template functions is styled-components, which allows you to create new React components from regular DOM elements and apply additional CSS styles to them:

      import styled from 'styled-components'
      
      const Button = styled.button`
        color: magenta;
      `
      
      // <Button> can now be used as a custom component
      

      You can also use the built-in String.raw method on tagged template literals to prevent any escape sequences from being processed:

      const rawString = String.raw`I want to write /n without it being escaped.`
      console.log(rawString)
      

      This will log the following:

      Output

      I want to write /n without it being escaped.

      Conclusion

      In this article, you reviewed single- and double-quoted string literals and you learned about template literals and tagged template literals. Template literals make a lot of common string tasks simpler by interpolating expressions in strings and creating multi-line strings without any concatenation or escaping. Template tags are also a useful advanced feature of template literals that many popular libraries have used, such as GraphQL and styled-components.

      To learn more about strings in JavaScript, read How To Work with Strings in JavaScript and How To Index, Split, and Manipulate Strings in JavaScript.



      Source link

      Understanding Default Parameters in JavaScript


      The author selected the COVID-19 Relief Fund to receive a donation as part of the Write for DOnations program.

      In ECMAScript 2015, default function parameters were introduced to the JavaScript language. These allow developers to initialize a function with default values if the arguments are not supplied to the function call. Initializing function parameters in this way will make your functions easier to read and less error-prone, and will provide default behavior for your functions. This will help you avoid errors that stem from passing in undefined arguments and destructuring objects that don’t exist.

      In this article, you will review the difference between parameters and arguments, learn how to use default parameters in functions, see alternate ways to support default parameters, and learn what types of values and expressions can be used as default parameters. You will also run through examples that demonstrate how default parameters work in JavaScript.

      Arguments and Parameters

      Before explaining default function parameters, it is important to know what it is that parameters can default to. Because of this, we will first review the difference between arguments and parameters in a function. If you would like to learn more about this distinction, check out our earlier article in the JavaScript series, How to Define Functions in JavaScript.

      In the following code block, you will create a function that returns the cube of a given number, defined as x:

      // Define a function to cube a number
      function cube(x) {
        return x * x * x
      }
      

      The x variable in this example is a parameter—a named variable passed into a function. A parameter must always be contained in a variable and must never have a direct value.

      Now take a look at this next code block, which calls the cube function you just created:

      // Invoke cube function
      cube(10)
      

      This will give the following output:

      Output

      1000

      In this case, 10 is an argument—a value passed to a function when it is invoked. Often the value will be contained in a variable as well, such as in this next example:

      // Assign a number to a variable
      const number = 10
      
      // Invoke cube function
      cube(number)
      

      This will yield the same result:

      Output

      1000

      If you do not pass an argument to a function that expects one, the function will implicitly use undefined as the value:

      // Invoke the cube function without passing an argument
      cube()
      

      This will return:

      Output

      NaN

      In this case, cube() is trying to calculate the value of undefined * undefined * undefined, which results in NaN, or “not a number”. For more on this, take a look at the number section of Understanding Data Types in JavaScript.

      This automatic behavior can sometimes be a problem. In some cases, you might want the parameter to have a value even if no argument was passed to the function. That’s where the default parameters feature comes in handy, a topic that you will cover in the next section.

      Default Parameter Syntax

      With the addition of default parameters in ES2015, you can now assign a default value to any parameter, which the function will use instead of undefined when called without an argument. This section will first show you how to do this manually, and then will guide you through setting default parameters.

      Without default parameters, you would have to explicitly check for undefined values in order to set defaults, as is shown in this example:

      // Check for undefined manually
      function cube(x) {
        if (typeof x === 'undefined') {
          x = 5
        }
      
        return x * x * x
      }
      
      cube()
      

      This uses a conditional statement to check if the value has been automatically provided as undefined, then sets the value of x as 5. This will result in the following output:

      Output

      125

      In contrast, using default parameters accomplishes the same goal in much less code. You can set a default value to the parameter in cube by assigning it with the equality assignment operator (=), as highlighted here:

      // Define a cube function with a default value
      function cube(x = 5) {
        return x * x * x
      }
      

      Now when the cube function is invoked without an argument, it will assign 5 to x and return the calculation instead of NaN:

      // Invoke cube function without an argument
      cube()
      

      Output

      125

      It will still function as intended when an argument is passed, ignoring the default value:

      // Invoke cube function with an argument
      cube(2)
      

      Output

      8

      However, one important caveat to note is that the default parameter value will also override an explicit undefined passed as an argument to a function, as demonstrated here:

      // Invoke cube function with undefined
      cube(undefined)
      

      This will give the calculation with x equal to 5:

      Output

      125

      In this case, the default parameter values were calculated, and an explicit undefined value did not override them.

      Now that you have an idea of the basic syntax of default parameters, the next section will show how default parameters work with different data types.

      Default Parameter Data Types

      Any primitive value or object can be used as a default parameter value. In this section, you will see how this flexibility increases the ways in which default parameters can be used.

      First, set parameters using a number, string, boolean, object, array, and null value as a default value. This example will use arrow function syntax:

      // Create functions with a default value for each data type
      const defaultNumber = (number = 42) => console.log(number)
      const defaultString = (string = 'Shark') => console.log(string)
      const defaultBoolean = (boolean = true) => console.log(boolean)
      const defaultObject = (object = { id: 7 }) => console.log(object)
      const defaultArray = (array = [1, 2, 3]) => console.log(array)
      const defaultNull = (nullValue = null) => console.log(nullValue)
      

      When these functions are invoked without parameters, they will all use the default values:

      // Invoke each function
      defaultNumber()
      defaultString()
      defaultBoolean()
      defaultObject()
      defaultArray()
      defaultNull()
      

      Output

      42 "Shark" true {id: 7} (3) [1, 2, 3] null

      Note that any object created in a default parameter will be created every time the function is called. One of the common use cases for default parameters is to use this behavior to obtain values out of an object. If you try to destructure or access a value from an object that doesn’t exist, it will throw an error. However, if the default parameter is an empty object, it will simply give you undefined values instead of throwing an error:

      // Define a settings function with a default object
      function settings(options = {}) {
        const { theme, debug } = options
      
        // Do something with settings
      }
      

      This will avoid the error caused by destructuring objects that don’t exist.

      Now that you’ve seen how default parameters operate with different data types, the next section will explain how multiple default parameters can work together.

      Using Multiple Default Parameters

      You can use as many default parameters as you want in a function. This section will show you how to do this, and how to use it to manipulate the DOM in a real-world example.

      First, declare a sum() function with multiple default parameters:

      // Define a function to add two values
      function sum(a = 1, b = 2) {
        return a + b
      }
      
      sum()
      

      This will result in the following default calculation:

      Output

      3

      Additionally, the value used in a parameter can be used in any subsequent default parameter, from left to right. For example, this createUser function creates a user object userObj as the third parameter, and all the function itself does is return userObj with the first two parameters:

      // Define a function to create a user object using parameters
      function createUser(name, rank, userObj = { name, rank }) {
        return userObj
      }
      
      // Create user
      const user = createUser('Jean-Luc Picard', 'Captain')
      

      If you call user here, you will get the following:

      Output

      {name: "Jean-Luc Picard", rank: "Captain"}

      It is usually recommended to put all default parameters at the end of a list of parameters, so that you can easily leave off optional values. If you use a default parameter first, you will have to explicitly pass undefined to use the default value.

      Here is an example with the default parameter at the beginning of the list:

      // Define a function with a default parameter at the start of the list
      function defaultFirst(a = 1, b) {
        return a + b
      }
      

      When calling this function, you would have to call defaultFirst() with two arguments:

      defaultFirst(undefined, 2)
      

      This would give the following:

      Output

      3

      Here is an example with the default parameter at the end of the list:

      // Define a function with a default parameter at the end of the list
      function defaultLast(a, b = 1) {
        return a + b
      }
      
      defaultLast(2)
      

      This would yield the same value:

      Output

      3

      Both functions have the same result, but the one with the default value last allows a much cleaner function call.

      For a real-world example, here is a function that will create a DOM element, and add a text label and classes, if they exist.

      // Define function to create an element
      function createNewElement(tag, text, classNames = []) {
        const el = document.createElement(tag)
        el.textContent = text
      
        classNames.forEach(className => {
          el.classList.add(className)
        })
      
        return el
      }
      

      You can call the function with some classes in an array:

      const greeting = createNewElement('p', 'Hello!', ['greeting', 'active'])
      

      Calling greeting will give the following value:

      Output

      <p class="greeting active">Hello!</p>

      However, if you leave the classNames array out of the function call, it will still work.

      const greeting2 = createNewElement('p', 'Hello!')
      

      greeting2 now has the following value:

      Output

      <p>Hello!</p>

      In this example, forEach() can be used on an empty array without an issue. If that empty array were not set in the default parameter, you would get the following error:

      Output

      VM2673:5 Uncaught TypeError: Cannot read property 'forEach' of undefined at createNewElement (<anonymous>:5:14) at <anonymous>:12:18

      Now that you have seen how multiple default parameters can interact, you can move on to the next section to see how function calls work as default parameters.

      Function Calls as Default Parameters

      In addition to primitives and objects, the result of calling a function can be used as a default parameter.

      In this code block, you will create a function to return a random number, and then use the result as the default parameter value in a cube function:

      // Define a function to return a random number from 1 to 10
      function getRandomNumber() {
        return Math.floor(Math.random() * 10)
      }
      
      // Use the random number function as a default parameter for the cube function
      function cube(x = getRandomNumber()) {
        return x * x * x
      }
      

      Now invoking the cube function without a parameter will have potentially different results every time you call it:

      // Invoke cube function twice for two potentially different results
      cube()
      cube()
      

      The output from these function calls will vary:

      Output

      512 64

      You can even use built-in methods, like those on the Math object, and use the value returned in one function call as a parameter in another function.

      In the following example, a random number is assigned to x, which is used as the parameter in the cube function you created. The y parameter will then calculate the cube root of the number and check to see if x and y are equal:

      // Assign a random number to x
      // Assign the cube root of the result of the cube function and x to y
      function doesXEqualY(x = getRandomNumber(), y = Math.cbrt(cube(x))) {
        return x === y
      }
      
      doesXEqualY()
      

      This will give the following:

      Output

      true

      A default parameter can even be a function definition, as seen in this example, which defines a parameter as the inner function and returns the function call of parameter:

      // Define a function with a default parameter that is an anonymous function
      function outer(
        parameter = function inner() {
          return 100
        }
      ) {
        return parameter()
      }
      
      // Invoke outer function
      outer()
      

      Output

      100

      This inner function will be created from scratch every time the outer function is invoked.

      Conclusion

      In this article, you learned what default function parameters are and how to use them. Now you can use default parameters to help keep your functions clean and easy to read. You can also assign empty objects and arrays to parameters upfront to reduce both complexity and lines of code when dealing with situations such as retrieving values from an object or looping through an array.

      If you would like to learn more about JavaScript, check out the homepage for our How To Code in JavaScript series, or browse our How to Code in Node.js series for articles on back-end development.



      Source link