This is the second part of the series in 11 Things about JavaScript Functions that .NET Developers Should Know . You can find part 1 on our blog, and in this part of the series we will discuss:
- Scopes in functions
- Nested functions and Lexical scoping
- Functions’s this keyword
- Function as constructor
- The call() and the apply() methods
Scopes in function
Scoping stands for the current context of code execution. Either a variable o expression can be executed in the context of the function you’re creating, or in the global context of JavaScript. JavaScript does not have block scoping, but only supports scoping at the function level or global level.
A variable defined anywhere in the function can be used everywhere in the function, but not outside the function. Let us consider the following code listing:
https://gist.github.com/debugmodedotnet/2181aad03265d2a1f306
(function Foo() {
myVar = "doo";
console.log(myVar);
var myVar = "bar";
})();
In this snippet you’ll see a few important things:
- Variable myVar can only be accessed inside the function Foo
- Variable myVar is created using the function scope
- Variable myVar can be used anywhere inside the function Foo
- Variable myVar cannot be accessed outside the function Foo
- As an output string doo will be printed on the console
JavaScript works on the function scope. A variable can be defined anywhere inside a function and can be used everywhere in the function. However, it cannot be used outside the function in which it is defined.
JavaScript scoping can be divided into three categories:
- Global scope
- Function scope
- Lexical scope
Global scope
Any variable defined not inside any function is in global scope. Any variable in the global scope can be used anywhere. Let us consider the following code:
https://gist.github.com/debugmodedotnet/cb5cfee9ffad3e27d96a
var globalVar = "doo";
console.log(globalVar);
function Foo() {
console.log(globalVar);
}
Foo();
The variable globalVar is created in the global scope, so it can be used anywhere. As you might notice, globalVar is also being used inside the Foo function as well.
Local scope
Any scope which is not global scope is either local scope or function scope. JavaScript works with function scope, where each function has its own local scope. Let’s say we’ve created a function and a variable inside a function. Then the variable has local scope to the function. Let’s see it in this code snippet:
https://gist.github.com/debugmodedotnet/54ec9f06a1ed0fce1470
function Foo() {
var myVar = 'doo';
console.log(myVar);
}
Foo();
Here, the variable named myVar is the local scope inside the function Foo. myVar cannot be accessed in the global scope.
Nested functions
In JavaScript, a function can be nested inside another function. Let’s learn more in the following sections.
Lexical scoping
A nested function brings concepts of lexical scoping into JavaScript. Let’s say there is a function “A” which is inside function “B”. The inner function B has access to the scope of the outer function A: this is known as lexical scoping or static scoping in JavaScript. Let’s see it in action:
https://gist.github.com/debugmodedotnet/108769d90b5ad2ceac2a
(function A() {
var myVar = 'doo';
// console.log(localVar); // Throw Exception
function B() {
console.log(myVar);
var localVar = 'koo';
}
B();
})();
In the above snippet:
- Function B is nested inside function A;
- The variable named myVar is created in the outer function A, so can be accessed inside the child function B;
- The variable localVar is created inside the inner function B, so cannot be accessed inside the outer function A;
- As an output, you’ll find “doo” printed in the console
In short, lexical scoping means that anything (function, object, variable) defined in the parent scope can be accessed inside the child scope. However the opposite is not true.
Function’s “this” keyword
In JavaScript, the keyword “this” works in a weird way – it’s definitely not like anything you’ll see in other languages. To start with, in the global scope “this” represents either a document or window object. If you are running the application in the browser, in the global context, “this” represents a window object.
Let us consider the following code listing:
https://gist.github.com/debugmodedotnet/203ad589d7278e3c256d
if (this === window)
alert("window");
else
alert("not window");
In the browser, the code snippet above will alert “window”. And when JavaScript is running in the browser, in the global scope this is set to the window.
In the function scope (or inside the function), the value of “this” is determined by how the function is being called. Now let’s look at the following code listing:
https://gist.github.com/debugmodedotnet/2a797a995655497516ed
function Foo() {
returnthis;
}
var a = Foo();
alert(a);
In the browser, the snippet above will return window object. And if you run the snippet above in the strict mode then this will be assigned with the value undefined, because it’s been set to undefined at the time of entering in the execution context.
Here’s another code snippet:
https://gist.github.com/debugmodedotnet/b7351ea77b50957a6951
"use strict"
function Foo() {
returnthis;
}
var a = Foo();
alert(a);
In the browser, the snippet above will alert “undefined” because at the time of entering into the execution context, we are not setting any value for “this”.
To understand it better, let us assume that we are rewriting the above code listing as shown below:
https://gist.github.com/debugmodedotnet/33577d91b8686a1e27d3
"use strict"
function Foo() {
returnthis;
}
var a = window.Foo();
alert(a);
Here, we are calling the function “Foo” using the global object window. In this case, the value of “this” will be set to the global object window. In the strict mode, if we don’t set the calling base then the value of “this” would be set to undefined. However if we set the base, the value would be set to the base object.
Let us consider the following code listing:
https://gist.github.com/debugmodedotnet/b47c0fcb7c2584dc5643
var foo = {
fooAge: 37,
o: function () {
returnthis.fooAge;
}
};
var res = foo.o();
console.log(res);
Here we’re calling the function “o” using the base object foo. In this case, the execution context is set to the base object foo, so the value of this is also set to foo. If you print the value of “this”, [ object,object ] will be printed.
Function as a constructor
In JavaScript a function can be called using the new operation. If we call a function using “new”, it is known as function as constructor. When we create an object using “new”, the function constructor returns the object being created. Inside the function, the current object will be represented. Let’s see it here:
https://gist.github.com/debugmodedotnet/f4b2f11253064f7869a9
function Foo(num) {
this.myVar = num;
console.log(this);
}
var fooObject = new Foo(12);
console.log(fooObject.myVar);
Here we’re creating the fooObject using “new”. Inside the Foo function, this will represent the object being used to call the function constructor. A constructor function can either return one of the following options:
- Object referenced by this. [as shown in the above listing];
- Some other object.
Let us consider the following code listing:
https://gist.github.com/debugmodedotnet/18690a7a768e44b51a6c
function Foo(num) {
this.myVar = num;
return { myVar: 99 };
}
var fooObject = new Foo(12);
console.log(fooObject.myVar);
In above code snippet, function Foo is returning other object than the object return by this. As an output we will get 99 printed in the console.
The call() and the apply() methods
The call() and the apply() methods allow us to call a function indirectly and to invoke a function on the method of another object. However, function is not related to the object.
The call() method allows us to invoke a function with given value of this and passing each arguments separately. Let us consider the following listing:
https://gist.github.com/debugmodedotnet/95b4940cda009bbbccdb
function Student(name, age) {
this.name = name;
this.age = age;
returnthis;
}
function ScienceStudent(name, age) {
Student.call(this, name, age);
this.subject = "Physics";
}
ScienceStudent.prototype = Object.create(Student.prototype);
var stud1 = new ScienceStudent('DJ', 32);
console.log(stud1.name + stud1.subject);
Here we’ve created the Student function and then the ScienceStudent function. Inside the ScienceStudent function, we are using the call() method to call the Student function with passing value of this as the current object, along with the name and age parameters.
The apply() method allows us to invoke a function with a given value of “this” and a set of arguments. Arguments should be passed as an array like object.
Let us consider the following code listing. Using the apply() method on Math function, the largest in the array of integers can be found:
https://gist.github.com/debugmodedotnet/13b9b81573778cf9c965
var largestNumber = Math.max.apply(Math, [34, 56, 2, 6]);
console.log(largestNumber);
Here, the apply() method takes an object as value of this and an array as the input parameter. In further articles we will cover more on apply(), bind() and call() method on a JavaScript function.
Summary
In this, the second article of a series, we covered:
- Scopes in functions
- Nested functions and Lexical scoping
- Function’s “this” keyword
- Function as a constructor
- The call() and the apply() methods
I hope these two articles will help you in clearing the basics of JavaScript functions!