Categories
JavaScript

Good Parts of JavaScript — Strings and Flow Control

JavaScript is one of the most popular programming languages in the world. It can do a lot and have some features that are ahead of many other languages.

In this article, we’ll look at some good parts of JavaScript, including strings and flow control.

Strings

Strings can be wrapped in single or double quotes or backticks.

It can contain 0 or more characters. The “ (backslash) is an escape character.

JavaScript doesn’t have a character type. We just put one character in a string to represent one character.

Single or double quotes are good for delimiting short strings that don’t have any dynamic parts inside.

Backticks are used for delimiting template strings, which can contain expressions and can be multiple lines long.

Therefore, whenever we can, we should use template strings.

It’s much more convenient than using regular strings.

We can also use the single or double quotes within template strings as normal characters rather than use it to delimit strings.

For instance, we can define strings in the following ways. We can define a string with single quotes:

const foo = 'foo';

To define strings with double quotes, we can write:

const foo = "foo";

or we can define template strings by writing:

const world = 'world';
const greeting = `hello ${world}`;

Template strings can contain expressions, which can optionally contain expressions.

Expressions are surrounded by the ${} characters.

This is great since dynamic string replaces concatenation, which is a pain to use if we have to create dynamic strings.

We can create multiline strings without hassle as follows:

const hello = `
hello
world
`

Now 'hello' and 'world' will be in separate lines.

We can also use template tags to return a value by passing in a template string.

Template tags are just functions with special signatures.

The first parameter of a template tag is an array of strings, and the remaining parameters are the expressions.

If we write:

const tag = (strings, ...exps)=>{
 console.log(strings, exps);
}

const name = 'world';
tag`hello ${name}`;

We get that strings is [“hello “, “”, raw: Array(2)] and exps is an array of expressions, which is [“world”] .

All strings have a length property. It returns the length of the string.

JavaScript strings are immutable. Once it’s made, it can never be changed.

But we can create new strings by concatenation or putting them in template strings.

2 strings that have the same length and exactly the same characters in the same order are considered the same.

So:

'foo' + 'bar' === 'foobar';

returns true .

JavaScript strings also have many methods that we can use to manipulate them.

Photo by Samuel Ferrara on Unsplash

Statements

JavaScript programs are composed of one or more statements.

If we use script tags only, then everything is thrown into the global namespace.

However, with the introduction of JavaScript modules, modules can be bundled together to compile them into a big bundle.

let or var can be used to declare variables. And they’re private if they’re declared in a function.

let is also private within the block.

const defines a constant, which is also block scoped.

Constants are mutable, but we can’t assign them to a new value.

The switch , while , for and do statements are allowed to have an optional label statement that can be used with the break statement.

Statements are usually run from top to bottom.

The sequence can be changed with conditional statements, if and switch .

Loop statements, while , for , and do can also change the order of execution of statements.

Disruptive statements like break , return , and throw can also change the execution flow.

Function invocation can also change the flow of the program.

A block is wrapped in curly braces. Blocks create a new scope for any data declared with let or const .

Therefore, it’s preferred that we use let or const to declare our variables and constants.

An if statement changes the flow of a program based on the value of the expression within the parentheses.

If it returns true , then the code in the if block is run.

Otherwise, else if ‘s conditions will be check and the code in those blocks will run if possible.

If an else block is present, that will run if other blocks before it isn’t run.

Conclusion

Template strings are great. We can have expressions and they can be more than one line long.

Statements are building blocks of programs. We can run the flow can change based on various flow control statements.

Categories
JavaScript

The Good Parts of JavaScript

JavaScript is one of the most popular programming languages in the world. It can do a lot and have some features that are ahead of many other languages.

In this article, we’ll look at some good parts of JavaScript.

Misconceptions About JavaScript

We can’t assume that JavaScript is like any other language. To take advantage of the good parts, we’ve to learn it as a new language.

It’s possible to create things with JavaScript without knowing too much about it.

But without knowing the good parts, we won’t be writing code as cleaning as we could.

Dynamic Types

We can use dynamic types to our advantage. With or without strong typing, we got to test our code thoroughly.

Otherwise, we’re going to run into issues regardless of whether the language has strong typing or not.

Type errors are only one class of errors and we can eliminate that with tests that we have to type anyways.

The dynamically typed natures of JavaScript with the ability to create one-off objects with object literals are a great feature that we can’t ignore.

We can create objects without creating classes.

Also, it inspired the JavaScript Object Notation (JSON) for transmitting data,

It’s very similar to JavaScript object literals and we can convert them easily.

Simple Testing Ground

Both Node.js and browsers have a REPL where we can test out our code.

There’re also many online JavaScript editors for running Node.js and browser code.

