📜 ⬆️ ⬇️

Four function call patterns in javascript

JavaScript was introduced as a functional programming language. The reason is that functions in JS do not just divide logic into operational blocks, functions are first-class objects that can create other objects. Such a dependence on functions is both a strength and a real curse of this language. The strength is that the language, having such features, becomes lightweight and fast (which JavaScript was originally seen by its creators). However, if you do not know what you are doing - definitely wait for trouble.

I propose to look at the function call patterns, or rather, how the result varies significantly depending on the selected pattern. We will also look at how this behaves, depending on how the function is called.

So, there are four ways to call functions:
')


Function execution


JavaScript, like all modern languages, can modulate logic inside functions, and these functions can be called at any time, in the middle of an already running process. By calling a function, we give it the necessary parameters and process control, stopping the current operation. Call operator - parentheses () , which can include parameters, separated by commas.

Unfortunately, there are several patterns for calling functions. About them do not need to be aware of. They need to be jagged and understood, because, depending on the chosen pattern, you will get different results. In my opinion, this feature is an error in the design of the language itself, and if JavaScript were created in less haste and with more attention, various problems of a similar nature could have been avoided.

Four patterns


As already mentioned, the operator to call a function is one, and there are four ways to call it.

Method Call - Method Invocation

When a function is part of an object, it is called a method. A “method call” is a call to a function belonging to an object. Example:

var obj = {
value : 0 ,
increment : function ( ) {
this . value + = 1 ;
}
} ;

obj. increment ( ) ;

In the “method call”, the value of this will refer to the object to which the function belongs, in our case, to obj, and this connection will be established after the function is launched, which is the term late binding .

Function Call - Function Invocation

The function call is performed using the () operator:

add ( 2 , 3 ) ; //five

Using this pattern, this bound to a global object. This is undoubtedly a language error — the constant binding of this to a global object can destroy its context. This is especially noticeable if you use the function inside the method. Let's look at an example:

var value = 500 ; // Global variable
var obj = {
value : 0 ,
increment : function ( ) {
this . value ++;

var innerFunction = function ( ) {
alert ( this . value ) ;
}

innerFunction ( ) ; // Function invocation pattern
}
}
obj. increment ( ) ; // Method invocation pattern

What do you think will be displayed on the screen? If you decide that 1 - you are wrong (but do not blame yourself - blame crooked JavaScript design). The correct answer is 500. Note that innerFunction is called using the aforementioned “function call” pattern, so this bound to a global object. As a result, we get 500.

You can easily get around this problem by creating the this variable, but this, in my opinion, is a hack.

var value = 500 ; // Global variable
var obj = {
value : 0 ,
increment : function ( ) {
var that = this ;
that. value ++;

var innerFunction = function ( ) {
alert ( that. value ) ;
}

innerFunction ( ) ; // Function invocation pattern
}
}
obj. increment ( ) ;

Thus, we tied this to the object within which the function is called.

Constructor Call - Constructor Invocation

Warning: this is another JavaScript feature that is very different from classic OOP languages! It is a prototype-oriented programming language, but its creators thought that the people of the “classical school” (of whom most) would feel uncomfortable. As a result, the principles of the classic OOP were added to the prototype JavaScript and it turned out what turned out to be a mess.

In classic OOP, an object is a class implementation. In C ++ and Java, the new operator is used for this implementation. Apparently, the creators of JS decided not to go far beyond the example, and to implement something similar in the “constructor challenge” pattern ...

The pattern is started by placing the new operator right before the call, for example:

var Cheese = function ( type ) {
cheeseType = type ;
return cheeseType ;
}

cheddar = new Cheese ( "cheddar" ) ; // Returns an object, not a type.

Despite the fact that Cheese is a functional object (which means it can digest the code), we created a new object by calling a function with new . this in this case will refer to the newly created object, and the return behavior will be changed. Speaking of return. Its use in the "constructor call" has two features:


var obj = {
data : "Hello World"
}

var Func1 = function ( ) {
return obj ;
}

var Func2 = function ( ) {
return "I am a simple type" ;
}

var f1 = new Func1 ( ) ; // f1 is assigned to the object
var f2 = new Func2 ( ) ; // f2 assigned to new object

We could ignore the use of this , and assign literals to objects if it were not for one thing: the creators of JavaScript associated one of the key features of the language with the given pattern — creating objects with an arbitrary reference to the prototype ( for more , see English here ). This pattern is unintuitive, moreover, problems often arise with it. The solution to the problem was suggested by Douglas Crockford: you can use the augment object with the create method. I am pleased to announce that since version 1.8.5 of JavaScript, Object.create is quite a working tool.

Call apply and call - Apply And Call Invocation

This pattern is designed much better than others. It allows you to manually start the function, simultaneously providing it with parameters and designating this . Due to the fact that our functions are full-fledged objects, each function in JavaScript is associated with Function.prototype , which means we can easily add methods to them.

This pattern uses two parameters: the first is the object this is bound to, the second is an array associated with the parameters:

var add = function ( num1 , num2 ) {
return num1 + num2 ;
}

array = [ 3 , 4 ] ;
add. apply ( null , array ) ; // 7

In the example above, this refers to null (the function is not an object), and the array is bound to num1 and num2 . But let's continue experimenting with the first parameter:

var obj = {
data : 'Hello World'
}

var displayData = function ( ) {
alert ( this . data ) ;
}

displayData ( ) ; // undefined
displayData. apply ( obj ) ; // Hello World

This example uses apply to bind this to obj . As a result, we are able to get the value of this.data . The real value of apply lies precisely in the binding of this .

In JavaScript, there is also a call operator, similar to apply all, except that it receives not a parameter, but a list of arguments.

Conclusion


Good or not, JavaScript is about to take over the world. That is why it is just necessary to know about its features, especially about those that should be avoided. Understanding the four function call patterns is a prerequisite for learning JavaScript. I hope that this post will help you.

Source: https://habr.com/ru/post/155815/


All Articles