What is a function
A function is a "container" for a block of code. Functions can help us with:
- Avoiding code repetition. A single function can be invoked any number of times.
- Creating local scopes to encapsulate code, which will limit and protect access to data
- Split our code into components and thereby make our codebase more manageable, modular and scalable
First Class Functions
Build in functions
Build in functions does not have to be declared (they are allready declarered in the API)
alert() is a function build in to the window object We could also have called it by typing window.alert('Hello'); When functions are encapsulated in objects they are often called methods.
Usually we would like to be able to do more than invoking build in functions. Fortunately we can declare our own functions. The most common way to do so is with a function statement which contains:
- A function keyword
- A name for the function
- A set of brackets for optional parameters
- A function body - a set of curly brackets which contains all the local variables, commands, expressions statments of the function
Arguments are data that are passed to the function when it is being called. These data are only accessible within the function body (Read: Scope)
Before we can pass any arguments to the function we need to place parameters in the function declaration. Think of the parameters as empty placeholders for data
If we are using multiple arguments/parameters, we seperate them with commas.
Note that parameters and arguments are the same thing. But we use the different terms depending on the context. The term parameter is used in the function declarationen, and the term argument is used in the function call.
So far all the function examples have been executing code but it is oftem more useful to let the function return a value instead
Let's make a program that can add two numbers:
Return values makes it easy to pass data as arguments from one function to another:
Any function that recieves, or returns, other functions (instead of just values) are Higher-order functions
Hoisting is not common. In most programming languages you need to declare a function before you call it.
Anonymous functions and function expressions
A function does not necessarily have to be declarered with a name. The term for a function with no name is an anonymous function. It is very common to declare a variable and set its value to an anonymous function
This practice is called a function expression and works almost simular to a function statement, but with the important difference that function expressions are not hoisted. Function expressions must be declarered before they are called
IIFE, or Immediately Invoked Function Expression, is another typical use for anonymous functions. An IIFE is executed immediately it is declared.
The usecase for IIFE is typically for initialization of a program. Eg. when we want to encapsulate a piece of code in a scope and run it only once.
Nested functions and closures
One of the more complex concepts in JS is closures.
Closures is when an inner (nested) function is returned from an outer (parent) function and called after the outer function is executed, dead and buried. Because of the closure concept, the returned inner function still have access to the variables in the outer (dead and buried) functions scope.
The interesting thing is the difference between a and b.
b gets redeclarered every time we call c() so it's value gets reset every time, but a (which exist as a closure) will not be redeclared, so its value increases every time c() is executed
Arrow function syntax (only ECMAScript 6+)
Anonymous functions can now be declared with a shorter syntax.
We remove the function keyword and replace it with these symbols
=> after the brackets
We can even shorten the code further by ommiting the function body and use the arrow functions implicit return value
As mentioned we can pass a function as a parameter to another (higher-order) function. One of the most common usecases for this is callback functions.
A Callback is when function B is passed as parameter to function A and is invoked immediately after function A is executed
The addEventListener function, takes (in this example) two parameters. The first parameter is the type of event (click). The second parameter is an anonymous function, executed as a callback when the event occurs
In the previous example, we used an anonymous callback function. Sometimes it would be a better solution to pass an external function as the callback, especially if we want to attach the functionality to multiple eventlisteners. Such functions are often refered to as handler functions because they handle all the actions that the event trigggers.
This and event.target
Event handlers in loops
If you've paid attention you might have noticed the use of the word this in the previous examples.
When the this keyword is used in an event handler, it points to the object the event is attached to in the given context.
So The handler function will interpret this as whatever element, we clicked on, that triggered the function.
The This keyword is very useful if we need to attach events to an unknown numbers of elements in a loop. For example all elements with a certain class, like in following code:
If you click the HTML tab on the embedded fiddle, you can see that all the targeted element has a data attribute. We can access the individual data attribe of each element in the loop with by using this
Note that the handler function takes the event object as an argument
That means that we can delegate one single eventlistener to all the child elements. But to target the individual elements we will have to use event.target instead of this
Object Orientet JS
Object Orientet Programming (OOP) means that you create special types of blueprint functions (in most programming languages known as classes). The code inside the class itself is not executed directly. Instead we instansiate (create) objects. Each object/ instance, acts as clones of the class and inherits all the properties (variables) and methods (functions) of the class.
OOP allow us to minimize repetitions and to encapsulate and protect data. Another iportant concept in OOP is inheritance. Not only our instanses of the class can inherit propperties/methods. We can even create sub classes that inherits everything from a super class.
We have now successfully created two instances of an "Animal".
Note that the name of the constructer function is declared with PascalCase (capitalized first letter in every word). This is a common practice for class definitions
New ES6 class syntax
This is good news for programmers that are used to traditional programming languages (eg. JAVA and C++), because we can use the same syntax. Like in these languages, we can declare static methods (methods that belong to the class itself, not the instances), we can however not declare private methods/ properties.
Note that in order to calculate the age of the person we need to reference Person.currentYear(). We can not use this.currentYear() because it is static.
Note that unlike the previous constructer function, classes are not hoisted. A class must be declared before it can be instanciated
Inheritance in OOP
We can create sup classes that inherits the properties of a super class
Let's try to extend our Person class to two sub classes: Employee and Customer
Both types are persons so they should inherit the name age and gender properties from the Person class. We can do that with the super keyword
Both types should also have their own unique properties:
Object Literals and Prototypes
It is important to note that there are other models for creating objects with inheritance, in JS
One of these models are to simply create object literals and use Object.setPrototypeOf to create objects that inherit properties/methods
Here's an example showing how to do it with this approach