What's the .apply jQuery function? - javascript

I see that in different plugins and codes, but I don't understand what does that function... In the jQuery api isn't referenced!

apply calls a function with a set of arguments. It's not part of jQuery, it's part of core Javascript. However, there is mention of it in the jQuery docs:
http://docs.jquery.com/Types#Context.2C_Call_and_Apply
Syntax:
somefunction.apply(thisObj, [argsArray])
The above calls the function somefunction, setting this to thisObj within the function's scope, and passing in the arguments from argsArray as the arguments to the function.

Essentially, apply will call a function with the context being set to the object you apply the function to. This means that within the function, referencing this will refer to that object.

Related

Calling vs invoking a function

Up to this point, I thought "calling" and "invoking" a function meant the same thing. However, in a YouTube tutorial it said to invoke a function by calling it. My first thought was that the wording was a mistake, but on W3Schools' page on Function Invocation, it says:
It is common to use the term "call a function" instead of "invoke a
function" ... In this tutorial, we will use invoke, because a
JavaScript function can be invoked without being called.
Okay, so there's a difference. What is it?
Your reference text:
It is common to use the term "call a function" instead of "invoke a
function" ... In this tutorial, we will use invoke, because a
JavaScript function can be invoked without being called.
Now let me rephrase it:
It is common to use the term "call a function" instead of "invoke a
function" ... In this tutorial, we will use the term invoke instead of call, because a
JavaScript function can be invoked indirectly like fn.call() and fn.apply() without being called directly like fn().
So, when I do fn(), it's invoked directly and when I do it like fn.call(), it's invoked indirectly but in both cases, the function is being invoked. Otherwise, I see no difference here and I can also say that I can call a function in many ways, for example:
fn(); // I'm calling it
fn.call(); // I'm calling it
fn.apply(); // I'm calling it
So, the difference is semantic but both are interchangeable, IMO. BTW, I wrote a comment above, under the question and I would like to put it here, which is:
IMO, that's a misleading statement. Maybe there are some indication of
call/apply or something else but it's totally confusing.
The difference is semantic and subtle. When you call a function, you are directly telling it to run. When you invoke a function, you are letting something run it.
There is one way to call a function:
myFunction()
Here, you are invoking the function (letting it run) by calling it directly.
There are many ways to invoke a function (given throughout different comments and answers). Here's one example:
function invoker(functionName) {
functionName()
}
invoker(myFunction)
Here, by calling invoker, you are invoking myFunction, which is being called indirectly.
Yes, in most cases we use both to refer the execution of a function.
There are 2 ways to reach place B from your HOME.
Direct/Automatic way (Invoke), i.e. if you choose first way, you do not need to walk. Someone will automatically take you to place B.
Indirect way (Call), i.e. if choose second way, you only need to reach A(by walk). Someone is there at place A to automatically take you to place B.
Have a look at the below image. I think it will clear your doubt.
In case of Calling, you originally refer to the statement that actually calls the function.
In case of Invoking, you indirectly refer to calling statement to actually invoke/run the function.
Many people use the term calling and invoking interchangeably but that's not right. There is a very slight difference between calling and invoking a function. In JavaScript functions can be invoked without being called which means that the code inside the body of the function can be executed without creating an object for the same. It is tied to the global object. When there is no individual object, the value of this is associated with the global object.
There is also a difference between call and apply, the fundamental difference is that call() accepts an argument list, while apply() accepts a single array of arguments. A different this object can be assigned when calling an existing function. this refers to the current object, the calling object. With call, you can write a method once and then inherit it in another object, without having to rewrite the method for the new object.
So, the major difference between invoking and calling comes in terms of the this object. Calling let's you set the this value whereas invoking just ties it to the global object.
"function invoked" means a function got executed
"function called" means that a function was called by another function and then executed
"function invoked without being called" is a function that got self invoked without being called by another function
example of a self invoking function calling another function:
var f = (function() {
foo();
})(); ///() here means it self invoked -- without being called directly.
var foo = (function() {
///Do something here
});

jQuery using on and bind in the same call

