when i try to call a function inside the object using "this" from a callback function, an error occur saying that the method is undefined.
How can I solve this issue!.
var object_log = {
user: "",
pass: "",
error_message: "an error occured while connecting",
init: function(user, pass) {
this.user = user;
this.pass = pass;
},
login: function() {
remote_submit(identify, this.success, this.error);
},
error: function() {
alert(this.error_message);
},
success: function() {
alert("success");
}
};
You need to use the .call() or .apply() methods on the callback to specify the context which the method is called upon.
The callback method remote_submit does not know what this will be anymore and thus when it calls the callback methods they're executed like normal functions not on an object.
You can "Bind" your functions by wrapping them on the way out:
var self = this;
remote_submit(
identify,
function() { return self.success.apply(self, arguments); },
function() { return self.error.apply(self, arguments); }
);
This allows you to pass the context in the closure of the anonymous function and execute the callbacks with an exclusive this context.
It appears that in EMCAScript5+ you can use bind on the function to bind it for use in a callback:
remote_submit(identify, this.success.bind(), this.error.bind())
However from the MDN Documentation:
The bind function is a recent addition to ECMA-262, 5th edition; as such it may not be present in all browsers. You can partially work around this by inserting the following code at the beginning of your scripts, allowing use of much of the functionality of bind() in implementations that do not natively support it.
The shim/polyfill is here:
if (!Function.prototype.bind) {
Function.prototype.bind = function (oThis) {
if (typeof this !== "function") {
// closest thing possible to the ECMAScript 5 internal IsCallable function
throw new TypeError("Function.prototype.bind - what is trying to be bound is not callable");
}
var aArgs = Array.prototype.slice.call(arguments, 1),
fToBind = this,
fNOP = function () {},
fBound = function () {
return fToBind.apply(this instanceof fNOP && oThis
? this
: oThis,
aArgs.concat(Array.prototype.slice.call(arguments)));
};
fNOP.prototype = this.prototype;
fBound.prototype = new fNOP();
return fBound;
};
}
Update:
To answer your additional question, let's first look at the call and apply documentation and break down how they work:
Fundamentally they work the same, the only difference is how they take their arguments:
myfunc.call(target, param1, param2, param3);
Will call myfunc(param1, param2, param3) with target as this.
var args = [param1, param2, param3];
myfunc.apply(target, args);
Will call myfunc(param1, param2, param3) with target as this.
Basically the difference is that .apply() takes an array of arguments, where the call function requires you to write in the arguments in the code.
Next, if we look at the example i gave you:
function() { return self.success.apply(self, arguments); }
This returns a function that will call your callback by passing all the arguments (arguments variable) that were passed into the anonymous function, onto the apply function. So:
var a = function() { return self.success.apply(self, arguments); };
a(1,2,3,4);
This will call self.success(1,2,3,4) with self as this. If you'd like to augment the arguments with something specific for example if you wanted a(1,2,3,4) to call self.success(self.test, 1, 2, 3, 4) then you'll have to provide an augmented array to the apply function:
var a = function() {
var args = [self.test];
for(var i = 0; i < arguments.length; i++) args[] = arguments[i];
return self.success.apply(self, args);
}
When you pass the function as a callback, do it like this:
whatever( object_log.login.bind( object_log ) );
That call to the .bind method will return a function that'll make sure your "login" function will be called such that this references the "object_log" object.
There's a good shim for .bind for older browsers at the MDN documentation site.
Related
Here the code:
Function.prototype.curry = function() {
var slice = Array.prototype.slice,
args = slice.apply(arguments), // no thisArg ? arguments are the sec param [argsArray]
that = this;
return function() {
// thisArg: null
return that.apply(null, args.concat(slice.apply(arguments)));
}
}
Above is what I understand. So why does that.apply have a null param, while the slice.apply doesn't have one?
And when I changed it to args = slice.apply(null, arguments), It threw an error which said:
Uncaught TypeError: Array.prototype.slice called on null or undefined
Where am I wrong about Function.prototype.apply()?
.apply sets context and arguments for a function:
my_fn.apply({}, [1,2,3]);
function my_fn() {
console.log(this); // {}
console.log(arguments); // [1,2,3]
}
slice.apply(arguments); is a hack to convert an array like object to an actual array, actually it could also have been .call(arguments); since call works almost like .apply:
my_fn.call({}, 1,2,3); // <- no array but more arguments
function my_fn() {
console.log(this); // {}
console.log(arguments); // [1,2,3]
}
So that.apply(null, ... just doesn't set a context for the function that. While Array.prototype.slice expects to work on an array like object and will fail if it gets no context.
The slice.apply and that.apply calls in that function have different purposes.
Just a quick recap: Function#apply accepts up to two arguments: The value to use as this during the call to the original function, and any array-like object which has the arguments (if any) to pass to the function.
The slice.apply calls, such as this one:
args = slice.apply(arguments);
...are passing arguments as the first argument, so slice gets called with this referring to the arguments object and with no arguments at all. This is a fairly common idiom for converting the array-like arguments object into a true array. (In modern code with ES2015, we'd probably use args = Array.from(arguments); instead.)
The that.apply call doing something else entirely: It's calling the function object that curry was called on, passing it the arguments supplied to curry followed by the arguments supplied when the curried function was actually called. It passes null as the first argument, the value to use as this during the call, which means the original function will be called with this referring to the global object (if this is in loose mode) or null (in strict mode`).
Not to bikeshed it, but that's not a great implementation of curry if it's been quoted correctly:
(You've fixed this in the question.) It creates two implicit globals: args and that, which is a pretty bad idea. janje suggests it may be a misquoted version of Crockford's curry from The Good Parts; if so, the ; after Array.prototype.slice and after slice.apply(arguments) should be a , instead:
Function.prototype.curry = function() {
var slice = Array.prototype.slice, // <== comma here
args = slice.apply(arguments), // <== comma here
that = this;
return function() {
return that.apply(null, args.concat(slice.apply(arguments)));
}; // Crockford probably didn't leave this semicolon out
}; // Or this one
It blocks this when calling the original function; instead, it should use the same this that hte curried function was called with.
It's creating an enumerable property on Function.prototype; all the other methods on Function.prototype are non-enumerable, probably best to keep it that way.
Instead:
(function() {
var slice = Array.prototype.slice;
Object.defineProperty(Function.prototype, "curry", {
value: function() {
var originalFunction = this;
var args = slice.apply(arguments);
return function() {
return originalFunction.apply(this, args.concat(slice.apply(arguments)));
};
},
writable: true,
configurable: true
});
})();
Example:
"use strict";
// Define it
(function() {
var slice = Array.prototype.slice;
Object.defineProperty(Function.prototype, "curry", {
value: function() {
var originalFunction = this;
var args = slice.apply(arguments);
return function() {
return originalFunction.apply(this, args.concat(slice.apply(arguments)));
};
},
writable: true,
configurable: true
});
})();
// Demonstrate it
function foo() {
console.log("this.answer:", this && this.answer);
console.log("args:", arguments);
}
var obj = {answer: 42, foo: foo.curry("curried")};
obj.foo("supplied during call");
There are optimizations one could make (it's not strictly necessary to create a new array on each call to the curried function), but they don't really buy much.
I'm trying to understand the difference between curry vs bind.
The implementation of bind is :
/*1*/ Function.prototype.bind = function ()
/*2*/ {
/*3*/ var fn = this,
/*4*/ args = Array.prototype.slice.call(arguments);
/*5*/ var object = args.shift();
/*6*/ return function ()
/*7*/ {
/*8*/ return fn.apply(object,
/*9*/ args.concat(Array.prototype.slice.call(arguments)))
/*10*/ };
/*11*/ }
The implementation of curry is :
/*1*/ Function.prototype.curry = function ()
/*2*/ {
/*3*/ var fn = this,
/*4*/ args = Array.prototype.slice.call(arguments);
/*5*/ return function ()
/*6*/ {
/*7*/ return fn.apply(this,
/*8*/ args.concat(Array.prototype.slice.call(arguments)));
/*9*/ };
/*10*/ };
I already know that curry is not an internal function (unlike bind which is in IE9+). But still:
Why do I hear people keep talking about curry , While they can simply use bind operation ?
The only difference is the context which is actually found only at the bind function.
differences
Example :
Let's say I have this function :
function add(x,y,z)
{
return x+y+z;
}
I could do it with curry :
alert(add.curry(2).curry(1)(4)) //7
But I could also do it with :
alert(add.bind(undefined,2).bind(undefined,1)(4)) //7
I don't understand why this curry term function exists while it is possible to add a dummy context to the bind function.
What am I missing ?
bind forces you to attach a context to the function, while by using curry, you can delay the specification of function context until invoking the curried function, useful in many cases.
consider the following example (not the perfect one, just to illustrate the idea):
function Query(sessionKey, dataBuilder) {
this.sessionKey = sessionKey;
this.url = "http://www.example.com/search";
this.dataBuilder = dataBuilder
this.search = function (term) {
$.ajax({
type: "POST",
url: this.url,
data: this.dataBuilder(term);
})
}
}
function dataBuilder(entity, query) {
var payload = JSON.stringify({
'entity': entity,
'searchTerm': query
'session': this.sessionKey // will be always undefined if bind(undefined,...) is used
});
return payload
}
var bindEx= dataBuilder.bind(undefined, "username");
var curryEx= dataBuilder.curry("username");
var usernameQuery = new Query("id1234",bindEx); // won't work, this.sessionKey will be undefined
usernameQuery = new Query("id1234",curryEx); // will work, this.sessionKey will be id1234 in the DataBuilder
There is a difference in intention.
Currying is to reduce the number of arguments, usually to avoid calling a function a lot with the same initial arguments. For example:
var celsiusToKelvin = add.curry(273.15);
bind() is to make sure that a function is attached to an object. It also happens to offer a currying facility, so yes you can use bind() to curry(), but if you want to curry, curry() has fewer arguments and shows your intention.
I'd think it has something to do with compatibility with older browsers as bind is only available since ECMAScript 5.
See this for a list of .bind() support: http://kangax.github.io/es5-compat-table/
Also from what I've heard, most people still use curry because it looks cleaner as it doesn't need that extra undefined in the arguments.
I'm building some objects that will trigger custom events, and I'm using jQuery's bind and trigger to manage this for me, like so:
function MyObject() {
var _this = this;
this.onUpdate = function(fn) {
$(_this).bind('MyObject.update', fn);
};
this.update = function(params) {
//Do stuff...
$(_this).trigger('MyObject.update', [updatedID]);
};
}
My problem is when I come to register other callback functions with onUpdate - the functions I pass in need to include the 'event' parameter for trigger to work correctly, like so:
function myCallback(event, updatedID) {
//Do more stuff...
}
var myobject = new MyObject();
myobject.onUpdate(myCallback);
Is there a nice way I can wrap the function that I pass in to bind in the onUpdate method, so that myCallback doesn't need the 'event' parameter, as it seems a bit irrelevant for my purposes?
You could use apply [MDN]:
this.onUpdate = function(fn) {
$(_this).bind('MyObject.update', function() {
var params = [].slice.call(arguments, 1); // remove first argument
fn.apply(this, params);
});
};
OT: Instead of adding the functions to each instance, you should extend the functions prototype:
MyObject.prototype.onUpdate = function(fn) {...};
MyObject.prototype.update = function(params) {...};
This way, all the instances share these functions.
Articles that are worth to be read in this regard:
MDN - Working with Objects
MDN - Details of the object model
MDN - Inheritance revisited
Let's say I've created this plugin:
$.fn.my_namespace = function() {}
with level 1 sub functions:
$.fn.my_namespace.category_func = function() {}
and level 2 sub functions (actual application):
$.fn.my_namespace.category_func.app_func() {
alert(this);
alert(this.selector);
}
Execution:
$('div').my_namespace.category_func.app_func();
how can I now in my app_func retrieve the actual selector? In this case, 'this' seems to be the parent function (category_func) and not the jQuery object (selector).
How come? And how do I access the selector from app_func() ?
jQuerys .fn namespace is intended to hold functions which return a jQuery object / array of objects.
You can't just throw a new object in there and expect everything to work just like that.
I swear I've answered this before, but I can't seem to find it. this always refers to the object you are calling the method on. In this case you are using category_func as that object, and calling app_func().
The pattern that jQuery UI uses is one possible way to work around this issue. They allow you to call methods on a UI object by doing something like $elem.draggable('destroy');
Imagine for a moment:
$.fn.my_namespace = function(submethod, method) {
var args = [].slice.call(arguments, 1);
var func = $.fn.my_namespace[submethod];
if (func && method) {
if ($.isFunction(func[method])) {
args.shift(); // remove the method
func = func[method];
}
}
if ($.isFunction(func)) {
// using .apply() allows us to pass `this` along to our "method functions"
return func.apply(this, args);
} else {
// didn't find the method, return... or do something else...
console.log('my_namespace', this, arguments);
return this; // jQuery chaining default
}
}
$.fn.my_namespace.category_func = function() {
console.log('category_func', this, arguments);
return this;
}
$.fn.my_namespace.category_func.method_func = function() {
console.log('method_func', this, arguments);
return this;
}
$("body").my_namespace('category_func', 'method_func', 10);
//method_func jQuery(body) [10]
$("body").my_namespace('category_func', 10);
//category_func jQuery(body) [10]
$("body").my_namespace(10, 'slow');
//my_namespace jQuery(body) [10, "slow"]
I have a javascript function (class) that takes a function reference as one paremter.
function MyClass ( callBack ) {
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
}
For reasons I won't go in to here, I need to append something to the function by enclosing it in an anonymous function, but the only way I've been able to figure out how to do it is by adding a public function to MyClass that takes the callBack function as a parameter and returns the modified version.
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
Is it possible to make this work when passing the callBack function as a parameter to the class? Attempting to modify the function in this manner when passign it as a parameter seems to only affect the instance of it in within the class, but that doesn't seem like it's a valid assumption since functions are Objects in javascript, and are hence passed by reference.
Update: as crescentfresh pointed out (and I failed to explain well), I want to modify the callBack function in-place. I'd rather not call a second function if it's possible to do all of this when the class is instantiated.
Function objects don't provide methods to modify them. Therefore, what you want to do is impossible the way you want to do it. It's the same thing Jon Skeet likes to point out about Java: Objects are not really passed by reference, but instead a pointer to them is passed by value. That means that changing the value of an argument variable to a new one won't affect the original one at all.
There are only two ways to do what you want in call-by-value languages like Java and JavaScript: The first one would be to use the (function) object's methods to modify it. As I already stated, function objects don't have those. The other one is to pass the object of which the function object is a property as a second argument and set the appropriate property to a new function which wraps the old one.
Example:
var foo = {};
foo.func = function() {};
function wrapFunc(obj) {
var oldFunc = obj.func;
obj.func = function() {
// do some stuff
oldFunc.call(obj, _some_argument__);
};
}
wrapFunc(foo);
This works for global functions as well: they are properties of the window object.
As Javascript uses lexical scoping on variables the following is possible:
var modifiableCallback=function() { alert('A'); };
function ModifyCallbackClass(callback)
{
modifiableCallback=function() { callback(); alert('B'); };
}
function body_onload()
{
var myClass=new ModifyCallbackClass(modifiableCallback);
modifiableCallback();
}
This does what you want, however the function "modifiableCallback" must be referred to with the same name inside ModifyCallbackClass, otherwise the closure will not be applied. So this may limit the usefulness of this approach for you a little.
Using eval (performance may suffer a bit) it is also possible to make this approach more flexible:
var modfiableCallback1=function() { alert('A'); };
var modfiableCallback2=function() { alert('B'); };
var modfiableCallback3=function() { alert('C'); };
function ModifyCallbackClass(callbackName)
{
var temp=eval(callbackName);
var temp2=eval(callbackName);
temp= function() { temp2(); alert('Modified'); };
eval(callbackName + " = temp;");
}
function body_onload()
{
var myClass=new ModifyCallbackClass("modfiableCallback1");
modfiableCallback1();
myClass=new ModifyCallbackClass("modfiableCallback2");
modfiableCallback2();
myClass=new ModifyCallbackClass("modfiableCallback3");
modfiableCallback3();
}
I assume you are saving this callback somewhere... Any reason this won't work?
function MyClass ( callBack ) {
var myCallBack;
if (typeof callBack !== 'function')
throw "You didn't pass me a function!"
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
/* new code goes here */
}
myCallBack = callback;
}
You want to do something like:
function MyClass () {
this.modifyCallBack = function ( callBack ) {
var oldCallBack = callBack;
callBack = function () {
oldCallBack(); // call the original functionality
alert("new functionality");
}
return callBack;
}
}
/* elsewhere on the page, after the class is instantiated and the callback function defined */
var myCallBackFunction = function () {alert("original");};
var MyClassInstance = new MyClass();
myCallBackFunction = MyClassInstance.modifyCallBack( myCallBackFunction );
myCallBackFunction();