ghsamm

Introduction to javascript - part 2

Hello again, this is the second part of my ongoing series about javascript. I hope it's to some use to you. Let's get straight to the point, here's what we're covering :

Arrays

An array is what you will commonly use if you want to store a collection of data that you want to keep numerically indexed.

You can declare an array simply by :

var arr = ['a', 'b', 'c', 'd'] // declaring an array is as easy as wrapping a collection of elements
// in brackets and separating them by commas
console.log(arr[0], arr[1])
// -> a b
arr = ['a', 2, true, null, undefined, {object: true}] // being a dynamic language, javascript allows
// arrays to hold different data types, including complex ones such as objects and other arrays

Arrays are fun to work with because of the functional nature of the language. We'll see how easy how to manipulate them in a moment.

Functional programming

According to Eric Elliot, an influencing voice in the community of javascript, functional programming is one of the two pillars of the language (the other one being prototypal inheritance, a more advanced topic we might visit in the future).

Personally, I consider it the most useful feature of the language as it makes manipulating complex data types so much easier. First, let's take a look at the concept : basically, it all comes down to the fact that you can pass functions as arguments to other functions.

Let's say you have a function that calculates the sum of two numbers :

function log(){
    console.log('sorry i\'m late')
}

You can have another function that accepts a function as a parameter for internal use, let's pick one from the built-in functions, setTimeout which takes two parameters :

  • a function to call at a later time
  • time in milliseconds before executing it
setTimeout(log, 5000)
// 5 seconds later...
// -> sorry i'm late

You can see how setTimeout is using the log function just like any other parameter.

Things can be even more interesting because we can have functions passed to our own functions and execute them whenever and however we want, e.g we can pass custom arguments to them.

We'll be making our own version of the built-in function Array.prototype.forEach which takes a function as an argument and applies it to each element in an array.

// we'll rewrite our log function so that it handles one parameter
function log(element){
    console.log(element)
}

// our custom forEach function
function each(arr, func){
    var i = 0
    for(i = 0; i < arr.length; i++){
        func(arr[i])
    }
}

// let's test this out
var anArray = ['some', 'random', 'data', 0, 1, 2]

each(anArray, log)
// -> some random data 0 1 2

Now let's explore another feature of functional programming which is chaining functions. For this example we'll use string built-in functions.

var s = 'javascript is a functional language'
console.log(
    s.toUpperCase() // convert to uppercase -> JAVASCRIPT IS A FUNCTIONAL LANGUAGE
    .substr(16, 10) // take only 10 character after index 16 -> FUNCTIONAL
    .replace(/i/ig, '1') // replace i characters with 1 -> FUNCT1ONAL
    .replace(/o/ig, '0') // replace o characters with 0 -> FUNCT10NAL
)
// -> FUNCT10NAL

If you're wondering what's with /o/ig, it simply says : match the character 'o' or 'O'(i: ignore case) multiple times(g: global match)

Back to our example, the chaining mechanism is possible due to the fact that every function in the chain returns the result back to be processed by the next element.

Back to Arrays

Now that you have an idea about what functional programming is all about, let's revisit arrays from a new perspective.

If you type Array.prototype. in your developer console and run through the list of buil-in functions offered to manipulate arrays, you'll find few very interesting ones that handle array manipulation from a special point of view which is that of a functional programming language.

The list includes concat, every, fill, filter, find, forEach, map, reduce, some...

For starters, Array.prototype.concat returns a new array that is result of the concatenation of the current array and the first parameter which is an array:

var arr1 = [0, 1, 2],
    arr2 = ['a', 'b', 'c'],
    arr3 = arr1.concat(arr2)
console.log(arr3)
// -> [0, 1, 2, "a", "b", "c"]

Next up, we've got Array.prototype.every and Array.prototype.some, they both take one required parameter which is a callback function to run on every element of the target array and they return a boolean. However, every returns true when and only when the callback function returns a truthy value every time and some returns true if the callback functions returns at least one truthy value :

function isPair(el){
    return el % 2 === 0
}

function isNull(el){
    return el == null // undefined and null are treated equally when not using ===
}

var arr = [2, 0, 1, 5, 8]

console.log(arr.every(el=> !isNull(el))) // no element is null
// -> true
console.log(arr.some(isPair)) // at least one element is pair
// -> true

console.log(arr.some(el=> !isPair(el))) // at least one element is impair
// -> true