I ran into this code and am not sure how it works:
options.on('change', this._onBundleOptionChanged.bind(this));
this._onBundleOptionChanged is simply a function that takes one paramter, event:
_onBundleOptionChanged: function onBundleOptionChanged(event) {
jQuery version is 1.12.4.
the bind call returns function bound() whatever that means and if bind is passed a single parameter it has to be an object the documentation says "An object containing one or more DOM event types and functions to execute for them." here: http://api.jquery.com/bind/
So as I understand what it accomplishes, calling the _onBundleOptionChanged method when a select dropdown is changed.
What I don't understand is how, or why anyone would program it this way.
It is not jQuery's bind.
It is function.prototype.bind (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_objects/Function/bind).
It is changing the context of the callback function to the be the same as when this statement is executed. This can be very useful.
In most cases, the value of this is determined by how a function is called. It can't be set by assignment during execution, and it may be different each time the function is called. ES5 introduced the bind method to set the value of a function's this regardless of how it's called, and ES2015 introduced arrow functions which don't provide their own this binding (it retains the this value of the enclosing lexical context).
See:
How to access the correct `this` inside a callback?
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this

Why do we use $(this) inside a function acting on a jQuery object?

From what I understand, this inside of a function refers to the object invoking the function. So, for instance, in
myObj = { name : "Charlie", getType : function() { return typeof(this); } };
console.log(myObj.getType());
the object invoking the function getType is myObj and therefore typeof(this) is typeof(myObj).
Why, then, do I always see $(this) inside jQuery functions? For instance, in
$('.not-taller-than-50-pixels').each(function()
{
if ($(this).height() > 50) $(this).height(50);
});
doesn't $('.not-taller-than-50-pixels') return an array of jQuery objects and so inside the each the invoking function is a jQuery object and so this would refer to that jQuery object and I can simply write if (this.height() > 50) this.height(50); ???
From what I understand, this inside of a function refers to the object invoking the function.
that is correct, if the function is being called as a property of that object. However, in your case, your jQuery collection isn't invoking the function as a property of the jQuery collection, instead it's invoking the function using either .apply or .call to set its context to the element currently being iterated over.
https://github.com/jquery/jquery/blob/1.9.1/src/core.js#L628
It works similar to the way Array.prototype.forEach does. I assume that similarity is on purpose so that it seems familiar to most developers who are also familiar with native methods.
Here's an example more inline with your first snippet that WILL act the way you were expecting:
$.fn.alertHeight = function () {
alert(this.height());
}
$('body').alertHeight();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<p>Hello World!</p>
Because the function is stored on the prototype of $, and invoked as a property of a jQuery collection (which is an instance of $,) this refers to the jQuery collection, thus allowing us to use this.height() directly to get the height of the first element in the collection.
We use the $(this) because otherwise the this doesn't have a getter/setter method .height(). $() gives all selected elements access to jquery methods which plain javascript equivalents don't have. try console.log($(this), " VS ", this); remember that $() is a function.
doesn't $('.not-taller-than-50-pixels') return an array of jQuery
objects
No, $('.not-taller-than-50-pixels') does not return an array of JQuery objects. It returns a single JQuery object, which may wrap zero, one, or many DOM elements.
and so inside the each the invoking function is a jQuery
object and so this would refer to that jQuery object and I can simply
write if (this.height() > 50) this.height(50); ???
The callback function passed to .each() is invoked for each of the DOM elements wrapped by the JQuery object, and when the callback function is invoked, the DOM element is used as the context. That is, inside the callback function this will reference the DOM element, not a JQuery object.
This is stated in the JQuery documentation for the .each() function:
When called it iterates over the DOM elements that are part of the
jQuery object. Each time the callback runs, it is passed the current
loop iteration, beginning from 0. More importantly, the callback is
fired in the context of the current DOM element, so the keyword this
refers to the element.

Defining "this" within a JavaScript function and also sending the function an arguement

I have a function called myFunction().
Within myFunction, I want "this" to refer to the parent's "this".
Ok, I will call myFunction as myFunction.call(this).
Great!
Oops, Now I need to pass an argument to myFunction. Normally, I would just use myFunction(myArg), but that call thing kind of messed me up.
How can this be done?
Parameters following the first will be passed as individual arguments to your function documentation:
myFunction.call(this, argument_1, argument_2);
Alternatively you could use apply which allows you to pass the arguments as an array (or an array like object) documentation:
myFunction.apply(this, argsArray);
Javascript Call Function
After the bind you can send the function all the arguments you want
myFunction.call(this,arg1,arg2,...);

why is it necessary to wrap function call in a function body

I often see something like the following in JavaScript:
$("#sendButton").click(function() {
sendForm();
}
Why is it necessary to wrap the call to sendForm() inside a function? I would think that doing it like this would be more readable and less typing.
$("#sendButton").click(sendForm);
What are the advantages/disadvantages to each approach? thanks!
There's typically two cases where you'd want to use the former over the latter:
If you need to do any post-processing to the arguments before calling your function.
If you're calling a method on an object, the scope (this reference) will be different if you use the second form
For example:
MyClass = function(){
this.baz = 1;
};
MyClass.prototype.handle = function(){
console.log(this.baz);
};
var o = new MyClass();
$('#foo').click(o.handle);
$('#foo').click(function(){
o.handle();
});
Console output:
undefined
1
Probably one too many answers by now, but the difference between the two is the value of this, namely the scope, entering sendForm. (Also different will be the arguments.) Let me explain.
According to the JavaScript specification, calling a function like this: sendForm(); invokes the function with no context object. This is a JavaScript given.
However, when you pass a function as an argument, like this: $(...).click(sendForm), you simply pass a reference to the function for later invocation. You are not invoking that function just yet, but simply passing it around just like an object reference. You only invoke functions if the () follows them (with the exception of call and apply, discussed later). In any case, if and when someone eventually calls this function, that someone can choose what scope to call the function with.
In our case, that someone is jQuery. When you pass your function into $(...).click(), jQuery will later invoke the function and set the scope (this) to the HTML element target of the click event. You can try it: $(...).click(function() { alert(this); });, will get you a string representing a HTML element.
So if you give jQuery a reference to an anonymous function that says sendForm(), jQuery will set the scope when calling that function, and that function will then call sendForm without scope. In essence, it will clear the this. Try it: $(...).click(function() { (function() { alert(this); })(); });. Here, we have an anonymous function calling an anonymous function. We need the parentheses around the inner anonymous function so that the () applies to the function.
If instead you give jQuery a reference to the named function sendForm, jQuery will invoke this function directly and give it the scope that it promises to always give.
So the answer to your question becomes more obvious now: if you need this to point to the element target of the click when you start work in sendForm, use .click(sendForm). Otherwise, both work just as well. You probably don't need this, so skip the anonymous function.
For those curious, scope can be forced by using the JavaScript standard apply or call (see this for differences between the two). Scope is also assigned when using the dot operator, like in: obj.func, which asks of JavaScript to call a function with this pointing to obj. (So in theory you could force obj to be the scope when calling a function by doing something like: obj.foo = (reference to function); obj.foo(); delete obj.foo; but this is a pretty ugly way of using apply.
Function apply, used by jQuery to call your click handler with scope, can also force arguments on the function call, and in fact jQuery does pass arguments to its click handlers. Therefore, there is another difference between the two cases: arguments, not only scope, get lost when you call sendForm from an anonymous function and pass no parameters.
Here you are defining an anonymous event handler that could call multiple functions inline. It's dirty and tough to debug, but people do it because they are lazy and they can.
It would also work like your second example (how I define event handlers):
$("#sendButton").click(sendForm)
Something you get by defining your event handlers inline is the ability to pass event data to multiple functions and you get this scoped to the event object:
$("#sendButton").click(function(event) {
sendForm();
doSomethingElse(event);
andAnotherThing(event);
// say #sendButton is an image or has some data attributes
var myButtonSrc = $(this).attr("src");
var myData = $(this).data("someData");
});
If all you are doing is calling sendForm, then there isn't much difference, in the end, between the two examples you included.
$("#sendButton").click(function(event) {
if(event.someProperty) { /* ... */ }
else { sendForm({data: event.target, important: 'yes'}); }
}
However, in the above case, we could handle arguments passed to the callback from click(), but if the sendForm function is already equipped to handle this, then there's no reason why you wouldn't place sendForm as the callback argument if that is truly all you are doing.
function sendForm(event) {
// Do something meaningful here.
}
$("#sendButton").click(sendForm);
Note that it is up to you where you handle the differing layers of logic in your program; you may have encapsulated certain generic functionality in a sendForm function then have a sendFormCallback which you pass to these sorts of function which handle the interim business of event/callback processing before calling sendForm itself.
If you are working in a callback-heavy environment, it would be wise to separate significant functionality from the callback triggers themselves to avoid callback hell and promote maintainability and readability in your source code.
It's just to lock scope. When you wrap that sendForm() in the anonymous function that closes over the current scope. In other words, the this will be kept with it. If you just pass sendForm then any calls to this will come from the calling scope.
This is a good question for learning about scope in javascript, and questioning conventions.
Nope, that second example is perfectly valid.
99.9% of jQuery examples use the first notation, that doesn't mean you need to forget basic JavaScript syntax.

Categories

Resources