Is it possible to use object as invokable? - javascript

I found in requirejs-text plugin weird code. So load method accepts onLoad callable which is invoked for a few times as onLoad(), but later there is error handler which checks for an error method.
if (onLoad.error) {
onLoad.error(err);
}
Am i missing something or it's obvious code issue?

You cannot use a normal object as a callable entity, but a function is a type of object, so you can add properties to a function.
var onLoad = function(){
};
onLoad.error = function(){
};

Related

How can you pass anonymous functions as parameters to existing functions to use later in javascript?

I am trying to create a basic javascript framework that you can pass different things into, including functions for it to execute later. Right now, I'm in a more simple testing phase, but I can't quite get the function calling to work. A piece of my code is here:
[My JS Fiddle][1]http://jsfiddle.net/mp243wm6/
My code has an object that holds different data, and I want to call the method later, but with data that is available at the time of creation. Here is a code snippet of the function that uses the function that is passed to the object:
clickMe : function() {
this.obj.click(function() {
this.func();
});
}
Any suggestions or things I should read are welcome.
The problem is that there're two different contexts:
clickMe : function() {
// here is one
this.obj.click(function() {
// here is another
this.func();
});
}
You can simple pass the function as parameter, like the following:
clickMe : function() {
this.obj.click($.proxy(this.func, this));
}
http://jsfiddle.net/mp243wm6/2/
The problem:
Considering your code in the JSFiddle, you have:
onClick : function() {
this.obj.click(function() {
this.func();
});
},
As noted, you have different contexts going on here.
Consider the snippet this.obj.click(function() { this.func(); }). The first this here is a reference to the framework.events object. The second this here is a reference to whatever will be this when this function get called. In the case of your JSFiddle, when this.func gets called, this is actually the DOM object that represents the <div id="test">TEST</div> node. Since it doesn't have a func function, calling func() on it causes:
Uncaught TypeError: undefined is not a function
You have to understand the following: you have to pass the correct this in which you want the function func to be called.
The solution:
A couple of ways to make it work as you would like:
1. with bind
this.obj.click(this.func.bind(this));
This way, you are telling: "call my this.func function, but make sure that it will be called using the this that I am passing as a parameter". Vanilla JS, no $.proxy stuff.
JSFiddle
2. with a copy of the reference to the actual function
onClick : function() {
var theFunctionReference = this.func;
this.obj.click(function() {
theFunctionReference();
});
},
This way, you will not rely on the value of this outside of the context of the framework.events object.
JSFiddle
The issue is that this is not bound to the correct object. I would suggest you look into Function.bind() because that creates a function with this pointing to the right thing.

How to correctly define (function || function) inside a Javascript object?

This works:
<div id="result"></div>
<script type="text/javascript">
var Base64Encode = window.btoa || CryptoJS.enc.Base64.stringify;
document.getElementById('result').innerHTML = Base64Encode("Please work.");
</script>
However, this:
<div id="result"></div>
<script type="text/javascript">
var Test = {
Base64Encode: window.btoa || CryptoJS.enc.Base64.stringify
};
document.getElementById('result').innerHTML = Test.Base64Encode("Please work.");
</script>
Generates an error of "TypeError: 'btoa' called on an object that does not implement interface Window."
Fiddle:
http://jsfiddle.net/kAGU2/
Why does the first example work but the second one emit that error? What's the correct way to fix this particular error?
Why does the first example work but the second one emit that error?
When the function is called as Base64Encode(), the this context is implicitly set to window. However, when you call it as a method on Test.Base64Encode(), this will refer to Test and btoa grumps about that.
What's the correct way to fix this particular error?
You will need to bind it to the expected context:
Base64Encode = window.btoa
? window.btoa.bind(window)
: CryptoJS.enc.Base64.stringify;
Use .bind():
var Test = {
Base64Encode: function() {
if (window.btoa)
return window.btoa.bind(window);
return CryptoJS.enc.Base64.stringify;
}()
};
You got the error because you invoked the function via that object property reference. When you do that, the value of this is set to a reference to the object involved. The btoa() function doesn't like that (for who knows what reason), but .bind() creates a wrapper function for you that ensures the proper this.
It appears as that btoa function is a member function of Window class. And so it has to be called with this set to window.
In order it to work in your setup you should call it this way:
Test.Base64Encode.call(window,"Please work.");

Call function at native Error object's construction

