Functions in Objects
In JavaScript, functions are first-class citizens, which means they can be assigned to variables, passed as arguments, and returned from other functions. This flexibility allows us to include functions within objects as properties, creating methods that belong to that object.
Let’s explore how functions can be used as properties in objects:
-
Assigning a Named Function to an Object Key
We can assign a function, like
sayHello
, to a key within an object.var obj = {}; function sayHello() { console.log('Hello'); } obj.sayHello = sayHello; console.log(typeof(obj.sayHello)); // "function" obj.sayHello(); // "Hello"
-
Using Anonymous Functions
Instead of defining a function separately, we can use an anonymous function and assign it directly to the object key.
var obj = {}; obj.sayHello = function() { console.log('Hello'); }; console.log(typeof(obj.sayHello)); // "function" obj.sayHello(); // "Hello"
-
Defining Functions Inside Object Initialization
We can also initialize an object with a function as one of its properties.
var obj = { sayHello: function() { console.log('Hello'); } }; console.log(typeof(obj.sayHello)); // "function" obj.sayHello(); // "Hello"
-
Using Simplified Syntax for Object Methods
JavaScript provides a shorthand syntax for defining functions within an object.
var obj = { sayHello() { console.log('Hello'); } }; console.log(typeof(obj.sayHello)); // "function" obj.sayHello(); // "Hello"
-
Using Computed Property Names for Function Keys
If the key name is stored in a variable, we can use bracket notation to assign it dynamically.
var key = 'sayHello'; var obj = { [key]() { console.log('Hello'); } }; console.log(typeof(obj.sayHello)); // "function" obj.sayHello(); // "Hello"
-
Ensuring Understanding with Another Example
Here’s a final example to reinforce the concept:
var obj = { ['foo']() {} }; obj.foo(); // Calls the function
This approach enables you to define methods dynamically and use functions as properties in JavaScript objects efficiently.
this
Keyword - An Early Look
In JavaScript, functions within objects often need access to the object’s own properties. The reason we place functions inside objects is usually because the function is closely related to that object's data or behavior. To allow a function to access the object’s properties, we use the this
keyword.
Understanding this
In JavaScript, this
represents the object on which a function was called. Let’s explore this with some examples:
-
Basic Example of
this
When a function is called on an object,
this
refers to that object. Here’s an example:function printFoo() { console.log(this); } printFoo(); // Logs the global object (or undefined in strict mode) var obj = {}; obj.printFoo = printFoo; obj.printFoo(); // Logs the obj itself, as `this` refers to `obj`
-
Accessing Object Properties Using
this
Using the same concept, we can create a function inside an object that accesses the object’s properties using
this
.var obj = {}; obj.name = 'Raghav'; obj.hello = function() { console.log('Hello ' + this.name); }; obj.hello(); // "Hello Raghav"
In the second example, this
inside hello
refers to obj
, allowing us to access obj.name
. This flexibility enables us to create methods that dynamically respond based on the object's state.
Functions as Objects
In JavaScript, functions are more than just blocks of reusable code—they are also objects. This might seem unusual at first, but it opens up interesting possibilities. Let’s break down what this means and how it works.
What Does It Mean for a Function to Be an Object?
In programming, an object typically has both state and behavior (properties and methods). Since functions in JavaScript are also objects, they can have their own properties (state) and methods (behavior). In other words, we can add "fields" and "functions" to a function itself.
Let’s see an example:
-
Adding Properties and Methods to a Function
Here, we define a function
sum
and add a new methodprintFunctionName
to it.function sum(a, b) { return a + b; } sum.printFunctionName = function() { console.log('sum'); }; console.log(sum(4, 6)); // 10 sum.printFunctionName(); // "sum"
In this example, sum
behaves like an object with its own method printFunctionName
. While this might seem unusual initially, getting comfortable with the idea of functions as objects can reveal interesting patterns and uses in JavaScript. We'll explore these applications further as we delve deeper into JavaScript.
call()
and apply()
in JavaScript
In JavaScript, functions are objects, so we can use methods like call()
and apply()
to control how they execute, especially to specify the value of this
within the function. Let’s explore how call()
and apply()
work with examples.
Understanding call()
and apply()
Both call()
and apply()
methods allow us to invoke a function with a specified this
value, enabling us to control the context in which the function is executed. The difference between them lies in how they handle function arguments:
call()
accepts arguments individually.apply()
accepts arguments as an array.
Let’s go through examples to illustrate this.
-
Basic Function Call
Here’s a simple function that logs its context (
this
) and its arguments:function sum(a, b) { console.log(this); console.log(arguments); console.log(a + b); return a + b; } sum(3, 4); // Uses default `this` (global context or undefined in strict mode)
-
Using
call()
With
call()
, we can specify thethis
context explicitly and pass individual arguments.sum.call(this, 3, 4); // `this` refers to the global or current context sum.call({}, 3, 4); // `this` is an empty object
-
Using
apply()
With
apply()
, we specifythis
and pass arguments as an array.sum.apply(null, [3, 4]); // `this` refers to `null` (or global in non-strict mode)
These methods provide flexibility in JavaScript by allowing control over the this
context and handling of arguments, which can be particularly useful in scenarios where context needs to be switched dynamically.
prototype
- A Built-in Object Inside Every Function
In JavaScript, every function has a built-in object associated with it called prototype
. This object allows us to add properties and methods that can be shared across instances created by that function, making it a powerful tool in JavaScript’s inheritance model.
Understanding prototype
When a function is created, JavaScript automatically assigns it a prototype
object. Initially, this object is empty, but it can be customized by adding properties and methods.
Let’s explore prototype
with some examples:
-
Checking the Default Prototype
By default, the
prototype
object is empty. Here’s how we can observe it:function sum(a, b) { return a + b; } console.log(sum(3, 4)); // 7 console.log(sum.prototype); // Initially an empty object
-
Adding Properties to the Prototype
We can add properties to the
prototype
object. These properties can then be accessed by all instances created with the function, asprototype
is shared among them.function sum(a, b) { return a + b; } sum.prototype.x = 10; // Adding a property to the prototype console.log(sum.prototype); // { x: 10 }
Constructor Functions
In JavaScript, we can create objects using special functions called constructor functions. Constructor functions look like regular functions but are called with the new
keyword, which initiates the process of creating a new object with a link to the function’s prototype
.
How Constructor Functions Work
-
Defining a Constructor Function
Here’s how to create a constructor function and add properties to its prototype.
function Constructor() { } Constructor.prototype.place = 'Bangalore'; Constructor.prototype.hello = function() { console.log('Hello'); }; console.log(Constructor.prototype); // Logs the prototype with place and hello properties
-
Creating an Object with
new
When you call the constructor function with the
new
keyword, a new object is created with a “secret” link toConstructor.prototype
.var obj1 = new Constructor();
In this example,
obj1
is a new object linked toConstructor.prototype
. -
Prototype Linking and Property Lookup
With the
new
keyword, any object created through the constructor function will look up its properties in the constructor’s prototype if they aren’t found directly on the object itself.function Constructor() { } Constructor.prototype.place = 'Bangalore'; Constructor.prototype.hello = function() { console.log('Hello'); }; var obj1 = new Constructor(); console.log(obj1.place); // "Bangalore" obj1.hello(); // "Hello"
-
Creating Multiple Objects
You can create multiple instances from the same constructor function, each sharing the properties and methods defined in the prototype.
var obj1 = new Constructor(); console.log(obj1.place); // "Bangalore" obj1.hello(); // "Hello" var obj2 = new Constructor(); console.log(obj2.place); // "Bangalore" obj2.hello(); // "Hello"
this
in Constructor Functions
In JavaScript, constructor
functions are used to create objects, and when you call a function with the new
keyword, a new object is created, with this
inside the function referring to that new object. This allows you to define properties and methods on the new object using this
.
How this
Works in Constructor Functions
-
Setting Properties on
this
When a constructor function is called with
new
,this
refers to the newly created object. We can usethis
to assign properties directly to the new object, making each instance created with the constructor function unique.function Person(name, age) { this.name = name; this.age = age; } var person1 = new Person('Alice', 30); console.log(person1.name); // "Alice" console.log(person1.age); // 30
Here,
this.name
andthis.age
are properties that get set on the newPerson
instance. -
Adding Methods Using
this
You can also add methods directly on
this
, making each instance have its own copy of the method (though this is less common than adding methods to the prototype).function Person(name) { this.name = name; this.sayHello = function() { console.log('Hello, my name is ' + this.name); }; } var person1 = new Person('Alice'); person1.sayHello(); // "Hello, my name is Alice"
-
Creating Multiple Instances with Different
this
ContextsEvery time you call a constructor function with
new
, a new object is created, andthis
in the function refers to that new instance. This allows each instance to have its own state.var person1 = new Person('Alice', 30); var person2 = new Person('Bob', 25); console.log(person1.name); // "Alice" console.log(person2.name); // "Bob"
-
Using
this
in Combination with PrototypesWhile properties are often set directly on
this
inside the constructor, methods are typically added to the function’sprototype
, allowing all instances to share the same method.function Person(name) { this.name = name; } Person.prototype.sayHello = function() { console.log('Hello, my name is ' + this.name); }; var person1 = new Person('Alice'); var person2 = new Person('Bob'); person1.sayHello(); // "Hello, my name is Alice" person2.sayHello(); // "Hello, my name is Bob"