Another helpful array method is Array.prototype.map which simply maps an array of N elements to a new array of N elements using a callback function:


var ids = {
    'R': 'reading',
    'W': 'writing',
    'P': 'playing video games',
    'G': 'playing guitar',
    'S': 'swimming'
}
var student = {
    name: 'ghsamm',
    hobbies: 'RWP'
}
console.log(student.name + ' likes ' +
    student.hobbies.split('') // ['R', 'W', 'P']
        .map(el=> ids[el]) // ['reading', 'writing', 'playing video games']
        .join(', ')) // 'reading, writing, playing video games'
// -> ghsamm likes reading, writing, playing video games

My personal favorite array method is Array.prototype.reduce because it allows you to reduce a whole array to any kind of value you want. It's a little harder to grasp than its siblings.

// here is its signature
arr.reduce(callback, initialValue)
// and this is the callback's signature
function callback(previousValue, currentValue){}

For the callback, the currentValue parameter is always going to be the current value in the array. previousValue however is the meat of the trick because it's initial value is the one passed to reduce but for the following callback invocations, it's value is whatever the callback function returned last time.

The final result is the last value of previousValue, aka. the last returned value from callback.

Let's see some code:

// we'll be calculating the sum of the array
var arr = [57, 1, 153, 0, -2, 99]

function sum(prev, cur){
    return prev + cur // each time the sum function returns whatever
    // the previous sum is + the current element of the array
}

console.log(arr.reduce(sum, 0)) // of course, the initial value of the sum is 0

This is a simple example but reduce can be extremely powerful when dealing with arrays.

Moving on...

Objects

Object creation and manipulation in javascript is easier than any other language that I know of and it had become the inspiration for the most used data transfer protocol on the web : JSON(JavaScript Object Notation) for its simplicity and universality.

var student = {
    name: {
        first: 'samh',
        last: 'ghanmi'
    },
    age: 21,
    interests: [
        'javascript',
        'node.js',
        'git'
    ],
    sayHi: function(){
        console.log('Hi, I am ' + this.name.first + ', I like ' + this.interests.join(', '))
    }
}
student.sayHi()
// -> Hi, I am samh, I like javascript, node.js, git

The data structure is fairly obvious; objects are key:value pairs, with the value being one of the following data types: string, number, boolean, array, function or object.

Just like primitive types, objects are not committed to any sort of schema like in most other languages, so it is very normal in javascript to monkey-patch (aka. decorate) your objects as needed.

Here's a beginner implementation of the idea of adding properties to an existing object:

var student = {
    name: 'ghsamm'
}

function logName(obj){
    console.log(obj.name)
}

// utility function
function override(object, key, cb){
    object[key] = function(){
        cb(object)
    }
}

// now we can add the logName function as a 'method' to the original object
override(student, 'logName', logName)
student.sayName()
// -> ghsamm

Of course as I said this is not a practical example but it should be more than enough to make you grasp the concept of monkey-patching, a unique feature in the language.

An important thing to notice here is that although it is possible to monkey-patch buil-in objects (the Object.prototype for example which is the inherited prototype of all objects), it is not recommended to try it because it can result in conflicts with future language specs.

That being said, there are ways to do it wisely like for example when a new language feature is 'polyfilled' to run on older browsers.

That's it for today, my next article will cover typescript, the language that adds types to javascript for development-time static-analysis error checking. Stay tuned.


Introduction to javascript

Welcome to my very first blog post ever. As my blog focuses mainly on modern web technologies and because we can't say modern web without mentioning javascript, this post is going to be a brief introduction to the basic aspects of the language.

Javascript is a very versatile language and only one post is not nearly enough to cover most of its basics so this will be a series of posts. If however you would prefer more in-depth topics about the language and its wide eco-system, rest assured as there will be plenty of those in the upcoming blog posts.

What topics are we covering ?

Running javascript in the browser

Javascript can be run on many environments( browser, server... ) but at this level we're only going to be interested in good old javascript that runs in the browser.

Typically, you would want to write javascript to a .js file, load into a .html file that you can open using a browser. A much faster way, especially if you are still trying things out is by opening the developer console in your browser and writing javascript code directly.

Comments

Of course, the first thing you learn about a new language is how to write a comment to annotate your code with helpful hints and remarks. Comments in javascript are similar to many other languages.

