I am working on someone else's code and came across something puzzling.
Rather than calling functions the code is calling binding functions and then triggering it through a string.
Example 1:
bind("hello.world", function(){
console.log("hello world");
});
trigger("hello.world");
Rather than ---
Example 2:
helloWorld = function(){
console.log("hello world");
}
helloWorld();
What are the pros and cons between Example 1 and Example 2. Thank you.
Well, since javascript is an event driven programming language, I would recommend the first one.
Here's a case that illustrates the advantages of using event-handlers instead of simple function calls :
function someEventHandler(){
if($(this).hasClass('some-class'))
// do something
}
$('element').bind('eventName.eventNamespace',someEventHandler);
Now, if you simply call this function such as :
someEventHandler();
you can see that it will have no effect, because it is designed to be executed in a dom element context.
If you trigger the event that has the someEventHandler function as it's event-handler :
$('element').trigger('eventName.eventNamespace');
the function is called in the element context, something like :
someEventHandler.call($('element').get(0));
which will have the desired effect.
Moreover, you can bind multiple event-handlers to the same event and bind it to multiple elements.
If you would like to call a function for each of a list of dom elements, you would have to do something like this :
someEventHandler.call($('element1').get(0));
someEventHandler.call($('element2').get(0));
someEventHandler.call($('element3').get(0));
// ... and so on
while, with the first method would much more easier :
$('element1,element2,element3').bind('eventName.eventNamespace',someEventHandler);
$('element1,element2,element3').trigger('eventName.eventNamespace');
Note that the approach you take depends on the context you're using these functions. If your function has nothing to do with a dom element or you do not want more objects to subscribe to your event, you probably should keep it simple and use classic function declarations and calls.
Related
If I have multiple functions passed to a click event i.e.
#click="
inputHandler();
sendToken(computedUser.email);
responseMessage();
"
The function with an event parameter:
inputHandler(e) {
// code
}
Won't run. If I pass it on it's own:
#click="inputHandler"
It works fine.
Why is this and how can I get around it?
Internally Vue uses some RegExps to decide what form of event handler you're using.
If it seems to be the name of a method it will call it and pass the event.
If it seems to be inline code it'll just run it. In this case the event object is accessible as $event.
So:
#click="inputHandler($event)"
is roughly equivalent to:
#click="inputHandler"
Strictly speaking these aren't quite the equivalent, for example with component events that emit multiple arguments you'll only get the first one using $event like this.
See https://v2.vuejs.org/v2/guide/events.html#Methods-in-Inline-Handlers
For a deeper understanding see the Vue source code:
https://github.com/vuejs/vue/blob/0baa129d4cad44cf1847b0eaf07e95d4c71ab494/src/compiler/codegen/events.js#L96
Give your eyes a few minutes to adjust and it isn't too difficult to understand.
Personally I try to avoid anything more complicated than a single method call in the inline listener. Instead I'd suggest having something like #click="onSendClick" and let the method onSendClick worry about the details.
If I recall correctly, vue creates a wrapper function, if the passed value isn't a function. So
inputHandler();
sendToken(computedUser.email);
responseMessage();
actually get's turned into
function wrapper(){
inputHandler();
sendToken(computedUser.email);
responseMessage();
}
And as you can see the arguments passed to wrapper are lost.
The easiest way to fix this is probably to create a new method that accepts the event parameter and calls all of your function and use that one in the event handler.
Given the following, common scenario:
console.log(this); // window or any parent object
$('.selector').on('click', function(event) {
console.log(this); // clicked DOM element
});
var myFunc = function() {
console.log(this); // window or parent object
}
Since version 1.3 jQuery adds the event.currentTarget when binding event handlers for which counts event.currentTarget === this, so is there actually a good reason to manipulate this and switch context? Doesn't this behaviour generally go against the unspoken rule of "don't change keyword values" (like undefined = 'not defined')?
This "feature" of jQuery makes a lot of OOP less efficient and awkward imho, when we need to either cache the original this in a variable like self or use helpers like jQuery.proxy to reassign context to event handlers.
My question: is this just a relic of early jQuery implementations kept alive or is there an actual benefit which I cannot see (except maybe the slightly more convenient way than accessing event.currentTarget to get the element...)?
Let's say you've got an object with some methods on it:
var object = {
click: function() {
alert(this.property);
},
property: "Hello World"
}
You can call object.click() and, as you'd expect, you'll get "Hello World" in the alert.
You'd like to be able to use that "click" function as an event handler:
$("button").on("click", object.click);
However you discover that that doesn't work, because jQuery invokes the "click" function with this set to the DOM node for the clicked button. This is irritating. It's also inevitable because of the semantics of JavaScript function calls.
When you call the "click" function by way of a property reference, the language arranges for this to refer to that object. That's why object.click() works. However, when you fetch the reference to the function and pass it across a function boundary (as in the call to .on()), that relationship is lost. All that the jQuery method gets is a plain unadorned function that has absolutely no inherent relationship to the original object involved in its definition.
Thus, jQuery really has only two choices. The first is that it could make explicit the fact that the function is unconnected by arranging for this to be undefined. That wouldn't be very useful however. The other choice is to pick something interesting for this, and that's what the library does. Note that the native DOM level 0 event dispatch mechanism does the same thing.
The reason is that jQuery wants to mimic how regular event handlers (ones created without jQuery or any other library) works. In regular event handlers the value of this refers to the DOM node that triggers the event if there is one.
One could in fact consider that this is an example of jQuery not manipulating built-in behavior.
I am a beginner in javascript. and have no experience in programming, at all.
So I'd like you to be generous to beginner.
And here is my question.
I'm trying to code javascript unobtrusively.
So I put in all of my js codes into external js file. for example : test.js
and deleted these codes. to do unobtrusive js coding. for example :
and I tried to use these 2 methods :
variable.onclick=test(arg1, arg2);
variable.addEventListener('click',test(arg1, arg2),true);
but these triggers didn't work.
to put it delicately, function test(arg1, arg2) worked right after dom loding finished. regardless of activating 'click' trigger.
So I spent several hours solving this problem, and finally got a solution. this is it.
variable.onclick = function(){
variable.addEventListener('click',test('arg1','arg2'),true);
}
I wanna know why first two methods didn't work, and why that solution works well.
I solved the problem, but don't know why, and how...
In JavaScript, when you reference a function by name and follow that reference by a parenthesized list of arguments, that means that you want to call the function, right then and there. Thus a statement like
variable.onclick=test(arg1, arg2);
will assign to the "onclick" property the value obtained by calling the "test" function. In other words that statement means
Please call the function "test" passing it "arg1" and "arg2", and assign whatever it returns to the "onclick" property of the object referenced by "variable".
An event handler must be a function, however, and your "test" handler probably returns either nothing, or something that's not a function. So it didn't work.
Your solution, however, is also incorrect. You're successfully assigning a function to the handler property, but your function is itself installing another event handler. There's no reason to do that here, and in general setting up event handlers from within other event handlers is a suspicious practice. All you need is:
variable.onclick = function() { test(arg1, arg2); };
variable.onclick requires a function declaration by design. In your case you could have just done
variable.onclick = function(){
test(arg1,arg2);
};
The way you did it won't work because you're not giving the click handler any instructions. The corrections I have made say that when the variable (the one with the click handler attached) is clicked trigger this function that will in turn trigger the test function.
Same thing goes for the second one
variable.addEventListener('click', function(){
test(arg1,arg2);
});
This works again because you are saying when this variable is clicked run the function that will trigger the test function.
Basically you are trying to assign the result of running a function, the test function as a task for the click handler to run. This won't work except maybe your test function returns a function that contains code that you want to run when the click event is triggered. Hope this helps.
EDIT Helping people understand the question better
Can you call a argument and then use it in jQuery? I was thinking something like:
// Notice the "test" argument in the "foo" function
function foo(test) {
$("#randomDiv").click(function(){
$(test).toggle();
});
}
Would something like this work?
Yes, it will work. But it depends on what you want to achieve.
Your code will be something like a "instant-binder", eg: this code will bind toggling of the element when the document is parsed.
As far as you can bind many listeners for one event, following calls of the same functions will be executed in order.
You should run foo at the beginning of the html file. On that way you will be sure that the function document.ready would run wait until all the DOM is loaded.
I have following code that works -
$(function(){
$('#testbutton').click(function(){
var checkedValue = $('[name="someRadioGroup"]:radio:checked').val();
$('#result').html('The radio element with value <tt>' + checkedValue + '</tt> is checked');
});
});
I understand that $('#testbutton') fetches the HTML element with id testbutton and assigns an event handler to it.
But I don't understand why I need to put that code inside a function literal?
If I remove the $(function(){ (and the corresponding }); ) it does not work.
However other code can work without being wrapped in a function literal. Example -
alert('Hi there')
What is the difference? Why does alert work but the event assignment statement does not?
$(function(){...}); is shorthand for $(document).ready(function(){...});. The purpose of it is to not run your code until the elements that you intend to work with exist in the DOM (which generally is after the document is ready.)
It is not a requirement.
You are putting your code in an event handler that is invoked when the DOM is ready.
If you don't put your code in a DOM ready handler, and if your code performs DOM selection, you need to find some other way to to make sure the DOM is ready before it runs.
If your code doesn't perform DOM selection, then it's not needed. That's why your alert() works, because it doesn't need to fetch any elements.
An alternative is this.
<body>
<button id="testbutton">click</button>
<div id="result"></div>
<script type="text/javascript" src="/your/script.js"></script>
</body>
This places your code below all the elements on the page, so they are certain to be available when your code runs.
Another alternative is to use a window.onload handler.
window.onload = function() {
// your code
};
or using jQuery.
$(window).on("load", function() {
// your code
});
This is similar to the DOM ready handler, except that it waits for all resource, like images, to be loaded.
At the most basic level, something of the form (function(){...})() is a function literal that is executed immediately. What this means is that you have defined a function and you are calling it immediately.
This form is useful for information hiding and encapsulation since anything you define inside that function remains local to that function and inaccessible from the outside world (unless you specifically expose it - usually via a returned object literal).
A variation of this basic form is what you see in jQuery plugins (or in this module pattern in general). Since you are defining a function literal, it doesn't have access to anything from the outside world unless you explicitly pass in the information. Hence:
(function($) {
...
})(jQuery);
Which means you're passing in a reference to the actual jQuery object, but it's known as $ within the scope of the function literal.