Many of those editors even have templates for creating projects with various frameworks out of the box.

We can also include libraries on the fly.

With REPLs and online editors, we can create tests and prototype code without much effort.

In all the editors and REPLs, we can see the results right away.

Whitespace

In JavaScript, whitespace are usually insignificant. This lets us have some flexibility in formatting our code.

However, there are some whitespace that are required to separate some tokens like keywords and variables.

For instance, if we have:

const foo = this;

Then the space after the const is required, but the rest are not.

Comments

Comments are good to add to let us clarify our code.

We can write comments with blocks surrounded with /* */ or start with // ..

2 forward slashes are also used by regex literals, so we probably don’t want to use them.

Instead, we can create comment blocks with /* */ .

Names

Names in JavaScript are letters that are optionally followed by one or more characters, digits, or underscores.

They also can’t be reserved words that are used by the JavaScript language itself.

We can’t use reserved words as function names, class names, or variable names.

Numbers

There’s a single number type in JavaScript.

Floating point numbers and interest are all one type.

This is more convenient than having separate types for different kinds of numbers.

Having one type of number eliminates the type of errors that are caused by different types of numbers.

If a number has an exponential part, then the value of the literal is computed by multiplying the part before the e by 10 raised to the power after the e .

For instance, the number 1000 and 1e3 are the same number.

Negative numbers are formed by the - prefix operator.

NaN is a number value that’s the result of an operation that can’t produce a number.

NaN isn’t equal to any value, including itself.

For instance, if we divide a number by 0, then we get NaN returned.

We can check if something produces NaN by using the Number.isNaN method, which checks the value as-is, or the isNaN function, which does the conversion to number before checking the returned value.

Numbers have various methods that we can use to manipulate them. Also, we can do Math with the Math object.

Conclusion

JavaScript has a few useful features.

We can use dynamic typing to our advantage. The ability to create and use object literals is a convenience feature that many programming languages don’t provide.

It also has comments we can use to clarify code.

There’s only one number type in JavaScript, which eliminates lots of issues with multiple types of numbers.

Categories
JavaScript

Good Parts of JavaScript — Recursion and Scope

JavaScript is one of the most popular programming languages in the world. It can do a lot and have some features that are ahead of many other languages.

In this article, we’ll look at ways to make a function call itself and scopes of functions.

Recursion

A recursive function is a function that calls itself.

We can use it do divide a problem into a set of subproblems, each with a trivial solution.

For instance, we can create a recursive function as follows:

const count = (i) => {
  if (i === 10) {
    return;
  }
  console.log(i);
  count(i + 1);
}

count(0);

In the code above, we have a simple recursive function that stops with i reaches 10.

For each value of i , we log the value of i to the console.

We should make sure that we have a base case to stop the function.

If a function returns the result of running itself recursively, JavaScript doesn’t optimize that by replacing it with a loop.

For instance, if we have:

const factorial = (i, a = 1) => {
  if (i < 2) {
    return a;
  }
  return factorial(i - 1, a * i)
}

const result = factorial(10);

Then JavaScript will turn that into a loop, so the call stack would be full if we call it too many times.

Scope

Scope in a programming language controls the visibility of variables and parameters.

In JavaScript, we have a function and block-scoped variables.

let and const are block-scoped and var is function-scoped.

Therefore, to reduce confusion, we should use let and const to declare data.

For instance, if we have:

if (condition) {
  let x = 1;
  const y = 2;
  //...
}

x and y are block-scoped, so they’re only available within the if blocks.

We should just forget about var and use let or const exclusively.

Variables should be declared as late as possible so that their lifetimes are short.

This reduces the need to follow the use of variables through many lines of code when we’re reading code.

Closure

Inner functions get access to parameters and variables of functions that are defined in.

We can use this to make values private and use them in inner functions.

For instance, we can write:

const obj = (() => {
  let value = 0;
  return {
    increment(val) {
      value += val;
    },
    getValue() {
      return value;
    }
  };
})();

value is private, so that we can update value by incrementing it with val .

So we update value safely without exposing them to the outside.

We used an IIFE above, we can return an object that uses private variables.

Also, we can turn that into a factory function by removing the parentheses.

For instance, we can write:

const createName = (name) => {
  return {
    getName() {
      return name;
    }
  };
};

const name = createName('foo').getName();

We return an object that returns the value of the name parameter.

It’s not a constructor so that we can’t use it with the new operator.

Inner functions have access to the variable itself rather than the value when it’s made.

For instance, if we have:

const addHandlers = (nodes) => {
  for (var i = 0; i < nodes.length; i += 1) {
    nodes[i].onclick = () => {
      alert(i);
    }
  }
}

addHandlers(document.querySelectorAll('button'))

