The functions have an internal property names [[Call]]. This property is unique to functions and indicate that the object can be executed. Just because of this property the typeof operator returns type as “function”. In the past different browsers were identifying multiple reference types, for example regular expression, as function that has been corrected now.
Functions can be declared in two different forms;
The first form is function declaration where the function has a name;
function add(num1, num2){
return num1 + num2;
}
The second form is function expression where the function has no name;
var add = function(num1, num2){
return num1 + num2;
};
This code actually assigns a function value to the variable add. The function expression is almost identical to function declaration except for the missing name and the semicolon at the end.
These two forms are similar but there is a difference. Function declarations are hoisted to the top of the context when the code executes. This code might look like it will cause an error, but it works;
var result = add(5,5); //return 10
function add(num1, num2){
return num1 + num2;
}
The reason, JavaScript engine hoists the function declaration to the top and actually executes the code as if it were written like this;
function add(num1, num2){
return num1 + num2;
}
var result = add(5,5); //return 10
Function hoisting happens only for function declaration because function name is known ahead of time. This is not true for function expressions.
var result = add(5,5); //return error
var add = function(num1, num2){
return num1 + num2;
};
If we always define functions before using it, both approaches will work.
Passing Parameters
JavaScript functions allows you to pass any number of parameters to a function without causing any error. The reason, function parameters are stored an array-like structure called arguments. Arguments are similar to JavaScript array. The arguments values are referenced via numeric indices and there is a length property to determine how many values are present.
The argument object is automatically available inside any function. This means names parameters in a function exists mostly for convenience and don’t exactly limit the number of arguments that a function can accept. Function won’t throw an error if we pass too many or too few parameters.
Here is an example;
function reflect(value) {
return value;
}
console.log("hi"); //returns “hi”
console.log("hi", "there"); //returns “hi there”
reflect.length //returns 0
The same function can be written as;
reflect = function(){
return argument[0];
};
console.og("hi", "there"); //returns “hi”
console.log("hi", "there"); //returns “hi there”
console.log(reflect.length) //returns 0
The first implementation is much easier to understand because of named argument. The second implementation is using arguments and we much read the body to understand how arguments are used.
The best practice is to use named argument. However, using arguments is actually more effective in case we want to create a function that accepts any number of parameters and return their sum.
function sum()
{
var result = 0;
i = 0;
len = arguments.length;
while (i < len) {
result += arguments[i];
i++;
}
return result;
}
console.log(sum(1,2)); //returns 3
console.log(sum(1,2,3,4,5)); //returns 15
console.log(sum(1,2,3,4,5, 6, 7 , 8)); //returns 36
console.log(sum()); //returns 0
console.log(sum(50)); //returns 50
Function overloading
There is no concept of function overloading in JavaScript. JavaScript function can accept any number of parameters.
function sayMessage(message) {
console.log(message);
}
Overloading this function;
function sayMessage() {
console.log("Default message");
}
sayMessage(“Hello”) //returns “Default message”
Why do we see “Default message” where it should be “Hello”. When we define multiple functions with the same name, the one that appear last in code wins.
We can mimic overloading functionality using this approach;
function sayMessage(message) {
if (arguments.length == 0) {
console.log("Default message");
}
console.log(message);
}
sayMessage("hi") //returns “hi”
sayMessage() //returns “Default message”
Object Methods
Properties can be added or removed from objects at any time. When a property value is function, it’s considered a method.
var person = {
name:"Shahzad",
sayName: function(){
console.log(person.name);
}
};
person.sayName() //returns “Shahzad”
Syntax for data property and method is exactly the same. An identifier followed by : and the value. For function the value would be function().
The “this” Object
In our previous example, sayName() method reference person.name directly, which creates tight coupling between the method and the object. If we change the variable name, we also need to remember to change the reference to that name in method. Second, it would be difficult to use the same function for different objects.
Every scope in JavaScript has a “this” object that represents the calling object for the function. In the global scope, this represents the global object (window in web browsers). When a function is called while attached to an object, the value of “this” is equal to that object by default.
Let’s re-write the code;
var person = {
name:"Shahzad",
sayName: function(){
console.log(this.name);
}
};
person.sayName() //returns “Shahzad”
This code works the same as the earlier version, but this time, sayName() references “this” instead of person.
Let’s go with another example. Create a function “sayName”. Create two object literals and assign sayName to the sayNameFor function. Functions are reference values so they can be assign as property values on any number of objects.
Define a global variable called name. When sayNameForAll() is called directly, it will output global variable value.
function sayNameForAll() {
console.log(this.name);
}
var person1 = {
name: "Shahzad",
sayName: sayNameForAll
};
var person2 = {
name: "Ali",
sayName: sayNameForAll
};
person1.sayName() //returns “Shahzad“
person2.sayName() //returns “Ali”
sayNameForAll(); //returns empty value
Why sayNameForAll() returns null because there is no global scope variable. Let’s define one;
var name = “Hamza”;
sayNameForAll(); //returns “Hamza”
Changing this
The ability to use and manipulate the “this” value of functions is key to good object-oriented programming in JavaScript. There are three function method that allow us to change the value of this. Functions are objects and objects have methods, so function can, too.
The call() Method
This execute the function with a particular this value and with specific parameters. Let’s take our earlier example;
function sayNameForAll(label) {
console.log(label + ":" + this.name);
}
var person1 = {
name: "Shahzad"
};
var person2 = {
name: "Ali"
};
var name = “hamza”;
sayNameForAll.call(this, "global"); //returns global:hamza
sayNameForAll.call(person1, "person1"); //returns person1:Shahzad
sayNameForAll.call(person2, "person2"); //returns person2:Ali
sayNameForAll() accepts one parameter that is used as a label to the output value. There are no parentheses after the function name because it is accessed as an object rather than as code to execute. We did not added the function directly on each object. We explicitly specify the value of this instead of letting the JavaScript engine do it automatically.
The apply() Method
The second method we can use to manipulate “this” is apply(). This method works exactly the same as call() except that it accepts only two parameters: the value for this and an array or array-like object of parameters (it means we can use an arguments object as the second parameter). We can call our methods like this;
sayNameForAll.apply(this,["global"]); //return global:hamza
sayNameForAll.apply(person1,["person1"]); //return person1:Shahzad
sayNameForAll.apply(person2,["person2"]); //return person2:Ali
The use case between call and apply; if we have an array of data, we will use apply(). If we just have individual variable, we will use call().
The bind() Method
This method was added in ECMAScript 5 and it behaves quite differently than the other two. The first argument to bind() is the “this” value for the new function. All other arguments represent named parameters that should be permanently set in the new function.
We can call our methods like this;
var sayNameForPerson1 = sayNameForAll.bind(person1);
sayNameForPerson1("person1"); //returns “person1:Shahzad”
var sayNameForPerson2 = sayNameForAll.bind(person2);
sayNameForPerson2("person2"); //return “person2:Ali”
Resources