jQuery using on and bind in the same call - javascript

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

Related

When do we use .bind() in Javascript

I have read that .bind is used to preserve the value of 'this' and the function will be invoked in certain point of time in future where as for call/apply it will be invoked immediately. What could be some examples/scenarios where we call the functions in future(for bind) and bind 'this' value. Also, I would like to know the when to use which one - call, apply and bind.

React Questions

Am I wrong if I explain the provided example like this :
once the component loads, the first button will be clicked automatically because this.handleClick1 was called by adding the bracket.
If you click the second button, there will be an error because you are using an es5 function and the "this" keyword behaves differently in an ES5 function compared with the arrow function or ES6 function. In ES5 function, the "this" keyword refers directly to the object that contains it and in this case the object that contains it is the which is an object and so there is an error because the button object does not contain a handleClick1 property. To fix this problem, you have to either use an ES6 function to declare the handleClick1 function or if you must use the ES5 function then you have to bind the function to the class
The first button is not clicked immediately. You are calling the handler function immediately instead of assigning it as the handler.
Arrow functions and .bind() act similar in that they statically bind this for that function.
However, React.Component won't statically bind methods to itself. If you (properly) set a button onClick to a component method, the context will change. To fix this somewhat unexpected behavior you will need to use arrow functions or .bind() in the constructor.
Keep in mind that if you were to call handleClick1() from inside your component (as you do when improperly setting the first button handler) this will be what you expect it to be. Thats just how this works.
Here's a sandbox for anyone interested: https://codesandbox.io/s/react-playground-forked-nimby?file=/index.js

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
});

Is this.someFunction.bind(this) redundant?

I'm reading someone's code and I see the following:
this.device_name.changes().onValue(this.changeName.bind(this))
From what I understand, onValue takes a callback function, and that function is this.changeName.bind(this)). Correct me if I'm wrong:
The default value of this in a function call refers the object with which the function was called upon.
The .bind(someObject) method causes the function's this to refer to someObject instead, when the function gets executed.
Knowing this (heh), this.changeName.bind(this) seems redundant: the default value for this when calling this.changeName will be the same this that is passed in the bind parameter.
So! Can the function be safely refactored to simply this.changeName with no differences in behavior?
No, the bind is very important here.
A function's this pointer is set at the time the function is called. The call, in this case, is down inside whatever object is invoking the callback. Many objects just call with a this pointer either as null or (in the case of DOM objects) pointing to the DOM object itself.
Using the bind function this way returns a new function that hard-wired the this reference to the value passed to bind. If you take out the bind, it'll completely hose up the this pointer. It will DEFINITELY change the behavior.

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