If we run the code above, the alert box always shows 3 no matter which button we click.

This is because the loop body is found to the variable i rather than the variable i at the time the function is made.

To fix this, we can use let instead of var :

const addHandlers = (nodes) => {
  for (let i = 0; i < nodes.length; i += 1) {
    nodes[i].onclick = () => {
      alert(i);
    }
  }
}

addHandlers(document.querySelectorAll('button'))

let is block-scoped so that the onclick handler will get the current value of i rather than the value of i when the loop is done.

Conclusion

Recursive functions are functions that call themselves directly or indirectly.

It’s useful for dividing problems into trivial subproblems.

Scopes of variables depends on how we declare them. If we declare them with let or const , then they’re block-scoped.

If we declare them with var , then they’re function-scoped.

Closures allows us to access private variables.

Categories
Material UI

Material UI — Slider

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to add sliders with Material UI.

Discrete Sliders

We can add sliders to snaps to discrete values.

To do that, we set the marks prop to true .

For instance, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

export default function App() {
  return (
    <form>
      <Slider marks />
    </form>
  );
}

to make an uncontrolled slider that snaps to the nearest 10.

Small Steps

We can change the steps with the steps prop.

For example, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

export default function App() {
  return (
    <form>
      <Slider step={0.00001} marks />
    </form>
  );
}

to change the increment between each discrete value.

Custom Marks

We can add our own custom marks with the marks prop.

For example, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

const marks = [
  {
    value: 0,
    label: "0m"
  },
  {
    value: 25,
    label: "25m"
  },
  {
    value: 50,
    label: "50m"
  },
  {
    value: 75,
    label: "75m"
  },
  {
    value: 100,
    label: "100m"
  }
];

export default function App() {
  return (
    <form>
      <Slider step={10} marks={marks} valueLabelDisplay="auto" />
    </form>
  );
}

We add the marks array with the value and label properties in each entry to show the labels with the text in the label property.

Restricted Values

We can restrict values to the ones that are in the marks array by setting step to null .

For example, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

const marks = [
  {
    value: 0,
    label: "0m"
  },
  {
    value: 25,
    label: "25m"
  },
  {
    value: 50,
    label: "50m"
  },
  {
    value: 75,
    label: "75m"
  },
  {
    value: 100,
    label: "100m"
  }
];

export default function App() {
  return (
    <form>
      <Slider step={null} marks={marks} valueLabelDisplay="auto" />
    </form>
  );
}

Now we can only select the values that are marked in the marks array because of the null value we passed into the step prop.

Make Label Always Visible

We can make the labels always visible by setting the valueLabelDisplay prop to on .

For example, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

const marks = [
  {
    value: 0,
    label: "0m"
  },
  {
    value: 25,
    label: "25m"
  },
  {
    value: 50,
    label: "50m"
  },
  {
    value: 75,
    label: "75m"
  },
  {
    value: 100,
    label: "100m"
  }
];

export default function App() {
  return (
    <form>
      <Slider step={10} valueLabelDisplay="on" marks={marks} />
    </form>
  );
}

Now we see the value above the slider dot.

Range Slider

We can allow users to select a value range with the Slider .

To do that, we can set an array as the value as the initial value.

For example, we can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

export default function App() {
  const [value, setValue] = React.useState([20, 30]);

  const handleChange = (event, newValue) => {
    setValue(newValue);
  };
  return (
    <form>
      <Slider valueLabelDisplay="auto" value={value} onChange={handleChange} />
    </form>
  );
}

to make a range slider.

We set an array as the initial value of the value state to make the slider a range slider.

Vertical Sliders

We can make a slider vertical with the orientation prop set to vertical .

For instance, we can write:

import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Slider from "@material-ui/core/Slider";

const useStyles = makeStyles({
  root: {
    height: 300
  }
});

export default function App() {
  const classes = useStyles();

  return (
    <div className={classes.root}>
      <Slider
        orientation="vertical"
        valueLabelDisplay="auto"
        defaultValue={30}
      />
    </div>
  );
}

to create a vertical slider.

We’ve to set the height of the wrapper so that the slider is displayed.

Track

We can set track to false to remove the track that’s displayed when we select a value.

To do that, we write:

import React from "react";
import Slider from "@material-ui/core/Slider";

export default function App() {
  return (
    <div>
      <Slider track={false} defaultValue={30} />
    </div>
  );
}

to remove th track.

We can also set it to inverted to change the track to be opposite of the default.

Non-Linear Scale

The scale is linear by default, but we can change it to a nonlinear scale with the scale prop set to a function.

We can write:

import React from "react";
import Slider from "@material-ui/core/Slider";

