One place for hosting & domains

      Statements

      How To Write Conditional Statements in PHP


      The author selected Open Sourcing Mental Illness Ltd to receive a donation as part of the Write for DOnations program.

      Introduction

      Decisions are an integral part of life. From the mundane decisions about what to wear, to the life-altering decisions of jobs and family. So too in development. For a program to do anything useful, it must be able to respond to some sort of input. When a person clicks the contact button on a website, they expect to be taken to a contact page. If nothing happens, or they are taken to the wrong page, the user may choose to stop using that website or company completely.

      Decisions written in code are formed using conditionals: “If x, then y.” Even a button click is a form of condition: “If this button is clicked, go to a certain page.” Conditional statements are part of the logic, decision making, or flow control of a computer program. You can compare a conditional statement to a “Choose Your Own Adventure” book, or a flowchart.

      Let’s look at some examples where we would use conditional statements:

      • If the student receives over 65% on her test, report that her grade passes; if not, report that her grade fails.
      • If there is money in an account, calculate interest; if it is overdrawn, charge a penalty fee.
      • If they buy 10 oranges or more, calculate a discount of 5%; if they buy fewer, then don’t.
      • Check the location of a user and display the correct language based on country.
      • Send a form on submit, or display warnings next to missing required fields.
      • Open a dropdown on a click event, or close a dropdown if it is already open.
      • Display the booking form for a hotel, but not if the hotel is booked.

      When evaluating conditions and assigning code to run based on whether or not those conditions are met, we are writing conditional code.

      This tutorial will start with an overview of the comparison operators that will be used to build conditional statements. Next, it will take you through writing conditional statements in PHP, including the if, else, and elseif keywords. This also includes combining conditions using the logical operators of and or or. Finally it will also cover some special conditional operators to more precisely describe a situation.

      Overview of Comparison Operators

      A conditional statement evaluates whether a condition is true or false. This is most often the result of comparing two values. Comparison operators are used, as their name implies, to compare two values. PHP is a loosely typed language, which means, by default, PHP will attempt to change a data type to match an expected result when possible. This is called type juggling, and becomes very important when using comparison operators. As an example, all of the following values would be considered equal even though they are of different types:

      false
      0
      0.0
      ''
      

      PHP provides several comparison operators to express the desired comparison of both value and type/value combined:

      • Equal == in value, after type juggling, meaning all of the values in the previous code block are equal.

      • Identical === in both type and value, meaning none of the previous values are identical, because they are all of different types.

      • Not Equal != or <> in value, after type juggling. As the opposite of equal, comparing false != 0 would evaluate as false because the values match.

      • Not Identical !== in both type and value. Comparing false !== 0 would evaluate to true because although the values evaluate the same, the type is different.

      Note: Pay special attention to the exclamation point !, which functions to negate other conditions.

      Besides equal and identical, PHP also provides comparison operators to express how the values relate to one another.

      • Less than < is used to show that 5 < 6 is true.

      • Greater than > is used to show that 5 > 4 is true.

      • Less than or equal to <= is used so show that both 5 <= 5 and 5 <= 6 are true.

      • Greater than or equal to >= is used to show that both 5 >= 5 and 5 >= 4 are true.

      Now that we know what the comparison operators are, we can look at how to use them to write conditional statements.

      Writing Conditional Statements

      Comparison operators are used in combination with the if, else, and elseif keywords to build conditional statements that control the flow of a program.

      Using if Statements

      When we wish to execute a specific piece of code only when a condition is met, we use the conditional if statement, followed by the condition in parentheses (), followed by the code to execute within curly braces {}. The code within the conditional statement will only be executed if the condition evaluates to true. When the condition is not true, the code within the conditional statement is ignored and processing continues after the close of the conditional statement. Let’s see how this would look in code:

      if ($inventory > 0) {
          echo "Add to Cart";
      }
      

      The string “Add to Cart” will only be displayed when the variable $inventory contains a number greater than 0.

      Alternately, if there is only a single expression after the condition, PHP allows us to leave off the curly braces entirely. PHP will execute the first expression after a condition, ending in a semicolon. This includes any whitespace between them. The following evaluates the same way as the previous example:

      if ($inventory > 0) echo "Add to Cart";
      

      Using an else Block

      When we wish to execute either one specific piece of code or another, we add an else block to the conditional if statement. The code within the if block will only be executed if the statement evaluates to true, while the code within the else bock will only be executed when the statement is not true. Let’s take a look at an example where shoppers are given a discount if they purchase 10 or more items:

      if (count($cart) >= 10) {
          $discount = $subtotal * .3;
      } else {
          $discount = 0;
      }
      

      When the number of items in the cart is greater than or equal to 10, the statement evaluates to true, and a discount of 30% is calculated, based on the $subtotal. When the number of items in the cart is less than 10, the statement evaluates to false and the else block is executed, which gives no discount. The comparison could also be written as count($cart) > 9.

      Note: You cannot use the percent sign % when calculating the percent, because % is used to calculate the modulo, which is the remainder of $a divided by $b: 3 % 8 = 2. Instead, to calculate a percent, convert the percentage to a decimal by dividing it by 100. So 30% is 30/100, or 0.30, or 0.3. For more, check out How to Work with Numbers in PHP.

      Adding an else block can sometime make code more confusing. It’s worth considering whether or not we can accomplish the same thing without the else block. For example, the previous conditional could also be written as follows:

      $discount = 0;
      if (count($cart) >= 10) {
          $discount = $subtotal * .3;
      }
      

      We set a default value of 0 for the discount and only change it when the condition is met.

      Writing an elseif Statement

      When a second condition is needed, you could add a second conditional statement:

      $discount = 0;
      if (count($cart) >= 5) {
          $discount = $subtotal * .15
      }
      if (count($cart) >= 10) {
          $discount = $subtotal * .3;
      }
      

      When adding a second statement in this way, PHP must check each statement, even if the first statement has been matched. If there are 14 items in the cart, the first conditional statement would evaluate to true, because 14 is greater than or equal to 5, which would set the discount to 15%. After that, the second conditional statement would also evaluate to true, because 14 is also greater than or equal to 10, once again setting the discount which overrides the value to 30%.

      This could also end up returning the wrong discount if the conditions are not in the correct order. When there is the possibility of matching multiple conditions, it’s a good idea to double check that you are evaluating those conditions in the correct order.

      The code could be clarified and evaluated more cleanly by using the elseif block:

      $discount = 0;
      if (count($cart) >= 10) {
          $discount = $subtotal * .3;
      } elseif (count($cart) >= 5) {
          $discount = $subtotal * .15
      }
      

      In this case, the code first checks for a value greater than or qual to 10. If this first statement evaluates to true, the code within the first conditional block is executed and the other conditional statements are never evaluated. Only when the first condition is not met is the next condition evaluated.

      A conditional statement may have any number of elseif conditions, but only a single else.

      Nested Conditional Statements

      Like nesting dolls, conditional statements may contain other conditional statements “nested” within them. When nesting conditional statements, using consistent indentation helps tremendously with readability. Let’s expand upon our discounts to give more options:

      $discount = 0;
      if ($country === 'USA') {
          if (count($cart) >= 10) {
              if ($coupon_discount > .3) {
                  $discount = $subtotal * $coupon_discount;
              } else {
                  $discount = $subtotal * .3;
              }
          } elseif (count($cart) >= 5) {
              if ($coupon_discount > .15) {
                  $discount = $subtotal * $coupon_discount;
              } else {
                  $discount = $subtotal * .15
              }
          }
      }
      

      In this example, the discounts are only available for those in the US, so before we check for any discount, we first verify that the $country variable is set to USA. The rest of the conditionals will only be reached if that first condition is true.

      Next we check if the number of items in the cart is greater than or equal to 10. If this second condition is true, then we check if the value of a $coupon_discount is greater than the normal 30% discount for ordering 10 or more items. If this third condition is true, then use the $coupon_discount to calculate the $discount. Otherwise, this third condition is false, then use the normal 30% to calculate the discount.

      This brings us to the else block of the second condition. Instead of just else, the elseif block is used to verify that the number of items in the cart is greater than or equal to 5 before giving the option for a secondary discount. Once again we check for a value in the $coupon_discount variable that is greater than the secondary volume discount of 15%. If this fourth condition is true, the $coupon_discount is used to calculate the $discount. Otherwise, this fourth condition is false, then we reach the last discount of 15%.

      Nested conditional statements, like the one we just looked at, can be hard to follow, especially if you start adding additional levels. When possible, consider how you might rewrite a conditional statement to remove nesting. The previous condition could also be written as follows:

      $discount = 0;
      if ($country !== 'USA') {
          // no discount for non-us locations
      } elseif ($coupon_discount > .3) {
          $discount = $subtotal * $coupon_discount;
      } elseif (count($cart) >= 10) {
          $discount = $subtotal * .3;
      } elseif ($coupon_discount > .15) {
          $discount = $subtotal * $coupon_discount;
      } elseif (count($cart) >= 5) {
          $discount = $subtotal * .15;
      }
      

      Because PHP allows an empty conditional block, we can check for country first and skip any other conditions. Take careful note of the negative expression !== meaning that the country does not match the value USA. Although you can leave a block completely empty, adding a comment explains the intention to leave that block empty.

      For the elseif blocks, we start with the most restrictive and work our way down. Someone in the USA with a coupon worth 20% (.2) would have the first 3 blocks evaluate to false. Then they would reach the third elseif, which would evaluate to true because .2 is greater than .15. The discount would be calculated and the final condition block would be passed over.

      Alternative Syntax

      The most common syntax for conditional statements is using curly braces, as the previous examples showed. PHP does provide an alternative syntax which can make things easier to read when there are long blocks of code between each conditional, or when a loop, which also uses curly braces, is used within a conditional. This alternative syntax is written using colons after the conditional statement and finalizing the conditional block with an endif; statement. The discount example could be written with this alternative syntax as follows:

      $discount = 0;
      if ($country !== 'USA'):
          // no discount for non-us locations
      elseif ($coupon_discount > .3):
          $discount = $subtotal * $coupon_discount;
      elseif (count($cart) >= 10):
          $discount = $subtotal * .3;
      elseif ($coupon_discount > .15):
          $discount = $subtotal * $coupon_discount;
      elseif (count($cart) >= 5):
          $discount = $subtotal * .15;
      else:
          $discount = $subtotal * .05;
      endif;
      

      While nesting a loop within these conditional blocks is acceptable, nesting curly brace conditionals within these conditional blocks may lead to unexpected results. It’s best to stick with either curly braces or colons.

      Note: Because of the way PHP handles whitespace, it will accept spaces between else and if when using curly braces: } else if (...){. However, PHP will fail with a parse error if you use a space when using a colon to define your statement: elseif (...):. In practice, it’s a good idea to avoid spaces and always write this as the single elseif.

      Additional Comparisons Operators

      Using a single comparison operator in each conditional statement is not the only way to use comparison operators. Not only can we combine conditions, we can also use comparison operators outside of a conditional.

      Combining Conditions Using Logical Operators

      When there are multiple conditions that both need to be true, or multiple conditions which would have the same affect, the conditional statements may be combined into a single block using Logical Operators.

      • And and says that both conditions must be true.

      • Or or says that either condition is true or they could both be true.

      • Xor xor says that only one of the conditions is true.

      • Not ! is used to negate a condition, which changes it from evaluating true to evaluating false.

      • And && says that both conditions must be true.

      • Or || says that either condition is true or they could both be true.

      The reason for the two different variations of and and or operators is that they operate at different precedences. The precedence of an operator specifies how “tightly” it binds two expressions together, or in what order the operations are evaluated. (See Documentation for Operator Precedence.) Either way is perfectly acceptable and works the same in most situations. Operators in PHP are case-insensitive, meaning the operator could also be written as OR (or even Or or oR, neither of which would I recommend). To minimize confusion, the most important thing is to be consistent in whichever you choose. I’ll be using and and or in the examples because they are more natural to read.

      Using this in the discount example: To check that both the $country variable is set to USA and that the items in the cart are greater than or equal to 10, those conditions can be combined using the and operator:

      $discount = 0;
      if ($country === 'USA' and count($cart) >= 10) {
          $discount = $subtotal * .3;
      }
      

      The example has two conditions $country === 'USA' and count($cart) >= 10. If either of these conditions evaluates to true, the code within that block will be executed. This example used the and operator, but it could also have used AND or even the && operator with the exact same results.

      We can also combine conditions that would have to same result. If having 10 or more items in the cart produces a discount of 30%, or having a subtotal of $100 or more would also produce a discount of 30%, these conditionals could be combined:

      $discount = 0;
      if (count($cart) >= 10 or $subtotal >= 100) {
          $discount = $subtotal * .3;
      }
      

      More than two conditions can also be combined; however, be extra cautious in their use. Let’s try to combine the country evaluation along with the cart count and subtotal comparison:

      # BAD
      $discount = 0;
      if ($country === 'USA' and count($cart) >= 10 or $subtotal >= 100) {
          $discount = $subtotal * .3;
      }
      

      This example doesn’t actually work the way it was intended because the country is evaluated with the count of the cart first, then that result is evaluated against the subtotal comparison using or. This means that no matter what the country or count values, if $subtotal is greater than or equal to 100, the full conditional statement will evaluate to true.

      Parentheses can be used to make sure that the conditions are evaluated in the intended order:

      $discount = 0;
      if ($country === 'USA' and (count($cart) >= 10 or $subtotal >= 100)) {
          $discount = $subtotal * .3;
      }
      

      Now the cart count is evaluated with the subtotal comparison before the country is evaluated with that result. This provides the desired outcome of requiring $country to have the value of USA and then either the count of the cart or the comparison of the subtotal (or both) must also evaluate to true.

      Sometime an entire conditional block is not required to compare two values. PHP provides a few shorthand comparison operators to more precisely describe a situation.

      Ternary Operator

      When there should be one result if an expression is true and another result if that same expression is false, a ternary operator can be used. The expression (expr1) ? (expr2) : (expr3) evaluates to expr2 if expr1 evaluates to true, and expr3 if expr1 evaluates to false. Let’s say that the username of a visitor should be shown if they are logged in, while the word “Guest” should be displayed if not. The function isset will help us to evaluate this condition because it will check that a variable has actually been defined. If the variable is defined, isset returns true; if not, isset returns false:

      echo (isset($username)) ? 'Guest' : $username;
      

      This is identical to this if/else statement:

      if (isset($username)) {
          echo 'Guest';
      } else {
          echo $username;
      }
      

      It is possible to leave out the middle part of the ternary operator. The expression expr1 ?: expr3 returns expr1 if expr1 evaluates to true, and expr3 otherwise. To show either the username or the word “Guest”, the ternary operator would look something like:

      echo $username ?: 'Guest';
      

      This works if $username is set to an empty string, but if $username is not set at all, we get an error. The isset function cannot be used in this situation, because the output of isset($username) would either be true or false, instead of the value of $username. This brings us to our next operator.

      Null Coalescing Operator

      The null coalescing operator (??) has been added as “syntactic sugar” (sweet to have but not required) for the common case of needing to use a ternary in conjunction with isset(). It returns its first operand if it exists and is not null; otherwise it returns its second operand. To show either the username or the word “Guest”, the null coalescing operator is used:

      echo $username ?? 'Guest';
      

      Spaceship Operator

      The spaceship operator (<=>) is used for comparing two expressions: $a <=> $b. It returns -1, 0, or 1 when $a is respectively less than (<), equal to (=), or greater than (>) $b:

      echo 1 <=> 1; // 0
      echo 1 <=> 2; // -1
      echo 2 <=> 1; // 1
      

      Warning: Although the spaceship operator is not used often, it comes in very handy when writing a “user defined sort” (usort) function. The following example includes additional concepts you may not be familiar with yet. Don’t worry if you don’t follow all of the code right now. I’ll explain what’s going on in the example, and we’ll cover these concepts in more depth in a later tutorial.

      Let’s create an array of new products. Each product in the array will, in turn, be its own nested array of product attributes:

      $products = [
          ['name'=>'Flippers', 'price'=>7.99],
          ['name'=>'Wet Suit', 'price'=>18.99),
          ['name'=>'Snorkel', 'price'=>2.99),
          ['name'=>'Mask', 'price'=>6.99),
      ];
      

      Now let’s say we want to sort this $products array by the price of each item, in descending order. We can do this by using the usort function, into which we then pass an anonymous function which handles the sorting logic. Let’s look at the code:

      usort($products, function($item1, $item2) {
          return $item2["price"] <=> $item1["price"];
      });
      

      The usort function is taking two arguments (the values passed to a function). The first argument is the $products array. The second is an anonymous function which tells the usort function what to do with each item in the array. If the price of $item2 is less than the price of $item1, the operator will return -1, which will move $item2 before $item1. If the prices are the same, the operator will return 0, which will keep the items in the same order. Finally, if the price of $item2 is greater than the price of $item1, the operator will return 1, which will put $item2 after $item1, which again is the same order in which they started.

      To sort by price in ascending order instead, we flip the position of $item1 and $item2, which changes the order of the comparison:

      usort($products, function($item1, $item2) {
          return $item1["price"] <=> $item2["price"];
      });
      

      Conclusion

      Conditional statements provide us with flow control to determine the output choices of our programs. They are one of the foundational building blocks of programming, and can be found in virtually all programming languages.

      This tutorial covered both comparison operators for comparing values and logical operators for combining conditions. It demonstrated the use of the if, else, and elseif keywords while looking at nested statements and combining conditions. Finally it introduced the use of additional comparison operators, including the ternary operator, null coalescing operator, and the spaceship operator. To continue practicing conditional statements:

      • Try using different operators: <, >, ==, ===
      • Combine operators with and or or
      • Recreate an if statement using a ternary, null coalescing, or spaceship operator

      For more information on how to code in PHP, check out other tutorials in the How To Code in PHP series.



      Source link

      Understanding Modules and Import and Export Statements in JavaScript


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

      Introduction

      In the early days of the Web, websites consisted primarily of HTML and CSS. If any JavaScript loaded into a page at all, it was usually in the form of small snippets that provided effects and interactivity. As a result, JavaScript programs were often written entirely in one file and loaded into a script tag. A developer could break the JavaScript up into multiple files, but all variables and functions would still be added to the global scope.

      But as websites have evolved with the advent of frameworks like Angular, React, and Vue, and with companies creating advanced web applications instead of desktop applications, JavaScript now plays a major role in the browser. As a result, there is a much greater need to use third-party code for common tasks, to break up code into modular files, and to avoid polluting the global namespace.

      The ECMAScript 2015 specification introduced modules to the JavaScript language, which allowed for the use of import and export statements. In this tutorial, you will learn what a JavaScript module is and how to use import and export to organize your code.

      Modular Programming

      Before the concept of modules appeared in JavaScript, when a developer wanted to organize their code into segments, they would create multiple files and link to them as separate scripts. To demonstrate this, create an example index.html file and two JavaScript files, functions.js and script.js.

      The index.html file will display the sum, difference, product, and quotient of two numbers, and link to the two JavaScript files in script tags. Open index.html in a text editor and add the following code:

      index.html

      <!DOCTYPE html>
      <html lang="en">
        <head>
          <meta charset="utf-8" />
          <meta name="viewport" content="width=device-width, initial-scale=1.0" />
      
          <title>JavaScript Modules</title>
        </head>
      
        <body>
          <h1>Answers</h1>
          <h2><strong id="x"></strong> and <strong id="y"></strong></h2>
      
          <h3>Addition</h3>
          <p id="addition"></p>
      
          <h3>Subtraction</h3>
          <p id="subtraction"></p>
      
          <h3>Multiplication</h3>
          <p id="multiplication"></p>
      
          <h3>Division</h3>
          <p id="division"></p>
      
          <script src="https://www.digitalocean.com/community/tutorials/functions.js"></script>
          <script src="https://www.digitalocean.com/community/tutorials/script.js"></script>
        </body>
      </html>
      

      This HTML will display the value of variables x and y in an h2 header, and the value of operations on those variables in the following p elements. The id attributes of the elements are set for DOM manipulation, which will happen in the script.js file; this file will also set the values of x and y. For more information on HTML, check out our How To Build a Website with HTML series.

      The functions.js file will contain the mathematical functions that will be used in the second script. Open the functions.js file and add the following:

      functions.js

      function sum(x, y) {
        return x + y
      }
      
      function difference(x, y) {
        return x - y
      }
      
      function product(x, y) {
        return x * y
      }
      
      function quotient(x, y) {
        return x / y
      }
      

      Finally, the script.js file will determine the values of x and y, apply the functions to them, and display the result:

      script.js

      
      const x = 10
      const y = 5
      
      document.getElementById('x').textContent = x
      document.getElementById('y').textContent = y
      
      document.getElementById('addition').textContent = sum(x, y)
      document.getElementById('subtraction').textContent = difference(x, y)
      document.getElementById('multiplication').textContent = product(x, y)
      document.getElementById('division').textContent = quotient(x, y)
      

      After setting up these files and saving them, you can open index.html in a browser to display your website with all the results:

      Rendered HTML with the values 10 and 5 and the results of the functions.js operations.

      For websites with a few small scripts, this is an effective way to divide the code. However, there are some issues associated with this approach, including:

      • Polluting the global namespace: All the variables you created in your scripts—sum, difference, etc.—now exist on the window object. If you attempted to use another variable called sum in another file, it would become difficult to know which value would be used at any point in the scripts, since they would all be using the same window.sum variable. The only way a variable could be private was by putting it within a function scope. There could even be a conflict between an id in the DOM named x and var x.
      • Dependency management: Scripts would have to be loaded in order from top to bottom to ensure the correct variables were available. Saving the scripts as different files gives the illusion of separation, but it is essentially the same as having a single inline <script> in the browser page.

      Before ES6 added native modules to the JavaScript language, the community attempted to come up with several solutions. The first solutions were written in vanilla JavaScript, such as writing all code in objects or immediately invoked function expressions (IIFEs) and placing them on a single object in the global namespace. This was an improvement on the multiple script approach, but still had the same problems of putting at least one object in the global namespace, and did not make the problem of consistently sharing code between third parties any easier.

      After that, a few module solutions emerged: CommonJS, a synchronous approach that was implemented in Node.js, Asynchronous Module Definition (AMD), which was an asynchronous approach, and Universal Module Definition (UMD), which was intended to be a universal approach that supported both previous styles.

      The advent of these solutions made it easier for developers to share and reuse code in the form of packages, modules that can be distributed and shared, such as the ones found on npm. However, since there were many solutions and none were native to JavaScript, tools like Babel, Webpack, or Browserify had to be implemented to use modules in browsers.

      Due to the many problems with the multiple file approach and the complexity of the solutions proposed, developers were interested in bringing the modular programming approach to the JavaScript language. Because of this, ECMAScript 2015 supports the use of JavaScript modules.

      A module is a bundle of code that acts as an interface to provide functionality for other modules to use, as well as being able to rely on the functionality of other modules. A module exports to provide code and imports to use other code. Modules are useful because they allow developers to reuse code, they provide a stable, consistent interface that many developers can use, and they do not pollute the global namespace.

      Modules (sometimes referred to as ECMAScript modules or ES Modules) are now available natively in JavaScript, and in the rest of this tutorial you will explore how to use and implement them in your code.

      Native JavaScript Modules

      Modules in JavaScript use the import and export keywords:

      • import: Used to read code exported from another module.
      • export: Used to provide code to other modules.

      To demonstrate how to use this, update your functions.js file to be a module and export the functions. You will add export in front of each function, which will make them available to any other module.

      Add the following highlighted code to your file:

      functions.js

      export function sum(x, y) {
        return x + y
      }
      
      export function difference(x, y) {
        return x - y
      }
      
      export function product(x, y) {
        return x * y
      }
      
      export function quotient(x, y) {
        return x / y
      }
      

      Now, in script.js, you will use import to retrieve the code from the functions.js module at the top of the file.

      Note: import must always be at the top of the file before any other code, and it is also necessary to include the relative path (./ in this case).

      Add the following highlighted code to script.js:

      script.js

      
      import { sum, difference, product, quotient } from './functions.js'
      
      const x = 10
      const y = 5
      
      document.getElementById('x').textContent = x
      document.getElementById('y').textContent = y
      
      document.getElementById('addition').textContent = sum(x, y)
      document.getElementById('subtraction').textContent = difference(x, y)
      document.getElementById('multiplication').textContent = product(x, y)
      document.getElementById('division').textContent = quotient(x, y)
      

      Notice that individual functions are imported by naming them in curly braces.

      In order to ensure this code gets loaded as a module and not a regular script, add type="module" to the script tags in index.html. Any code that uses import or export must use this attribute:

      index.html

      ...
      <script type="module" src="https://www.digitalocean.com/community/tutorials/functions.js"></script>
      <script type="module" src="https://www.digitalocean.com/community/tutorials/script.js"></script>
      

      At this point, you will be able to reload the page with the updates and the website will now use modules. Browser support is very high, but caniuse is available to check which browsers support it. Note that if you are viewing the file as a direct link to a local file, you will encounter this error:

      Output

      Access to script at 'file:///Users/your_file_path/script.js' from origin 'null' has been blocked by CORS policy: Cross-origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, chrome-untrusted, https.

      Because of the CORS policy, Modules must be used in a server environment, which you can set up locally with http-server or on the internet with a hosting provider.

      Modules are different from regular scripts in a few ways:

      • Modules do not add anything to the global (window) scope.
      • Modules always are in strict mode.
      • Loading the same module twice in the same file will have no effect, as modules are only executed once.
      • Modules require a server environment.

      Modules are still often used alongside bundlers like Webpack for increased browser support and additional features, but they are also available for use directly in browsers.

      Next, you will explore some more ways in which the import and export syntax can be used.

      Named Exports

      As demonstrated earlier, using the export syntax will allow you to individually import values that have been exported by their name. For example, take this simplified version of functions.js:

      functions.js

      export function sum() {}
      export function difference() {}
      

      This would let you import sum and difference by name using curly braces:

      script.js

      import { sum, difference } from './functions.js'
      

      It is also possible to use an alias to rename the function. You might do this to avoid naming conflicts within the same module. In this example, sum will be renamed to add and difference will be renamed to subtract.

      script.js

      import {
        sum as add,
        difference as subtract
      } from './functions.js'
      
      add(1, 2) // 3
      

      Calling add() here will yield the result of the sum() function.

      Using the * syntax, you can import the contents of the entire module into one object. In this case, sum and difference will become methods on the mathFunctions object.

      script.js

      import * as mathFunctions from './functions.js'
      
      mathFunctions.sum(1, 2) // 3
      mathFunctions.difference(10, 3) // 7
      

      Primitive values, function expressions and definitions, asynchronous functions, classes, and instantiated classes can all be exported, as long as they have an identifier:

      // Primitive values
      export const number = 100
      export const string = 'string'
      export const undef = undefined
      export const empty = null
      export const obj = { name: 'Homer' }
      export const array = ['Bart', 'Lisa', 'Maggie']
      
      // Function expression
      export const sum = (x, y) => x + y
      
      // Function definition
      export function difference(x, y) {
        return x - y
      }
      
      // Asynchronous function
      export async function getBooks() {}
      
      // Class
      export class Book {
        constructor(name, author) {
          this.name = name
          this.author = author
        }
      }
      
      // Instantiated class
      export const book = new Book('Lord of the Rings', 'J. R. R. Tolkien')
      

      All of these exports can be successfully imported. The other type of export that you will explore in the next section is known as a default export.

      Default Exports

      In the previous examples, you exported multiple named exports and imported them individually or as one object with each export as a method on the object. Modules can also contain a default export, using the default keyword. A default export will not be imported with curly brackets, but will be directly imported into a named identifier.

      For example, take the following contents for the functions.js file:

      functions.js

      export default function sum(x, y) {
        return x + y
      }
      

      In the script.js file, you could import the default function as sum with the following:

      script.js

      import sum from './functions.js'
      
      sum(1, 2) // 3
      

      This can be dangerous, as there are no restrictions on what you can name a default export during the import. In this example, the default function is imported as difference although it is actually the sum function:

      script.js

      import difference from './functions.js'
      
      difference(1, 2) // 3
      

      For this reason, it is often preferred to use named exports. Unlike named exports, default exports do not require an identifier—a primitive value by itself or anonymous function can be used as a default export. Following is an example of an object used as a default export:

      functions.js

      export default {
        name: 'Lord of the Rings',
        author: 'J. R. R. Tolkien',
      }
      

      You could import this as book with the following:

      script.js

      import book from './functions.js'
      

      Similarly, the following example demonstrates exporting an anonymous arrow function as the default export:

      functions.js

      export default () => 'This function is anonymous'
      

      This could be imported with the following script.js:

      script.js

      import anonymousFunction from './functions.js'
      

      Named exports and default exports can be used alongside each other, as in this module that exports two named values and a default value:

      functions.js

      export const length = 10
      export const width = 5
      
      export default function perimeter(x, y) {
        return 2 * (x + y)
      }
      

      You could import these variables and the default function with the following:

      script.js

      import calculatePerimeter, { length, width } from './functions.js'
      
      calculatePerimeter(length, width) // 30
      

      Now the default value and named values are both available to the script.

      Conclusion

      Modular programming design practices allow you to separate code into individual components that can help make your code reusable and consistent, while also protecting the global namespace. A module interface can be implemented in native JavaScript with the import and export keywords.

      In this article, you learned about the history of modules in JavaScript, how to separate JavaScript files into multiple top-level scripts, how to update those files using a modular approach, and the import and export syntax for named and default exports.

      To learn more about modules in JavaScript, read Modules on the Mozilla Developer Network. If you’d like to explore modules in Node.js, try our How To Create a Node.js Module tutorial.



      Source link

      How To Write Switch Statements in Go


      Introduction

      Conditional statements give programmers the ability to direct their programs to take some action if a condition is true and another action if the condition is false. Frequently, we want to compare some variable against multiple possible values, taking different actions in each circumstance. It’s possible to make this work using if statements alone. Writing software, however, is not only about making things work but also communicating your intention to your future self and other developers. switch is an alternative conditional statement useful for communicating actions taken by your Go programs when presented with different options.

      Everything we can write with the switch statement can also be written with if statements. In this tutorial, we’ll look at a few examples of what the switch statement can do, the if statements it replaces, and where it’s most appropriately applied.

      Structure of Switch Statements

      Switch is commonly used to describe the actions taken by a program when a variable is assigned specific values. The following example demonstrates how we would accomplish this using if statements:

      package main
      
      import "fmt"
      
      func main() {
          flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
      
          for _, flav := range flavors {
              if flav == "strawberry" {
                  fmt.Println(flav, "is my favorite!")
                  continue
              }
      
              if flav == "vanilla" {
                  fmt.Println(flav, "is great!")
                  continue
              }
      
              if flav == "chocolate" {
                  fmt.Println(flav, "is great!")
                  continue
              }
      
              fmt.Println("I've never tried", flav, "before")
          }
      }
      

      This will generate the following output:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      Within main, we define a slice of ice-cream flavors. We then use a for loop to iterate through them. We use three if statements to print out different messages indicating preferences for different ice-cream flavors. Each if statement must use the continue statement to stop execution of the for loop so that the default message at the end is not printed for the preferred ice-cream flavors.

      As we add new ice-cream preferences, we have to keep adding if statements to handle the new cases. Duplicated messages, as in the case of "vanilla" and "chocolate", must have duplicated if statements. To future readers of our code (ourselves included), the repetitive nature of the if statements obscures the important part of what they are doing—comparing the variable against multiple values and taking different actions. Also, our fallback message is set apart from the conditionals, making it appear unrelated. The switch statement can help us organize this logic better.

      The switch statement begins with the switch keyword and is followed, in its most basic form, with some variable to perform comparisons against. This is followed by a pair of curly braces ({}) where multiple case clauses can appear. Case clauses describe the actions your Go program should take when the variable provided to the switch statement equals the value referenced by the case clause. The following example converts the previous example to use a switch instead of multiple if statements:

      package main
      
      import "fmt"
      
      func main() {
          flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
      
          for _, flav := range flavors {
              switch flav {
              case "strawberry":
                  fmt.Println(flav, "is my favorite!")
              case "vanilla", "chocolate":
                  fmt.Println(flav, "is great!")
              default:
                  fmt.Println("I've never tried", flav, "before")
              }
          }
      }
      

      The output is the same as before:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! I've never tried banana before

      We’ve once again defined a slice of ice-cream flavors in main and used the range statement to iterate over each flavor. This time, however, we’ve used a switch statement that will examine the flav variable. We use two case clauses to indicate preferences. We no longer need continue statements as only one case clause will be executed by the switch statement. We’re also able to combine the duplicated logic of the "chocolate" and "vanilla" conditionals by separating each with a comma in the declaration of the case clause. The default clause serves as our catch-all clause. It will run for any flavors that we haven’t accounted for in the body of the switch statement. In this case, "banana" will cause default to execute, printing the message I've never tried banana before.

      This simplified form of switch statements addresses the most common use for them: comparing a variable against multiple alternatives. It also provides conveniences for us where we want to take the same action for multiple different values and some other action when none of the listed conditions are met by using the provided default keyword.

      When this simplified form of switch proves too limiting, we can use a more general form of switch statement.

      General Switch Statements

      switch statements are useful for grouping collections of more complicated conditionals to show that they are somehow related. This is most commonly used when comparing some variable against a range of values, rather than specific values as in the earlier example. The following example implements a guessing game using if statements that could benefit from a switch statement:

      package main
      
      import (
          "fmt"
          "math/rand"
          "time"
      )
      
      func main() {
          rand.Seed(time.Now().UnixNano())
          target := rand.Intn(100)
      
          for {
              var guess int
              fmt.Print("Enter a guess: ")
              _, err := fmt.Scanf("%d", &guess)
              if err != nil {
                  fmt.Println("Invalid guess: err:", err)
                  continue
              }
      
              if guess > target {
                  fmt.Println("Too high!")
                  continue
              }
      
              if guess < target {
                  fmt.Println("Too low!")
                  continue
              }
      
              fmt.Println("You win!")
              break
          }
      }
      

      The output will vary depending on the random number selected and how well you play the game. Here is the output from one example session:

      Output

      Enter a guess: 10 Too low! Enter a guess: 15 Too low! Enter a guess: 18 Too high! Enter a guess: 17 You win!

      Our guessing game needs a random number to compare guesses against, so we use the rand.Intn function from the math/rand package. To make sure we get different values for target each time we play the game, we use rand.Seed to randomize the random number generator based on the current time. The argument 100 to rand.Intn will give us a number in the range 0–100. We then use a for loop to begin collecting guesses from the player.

      The fmt.Scanf function gives us a means to read user input into a variable of our choosing. It takes a format string verb that converts the user’s input into the type we expect. %d here means we expect an int, and we pass the address of the guess variable so that fmt.Scanf is able to set that variable. After handling any parsing errors we then use two if statements to compare the user’s guess to the target value. The string that they return, along with bool, controls the message displayed to the player and whether the game will exit.

      These if statements obscure the fact that the range of values that the variable is being compared against are all related in some way. It can also be difficult, at a glance, to tell if we missed some part of the range. The next example refactors the previous example to use a switch statement instead:

      package main
      
      import (
          "fmt"
          "math/rand"
      )
      
      func main() {
          target := rand.Intn(100)
      
          for {
              var guess int
              fmt.Print("Enter a guess: ")
              _, err := fmt.Scanf("%d", &guess)
              if err != nil {
                  fmt.Println("Invalid guess: err:", err)
                  continue
              }
      
              switch {
              case guess > target:
                  fmt.Println("Too high!")
              case guess < target:
                  fmt.Println("Too low!")
              default:
                  fmt.Println("You win!")
                  return
              }
          }
      }
      

      This will generate output similar to the following:

      Output

      Enter a guess: 25 Too low! Enter a guess: 28 Too high! Enter a guess: 27 You win!

      In this version of the guessing game, we’ve replaced the block of if statements with a switch statement. We omit the expression argument to switch because we are only interested in using switch to collect conditionals together. Each case clause contains a different expression comparing guess against target. Similar to the first time we replaced if statements with switch, we no longer need continue statements since only one case clause will be executed. Finally, the default clause handles the case where guess == target since we have covered all other possible values with the other two case clauses.

      In the examples that we’ve seen so far, exactly one case statement will be executed. Occasionally, you may wish to combine the behaviors of multiple case clauses. switch statements provide another keyword for achieving this behavior.

      Fallthrough

      Sometimes you will want to reuse the code that another case clause contains. In these cases, it’s possible to ask Go to run the body of the next case clause listed using the fallthrough keyword. This next example modifies our earlier ice cream flavor example to more accurately reflect our enthusiasm for strawberry ice cream:

      package main
      
      import "fmt"
      
      func main() {
          flavors := []string{"chocolate", "vanilla", "strawberry", "banana"}
      
          for _, flav := range flavors {
              switch flav {
              case "strawberry":
                  fmt.Println(flav, "is my favorite!")
                  fallthrough
              case "vanilla", "chocolate":
                  fmt.Println(flav, "is great!")
              default:
                  fmt.Println("I've never tried", flav, "before")
              }
          }
      }
      

      We will see this output:

      Output

      chocolate is great! vanilla is great! strawberry is my favorite! strawberry is great! I've never tried banana before

      As we’ve seen previously, we define a slice of string to represent flavors and iterate through this using a for loop. The switch statement here is identical to the one we’ve seen before, but with the addition of the fallthrough keyword at the end of the case clause for "strawberry". This will cause Go to run the body of case "strawberry":, first printing out the string strawberry is my favorite!. When it encounters fallthrough it will run the body of the next case clause. This will cause the body of case "vanilla", "chocolate": to run, printing strawberry is great!.

      The fallthrough keyword is not used often by Go developers. Usually, the code reuse realized by using fallthrough can be better obtained by defining a function with the common code. For these reasons, using fallthrough is generally discouraged.

      Conclusion

      switch statements help us convey to other developers reading our code that a set of comparisons are somehow related to each other. They make it much easier to add different behavior when a new case is added in the future and make it possible to ensure that anything we forgot is handled properly as well with default clauses. The next time you find yourself writing multiple if statements that all involve the same variable, try rewriting it with a switch statement—you’ll find it easier to rework when it comes time to consider some other alternative value.

      If you’d like to learn more about the Go programming language, check out the entire How To Code in Go series.



      Source link