How come two different javascript events treat this function differently? - javascript

I have the following javascript-function:
onMouseMoved = (function(_this) {
console.log(_this)
return function(event) {
console.log(event)
return;
};
})(this);
How come the mousemove-event trigers
If I add this listener:
document.addEventListener('mousemove', onMouseMoved, false);
console.log(event) get's triggered but not console.log(_this)
but if I add this listener:
document.addEventListener('mouseenter', onMouseMoved, false);
It's the other way around, why?

You're not invoking console.log(this) in the event handler, you're invoking that immediately. It's an immediately-invoked function expression, or IIFE. It executes and returns a function which is assigned to onMouseMoved.
onMouseMoved = (function(_this) {
console.log(_this)
return function(event) {
console.log(event)
return;
};
})(this);
// console.log(_this) has already bee called at this point
// onMouseMoved has been set to the returned function:
//
// function(event) {
// console.log(event)
// return;
// };
document.addEventListener('mousemove', onMouseMoved, false);
document.addEventListener('mousemove', onMouseMoved, false);

That console.log(_this) is only going to be called when onMouseMoved is instantiated the first time.
That onMouseMove is defined as a function which is called immediately with a value of this (probably for function scoping reasons). That console logging of _this, isn't inside its event handling function, so it wouldn't be called on the events.

Related

Javascript: Bind/unbind function behavior

When I bind a function with the parent this passed in thisArg, I can't unbind the same named function expression, but without it I can unbind the function itself. Why is that?
This works:
choicesList.addEventListener("click", function() {
const self= this;
document.addEventListener("click", function checkClick(e) {
if (!e) e = event;
if (!self.contains(e.target)) {
document.removeEventListener("click", checkClick);
}
}, false);
});
This doesn't:
choicesList.addEventListener("click", function() {
document.addEventListener("click", function checkClick(e) {
if (!e) e = event;
if (!this.contains(e.target)) {
document.removeEventListener("click", checkClick);
}
}.bind(this), false);
});
The reason for this is issue is that calling bind() on a function returns a new instance of that function:
function someHandler() {
alert('hi');
}
const someHandlerBinded = someHandler.bind(document);
// Returns false, seeing as these are different instances of the function
console.log( someHandlerBinded === someHandler );
By setting an event handler directly, via the result of bind() as you are in your second block of code, this causes a new instance of that function handler to be passed to addEventListener(). This in turn means that the subsequent attempt to removing this handler on line:
document.removeEventListener("click", checkClick);
will fail, seeing that the the defined function checkClick is not the same as the actual handler function used for that click event (ie the new function instance returned from function checkClick(){ ... }.bind())
One way to resolve this might be the following:
choicesList.addEventListener("click", function() {
// Declare the bound version of the click handler
const boundClickHandler = function checkClick(e) {
if (!e) e = event;
if (!this.contains(e.target)) {
// Removing the result of bind, rather than the declared
// checkClick handler
document.removeEventListener("click", boundClickHandler);
}
}.bind(this)
// Adding the result of bind as you currently are doing
document.addEventListener("click", boundClickHandler, false);
});
It's because this is in a function that is nested within another function and the nested function doesn't have the same invocation context as the outer one. The first one works because you are caching the object that the outermost this is referencing and you are then able to correctly reference it in the inner function.
You can read more about the volatility of this here.

Jquery ONE function PURE js

there! i have a problem when creating one function just like JQUERY does.
here is the action : https://jsfiddle.net/77yzLt6v/
one time execution event
HTML :
<div id="justOnce">click me!</div>
function one(dom, event, callback) {
dom.addEventListener(event, function(e) { // add event
this.removeEventListener(event, callback); // remove it
});
}
one(document.getElementById("justOnce"), "click", function() {
alert("this alert only show once time");
});
what's wrong with my code?
thanks in advance...
Your code binds an event handler that removes callback as an event handler.
The only problem is … you never bound callback as an event handler in the first place.
You want something more like this:
function one(dom, event, callback) {
function handler(e) {
callback.call(this, e);
this.removeEventListener(event, handler);
}
dom.addEventListener(event, handler);
}
i.e.
You need to call the callback
You need to remove the event handler you actually bound
New standard supports this, but don't work in any browser yet (caniuse.com)
window.addEventListener('resize', console.log, {once: true})
polyfill:
;(function(){
let p = document.createElement('p')
let count = 0
let event = new CustomEvent('x')
p.addEventListener('x', () => {i++})
p.dispatchEvent(event)
p.dispatchEvent(event)
if (i != 2) return
for (let obj of [Window, Element]) {
let orig = obj.prototype.addEventListener
function addEventListener(type, callback, opts) {
let args = Array.from(arguments)
if(opts && opts.once) {
function handler(e) {
callback.call(this, e)
this.removeEventListener(type, handler)
}
args[1] = handler
}
orig.apply(this, args)
}
obj.prototype.addEventListener = addEventListener
}
}())

How to get window.event in removeEventListener