export default function App() {
  return (
    <div>
      <Slider scale={x => x ** 5} defaultValue={30} />
    </div>
  );
}

to change the scale.

Conclusion

We can add sliders to let users select a number or a range of numbers from a slider.

Categories
Material UI

Material UI — Transfer List

Material UI is a Material Design library made for React.

It’s a set of React components that have Material Design styles.

In this article, we’ll look at how to add a transfer list with Material UI.

Transfer List

A transfer list lets us move one or more items between lists.

To use it, we can write:

import React from "react";
import Grid from "@material-ui/core/Grid";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import ListItemText from "@material-ui/core/ListItemText";
import Checkbox from "@material-ui/core/Checkbox";
import Button from "@material-ui/core/Button";
import Paper from "@material-ui/core/Paper";

function not(a, b) {
  return a.filter(value => b.indexOf(value) === -1);
}

function intersection(a, b) {
  return a.filter(value => b.indexOf(value) !== -1);
}

export default function App() {
  const [checked, setChecked] = React.useState([]);
  const [left, setLeft] = React.useState([0, 1, 2, 3]);
  const [right, setRight] = React.useState([4, 5, 6, 7]);

  const leftChecked = intersection(checked, left);
  const rightChecked = intersection(checked, right);

  const handleToggle = value => () => {
    const currentIndex = checked.indexOf(value);
    const newChecked = [...checked];

    if (currentIndex === -1) {
      newChecked.push(value);
    } else {
      newChecked.splice(currentIndex, 1);
    }

  setChecked(newChecked);
  };

  const handleAllRight = () => {
    setRight(right.concat(left));
    setLeft([]);
  };

  const handleCheckedRight = () => {
    setRight(right.concat(leftChecked));
    setLeft(not(left, leftChecked));
    setChecked(not(checked, leftChecked));
  };

  const handleCheckedLeft = () => {
    setLeft(left.concat(rightChecked));
    setRight(not(right, rightChecked));
    setChecked(not(checked, rightChecked));
  };

  const handleAllLeft = () => {
    setLeft(left.concat(right));
    setRight([]);
  };

  const customList = items => (
    <Paper>
      <List dense component="div" role="list">
        {items.map(value => {
          const labelId = `transfer-list-item-${value}-label`;

  return (
            <ListItem
              key={value}
              role="listitem"
              button
              onClick={handleToggle(value)}
            >
              <ListItemIcon>
                <Checkbox
                  checked={checked.indexOf(value) !== -1}
                  tabIndex={-1}
                  disableRipple
                  inputProps={{ "aria-labelledby": labelId }}
                />
              </ListItemIcon>
              <ListItemText id={labelId} primary={`item ${value + 1}`} />
            </ListItem>
          );
        })}
        <ListItem />
      </List>
    </Paper>
  );

  return (
    <Grid container spacing={2} justify="center" alignItems="center">
      <Grid item>{customList(left)}</Grid>
      <Grid item>
        <Grid container direction="column" alignItems="center">
          <Button
            variant="outlined"
            size="small"
            onClick={handleAllRight}
            disabled={left.length === 0}
            aria-label="move all right"
          >
            ≫
          </Button>
          <Button
            variant="outlined"
            size="small"
            onClick={handleCheckedRight}
            disabled={leftChecked.length === 0}
            aria-label="move selected right"
          >
            &gt;
          </Button>
          <Button
            variant="outlined"
            size="small"
            onClick={handleCheckedLeft}
            disabled={rightChecked.length === 0}
            aria-label="move selected left"
          >
            &lt;
          </Button>
          <Button
            variant="outlined"
            size="small"
            onClick={handleAllLeft}
            disabled={right.length === 0}
            aria-label="move all left"
          >
            ≪
          </Button>
        </Grid>
      </Grid>
      <Grid item>{customList(right)}</Grid>
    </Grid>
  );
}

We have a grid 2 lists side by side.

We added the list with the List component.

The left list is created with the customList component, which has a List with some items inside it.

Each item has its own checkbox so that’s we can check them off and move them.

The moving is done by a few functions.

The handleAllRight function moves everything to the right.

handleCheckedRight moves everything that’s checked to the right.

handleCheckedLeft moves the items that are check to the left list.

handleAllLeft moves all items to the left list.

The move is done by a few helper functions.

setLeft and setRight sets the items for the left and right respectively.

We concatenate the existing items with the ones that’s checked in each function.

setChecked is used to set the checked value of each item.

It only unchecks that values that are moved.

The example is simplified from the one at https://material-ui.com/components/transfer-list/

Conclusion

We can make a transfer list by following the Material UI example.

We make 2 lists with their own items.

The items are on each list are determined by the state.

Then we can move them by concatenating to the new list and removing them from the old list.