// this is a one-line comments
/*
    and this is a multi-line comment
*/

Input/Output

Input/Output in javascript can mean a multitude of things depending on the environment you work on. The default output operation is console.log, alternatively, you can use alert for simple output.

console.log(5)
// -> 5
console.log('one')
// -> one

As for input, when in browser, you should always use some HTML to ask a user for input, but if you're just trying things out, you can use window.prompt( aka. prompt ).

var a = prompt('give me something' /* this is the message the user will see */)
console.log(a)
// the result will be whatever your write to the prompt

Basic operations

Operators in javascript are very similar to many other languages like C and JAVA so this is not what sets the language apart. Nothing special here, folks.

Boolean operations

var a = true,
    b = false
console.log(!a) // negation
// -> false
console.log(a && b) // logical AND
// -> false
console.log(a || b) // logical OR
// -> true

Mathematic operations

console.log(5 + 3) // addition
// -> 8
console.log(3 - 5) // subtraction
// -> -2
console.log(3 * 4) // multiplication
// -> 12
console.log(12 / 7) // division
// -> 1.7142857142857142
console.log(13 % 5) // modulus (division remainder)
// -> 3
var a = 0
console.log(a++, a) // increment after, you can use a-- for decrement after
// -> 0 1
console.log(++a, a) // increment before, you can use --a for decrement before
// -> 2 2

String operations

console.log('aa' + 'bb') // string concatenation
// -> aabb
console.log(20 + '10') // Caution! this is implicit coercion, a language feature that strongly-typed languages consider a flaw
// -> 2010

Coercion

Type coercion (casting) can be performed in few ways, here is the simplest. typeof is a keyword we use to determine the type of the current value in a variable.

var a = 5
console.log(typeof a)
// -> number
a = '' + 5
console.log(typeof a)
// -> string
var b  = '20'
console.log(typeof b)
// -> string
b = +b
console.log(typeof b)
// -> number

var, let and const

To declare a new variable in javascript you have two options : var and let.

var a = 5
var A = -8
let b = 8
console.log(a, A, b, a + b)
// -> 5 -8 8 13

Javascript is a case-sensetive language so the variable a is a totally different variable from A.

Although var and let might appear similar at first glance, they behave differently on more advanced scenarios. More on that in future posts.

A constant on the other hand is an immutable "variable", its value can not change ( if the constant is an object however, its content can be changed but not its address, this has to do with the nature of objects in javascript ).

const a = 5
a = 55
console.log(a)
// -> 5

Primitive types

Javascript is a loosely-typed language which means any variable could have any type of content at any given time

var a = 5 // typeof a == 'number'
// later
a = 'sam' // typeof a == 'string'
// even later
a = new Date() // typeof a == 'object'

Here is a list of all primitive types in javascript :

  • boolean : the simplest type, a boolean can either be true or false. That said, in javascript, any variable can be "truthy" or "falsy" :
// you can coerce any variable to boolean to see whether or not it's truthy
// using `!!` (double negation 'operator')
var a = 0, b = 1, c = Infinity,
    d = '', e = 'e', f = [], g = [0]
console.log(!!a, !!b, !!c, !!d, !!e, !!f, !!g)
// -> false true true false true true true

Confused? no need to worry, at the exception of these values, everything is truthy : 0, NaN, '', null, undefined, false

  • nubmer : a number can be an integer, a float, Infinity or NaN (Not a Number) :
console.log(5 + 1)
// -> 6
console.log(5/0, -5/0)
// -> Infinity -Infinity
console.log(0.1 + 0.2)
// -> 0.30000000000000004
// what !? This is actually a language flaw, one of many others you'll encounter.
// It has to do with how numbers are saved in memory
console.log('f' / 2, 0/0, 'a' - 'm')
// -> Nan NaN NaN
// As you can see, NaN represents the result of a bad mathematic operation
  • string : a string of characters
var a = '' // empty string
a = 'a' // one character
var b = 5
console.log(a.toUpperCase())
// A
a = ` Over multiple lines
using backticks as string delimiter instead of quotes
`
a = `you can use string interpolation as such : b = ${b}`
console.log(a)
// -> you can use string interpolation as such : b = 5
  • undefined : this primitive type represents an empty variable, a newly created variable has this default value
var a
console.log(a)
// -> undefined

This concludes my first post, hopefully it was useful and it will be the first of many so stay tuned for more awesomeness ;)