In the following code example :
var oldConstructor = Error.constructor;
Error.constructor = function() {
console.log('Constructor');
oldConstructor.apply(null, arguments);
};
var a = new Error('ok');
Why isn't 'Constructor' printed ?
How can I run a function every time a native Error object's constructor is called ?
The goal I'm trying to achieve is that rather than bubbling Errors up the callback chain of the different modules used in my code base (mongoose, express.js, ...etc), I just want every error to emit an event or call a method (maybe with an Observer pattern).
I'm trying to solve the problem this way rather than modifying every line of code creating a new Error object.
Thanks in advance !
Error.constructor is a reference to the Function function, because Error is a function and functions are constructed by Function.
You could have done:
var oldError = Error;
Error = function( arg ) {
console.log('Constructor');
return new oldError( arg );
};
But this is not guaranteed to work at all as modules could have stored a local reference to the Error constructor if they run before your code.
You could instead use the uncaughtexception event

Can a click handler be an object?

I'm trying to register on +1 clicks from within my module, which is wrapped as an annonymous function.
For this end, I created a global object MyModule, and exported my click handler function through it. The problem is - my click handler doesn't get called.
Live demo. Code:
// Initialize +1 button
gapi.plusone.go();
(function(){
window.MyModule = {};
function plusOneClicked() {
alert("+1!");
}
window.MyModule.plusOneClicked = plusOneClicked;
})()
...
<g:plusone callback='window.MyModule.plusOneClicked'></g:plusone>
When I give as a callback an external function, whose only purpose is to forward the calls to window.MyModule.plusOneClicked, it works:
function foo() {
window.MyModule.plusOneClicked();
}
...
<g:plusone callback='foo'></g:plusone>
Why would the click handler miss window.MyModule.plusOneClicked(), but find foo()?
Google is probably writing
window[callback]();
in their code.
This requires that the callback string refer to a property of window, not a property of another object.
I believe because callback expects a direct handler method (as in foo()) rather than a reference (as in window.MyModule.plusOneClicked). So basically, you cannot simply assign such a reference to click handler, but write a (wrapper) method as the handler and have it perform the necessary invocation.

Javascript scope help

I am relatively new to javascript so please be patient if what i am asking is completely stupid!
I am trying to make a simple module. Inside the module i want to have a config object that holds settings for the module. I am also using jquery. The jquery selectors work only when in a function directly in the main object/module.
I understand that javascript has functional scope so I am suprised that I cannot use the jquery selectors anywhere inside the module.
EDIT:
I want to be able to directly set all of my configs inside the configs object using jquery selectors. This way i keep all the messy stuff inside one place and can then access configs.whatever throughout the rest of the module. At the moment jquery selectors do not work inside the configs module.
var OB = function() {
var configs = {
'mode' : 'test',
'numOfSelects' : $('.mySelect').find('select').length, // This doesnt work
}
var getMode = function() {
return configs.mode;
}
function init() {
alert(configs.numOfSelects); // This alerts 0 until the following line
alert($('.mySelect').find('select').length); // This correctly alerts 2
};
var handlers = {
successHandler : function() {
alert("Success");
},
errorHandler : function() {
alert("error");
}
}
return {
init : init,
getMode : getMode
}
}( );
$(document).ready(function(){
OB.init();
});
It isn't that jQuery isn't in scope — that's that the code isn't executing when you think it is. The variable config is defined when that anonymous function (var OB = function() {}()) is executed. The DOM isn't ready yet, so that DOM traversal doesn't find anything. When you do the DOM traversal in init(), that isn't executed until it's explicitly called inside the $(document).ready() handler, at which point that DOM is set up. That's the difference you're seeing.
OB() needs to be called after the DOM has completely loaded. Hence the answer by Marcelo, which calls OB() in the ready() method.
EDIT: It's funny that my original answer below was incorrect because I didn't notice two little parentheses at the end of the definition of OB, and it turns out that these are the culprit. You define and then immediately invoke OB, which is before the DOM has been fully loaded. Remove those parentheses and make the change I suggest below.
Calling OB() returns an object with init and getMode, but you haven't called OB(), you've only referred to OB. Try this instead:
$(document).ready(function(){
OB().init();
});
Also, I assume you want to later refer to getMode. In particular, you will to get the copy of getMode that has access to the same local scope that your init() call had access to. To achieve this, you will need to store the result of calling OB() for later use:
var ob;
$(document).ready(function(){
ob = OB();
ob.init();
});
function some_other_function() {
... ob.getMode() ...;
}

Categories

Resources