This article introduces the methods and principles of various function calls in Javascript in detail, which is of great help to understand JavaScript functions!
JavaScript, 5 ways to call functions
Time and again, I found that the bug-free Javascript code is caused by not really understanding how Javascript functions work (by the way, a lot of that code is written by me). JavaScript has the nature of functional programming, which will become a barrier to our progress when we choose to face it.
As beginners, let's test five function calls. From the surface we will think that those functions are very similar to those in C#, but we can see that there are still very important differences in the future. Ignoring these differences will undoubtedly lead to difficult-to-track bugs. First let's create a simple function, which will be used below, and this function only returns the current value of this and the two provided parameters.
The code copy is as follows:
<script type="text/javascript">
function makeArray(arg1, arg2){
return [ this, arg1, arg2 ];
}
</script>
The most commonly used method, but unfortunately, global function calls
When we learn Javascript, we learn how to define functions using the syntax in the example above.
, We also know that calling this function is very simple, and all we need to do is:
The code copy is as follows:
makeArray('one', 'two');
// => [ window, 'one', 'two' ]
Wait a minute. What's that window
alert( typeof window.methodThatDoesntExist );
// => undefined
alert( typeof window.makeArray);
// =>
window.makeArray('one', 'two');
// => [ window, 'one', 'two' ]
I say the most common method of calling is unfortunate because it causes the function we declare is global by default. We all know that global members are not a best practice for programming. This is particularly correct in JavaScript. You will not regret avoiding global members in JavaScript.
JavaScript function call rule 1
In functions that are not called directly by explicit owner objects, such as myFunction(), will cause this value to become the default object (window in the browser).
Function Calls
Let's create a simple object now, use the makeArray function as its method. We will use the json method to declare an object, and we will also call this method
The code copy is as follows:
//creating the object
var arrayMaker = {
someProperty: 'some value here',
make: makeArray
};
//invoke the make() method
arrayMaker.make('one', 'two');
// => [ arrayMaker, 'one', 'two' ]
// alternative syntax, using square brackets
arrayMaker['make']('one', 'two');
// => [ arrayMaker, 'one', 'two' ]
See the difference here, this value becomes the object itself. You may wonder why the original function definition has not changed, why it is not window. Well, this is how functions are passed in JSavar. Functions are a standard data type in JavaScript, or to be precise, an object. You can pass them or copy them. It is as if the entire function and the parameter list and the function body are copied and assigned to the property make in the arrayMaker, so it is like defining an arrayMaker like this:
The code copy is as follows:
var arrayMaker = {
someProperty: 'some value here',
make: function (arg1, arg2) {
return [ this, arg1, arg2 ];
}
};
JavaScript function call rule 2
In a method call syntax, such as obj.myFunction() or obj['myFunction'](), the value of this is obj
This is the main source of bugs in event handling code. Take a look at these examples
The code copy is as follows:
<input type="button" value="Button 1" id="btn1" />
<input type="button" value="Button 2" id="btn2" />
<input type="button" value="Button 3" id="btn3" onclick="buttonClicked();"/>
<script type="text/javascript">
function buttonClicked(){
var text = (this === window) ? 'window' : this.id;
alert( text );
}
var button1 = document.getElementById('btn1');
var button2 = document.getElementById('btn2');
button1.onclick = buttonClicked;
button2.onclick = function(){ buttonClicked(); };
</script>
Clicking the first button will display "btn" because it is a method call, this is the object to which it belongs (button element). Clicking the second button will display "window" because buttonClicked is called directly (unlike obj.buttonClicked().) This is the same as our third button, which puts the event handling function directly in the label. So the result of clicking the third button is the same as the second one.
Using JS library like jQuery has the advantage. When an event handler is defined in jQuery, the JS library will help override this value to ensure that it contains references to the current event source element.
The code copy is as follows:
//Use jQuery
$('#btn1').click( function() {
alert( this.id ); // jQuery ensures 'this' will be the button
});
How does jQuery overload the value of this? Continue reading
The other two: apply() and call()
The more you use JavaScript functions, the more you find that you need to pass functions and call them in different contexts. Just like Qjuery does in event handling functions, you often need to reset this value. Remember what I told you, in Javascript functions are also objects. Function objects contain some predefined methods, two of which are apply() and call(), which we can use to reset this.
The code copy is as follows:
var gasGuzzler = { year: 2008, model: 'Dodge Bailout' };
makeArray.apply( gasGuzzler, [ 'one', 'two' ] );
// => [ gasGuzzler, 'one' , 'two' ]
makeArray.call( gasGuzzler, 'one', 'two' );
// => [ gasGuzzler, 'one' , 'two' ]
These two methods are similar, the difference is the difference in the following parameters. Function.apply() uses an array to pass to the function, while Function.call() passes these parameters independently. In practice, you will find that apply() is more convenient in most cases.
JSavarscript function call rule 3
If we want to overload the value of this without copying the function to a method, we can use myFunction.apply( obj ) or myFunction.call( obj ).
Constructor
I don't want to dig into the definition of types in Javascript, but at this moment we need to know that there is no class in Javascript, and any custom type requires an initialization function. It is also a good idea to define your type using a prototype object (as a property of the initialization function). Let's create a simple type
The code copy is as follows:
//Declare a constructor
function ArrayMaker(arg1, arg2) {
this.someProperty = 'whatever';
this.theArray = [ this, arg1, arg2 ];
}
// Declare instantiation method
ArrayMaker.prototype = {
someMethod: function () {
alert( 'someMethod called');
},
getArray: function () {
return this.theArray;
}
};
var am = new ArrayMaker( 'one', 'two' );
var other = new ArrayMaker( 'first', 'second' );
am.getArray();
// => [ am, 'one' , 'two' ]
One very important and noteworthy is the new operator that appears in front of a function call. Without that, your function is like a global function, and the properties we create will be created on a global object (window), and you don't want to do that. Another topic is that because there is no return value in your constructor, if you forget to use the new operator, some of your variables will be assigned undefined. For this reason, it is a good habit to start with capital letters. This can be used as a reminder to not forget the previous new operator when calling.
With such caution, the code in the initialization function is similar to the initialization function you wrote in other languages. The value of this will be the object you will create.
Javascript function call rule 4
When you use a function as an initialization function, like MyFunction(), Javascript runtime will specify the value of this as a newly created object.
I hope that understanding the differences in the various functions call methods will keep your Sjavascript code away from bugs, and some such bugs will make sure you always know that the value of this is the first step to avoid them.