This scripts is getting #testDiv and add some listeners to it and works fine.
(function() {
this.testObject = function() {
/*options*/
this.options = arguments[0];
};
/*make object*/
testObject.prototype.make = function(){
this.targetElement = document.getElementById('testDiv');
this.targetElement.addEventListener('mousedown', function(evt){
...
});
this.targetElement.addEventListener('mouseup', function(evt){
...
});
this.targetElement.addEventListener('mousemove', function(evt){
...
});
};
}());
But as far as I know, in order to remove the listeners I should use real functions instead of anonymous functions in addEventListener and removeEventListener
this.targetElement.addEventListener('mousedown', mouseDownFunction(evt));
this.targetElement.addEventListener('mouseup', mouseUpFunction(evt));
this.targetElement.addEventListener('mousemove', mouseMoveFunction(evt));
And in removeEventListener:
this.targetElement.removeEventListener('mousedown', mouseDownFunction(evt));
this.targetElement.removeEventListener('mouseup', mouseUpFunction(evt));
this.targetElement.removeEventListener('mousemove', mouseMoveFunction(evt));
There is a problem here, I can't get evt ( event ) handler in real functions. Error: evt is undefined
for example in mouseDownFunction I get undefined :
function mouseDownFunction(evt){
console.log( evt ); // evt is undefined
console.log( window.event ) // undefined
}
How can I get evt?
thanks in advance.
You can do this
var listener = function (event) {
/* do something here */
};
this.targetElement.addEventListener('click', listener, false);
this.targetElement.removeEventListener('click', listener, false);
Or just this, which should work exactly the same:
function myListener(event) {
/* do something here */
}
this.targetElement.addEventListener('click', myListener, false);
And remove it:
this.targetElement.removeEventListener('click', myListener, false);
Note that when you add the event and pass in the function, you don't need to add the argument. You are just adding a reference to the function (function pointer).
In addition to Haukur answer. You can also do it like this.
this.targetElement.addEventListener('click', function(event){myClickFunction(event);});
this.targetElement.removeEventListener('click', function(event){myClickFunction(event);});
In this we are creating a anonymous function as you were doing earlier and then pass the parameter of that anonymous function to your function ie myClickFunction.
In case of extra parameters, just add them in the function.
this.targetElement.addEventListener('click', function(event){myClickFunction(event, param1, param2, param3);});
myClickFucntion(event, param1, param2, param3){
}

Registering for MouseMove: Event object is always undefined

I have a Javascript object that registers for the mouse move event. But my problem is that the event parameter is not being passed in my custom function, its always undefined.
If you look inside the function touchMove() below you will see that the parameter event is always undefined for some reason?
What am I doing wrong?
MyObject.prototype.registerPointerEvents = function()
{
var instance = this; // function() { instance.func(); }
var ele = this.getAttrib("divEle");
ele.addEventListener("mousemove", function() { instance.touchMove(); }, false);
}
MyObject.prototype.touchMove = function( /*Event*/ event )
{
// Virtual function to be overridden in child classes
console.log("MOVE 1: "+event); // here it outputs event is undefined
if (!event)
event = window.event;
console.log("MOVE 2: "+event); // here event is still undefined
if (this.getAttrib("isDragging") == "true")
{
console.log("MOVE TRUE");
this.getAttrib("divEle").style.left = event.clientX+"px";
this.getAttrib("divEle").style.top = event.clientY+"px";
}
}
Of course is undefined, you are calling an anonymous function without the parameter.
Better use this:
ele.addEventListener("mousemove", instance.touchMove, false);
That is (almost) the same as
ele.addEventListener("mousemove", function(e) { instance.touchMove(e); }, false);

What does this code (from a Mozilla Add-on tutorial) do?

var Helloworld = {
onLoad: function() {
// initialization code
this.initialized = true;
},
onMenuItemCommand: function() {
window.open("chrome://helloworld/content/hello.xul", "", "chrome");
}
};
window.addEventListener("load", function(e) { Helloworld.onLoad(e); }, false);
http://kb.mozillazine.org/Getting_started_with_extension_development
I don't understand the function(e) { Helloworld.onLoad(e); part. I think it passes an event parameter e to the onLoad function, but the onLoad function doesn't have onLoad: function(e) {} to receive e, so what's going on?
Just defines an anonymous function: the said function will will be called when the event load is triggered.
Note that in JavaScript, the function declaration isn't strict. One can call a function with parameters even if the declaration doesn't explicitly show such. In other words, there is no such thing as a "function signature" (like in Java, C++ etc.). The JavaScript interpreter will only call the "hasmethod" method on the object to determine if "method X" is implemented.
var Helloworld = {
// parameters can be sent to "onload" but they will be ignored.
onLoad: function() {
// initialization code
this.initialized = true;
},
onMenuItemCommand: function() {
window.open("chrome://helloworld/content/hello.xul", "", "chrome");
}
};
// attach an event handler to the event "load". Pass the event variable "e"
// even though the receiving function will ignore it.
window.addEventListener("load", function(e) { Helloworld.onLoad(e); }, false);
You can change the onLoad if you want to have a parameter, it's just an example onLoad. It's JavaScript, after all, not C/C++ etc.

Categories