JavaScript function/method context check - javascript

I know how to use the methods for changing the context of a function/method call: apply, bind, call. My question is this, is there a way to check if a function/method has already had its context set?
// given
var beta;
function alpha () {
return this;
}
function isContextSet (fn) {
/* check for context binding on fn */
}
beta = alpha.bind("hello");
isContextSet(alpha); // returns false
isContextSet(beta); // returns true
I think I know the answer to this already but thought I would ask anyway, if for no other reasons than: 1. confirm my assumption, or 2. learn something. I'm sure that I am not the first to ask this question but I have had no idea on how to actually find an answer since all I get are responses to how to use: .apply(), .call(), or .bind().

No.
Actually, it's incorrect to refer to binding as "changing" the context. What it does is transform one function into another one which calls the first with a particular context.
Functions can be bound in many ways. For instance, I could bind it myself:
function bind(fn,ctxt){
return function(){
fn.apply(ctxt,arguments);
};
}
Or, I could bind it with Function.prototype.bind, or a shim that does the same thing, or underscore's _.bind. I could bind it to initial arguments in addition to the context. In each case, there's no way to tell what has happened without essentially actually executing the function.
Binding is just one of many ways to transform one function into another one. I could also transform a function to execute one second from now, or be executed twice. There is nothing magic about binding; it just creates a new function based on the old one. There is no special variable called [[bound_to]] set on the function that you might be able to examine (unless you use your own custom implementation of bind, as another answer suggests). There's no post facto way to determine how the function was transformed.
The closest I can imagine coming is checking the possibly bound function against an unbound version and see if they are equal.
function log_this(){console.log(this);}
var bound_func=log_this.bind(my_var);
console.log(log_this===bound_func); // FALSE

What could be done is something like this:
function f(context, whatever) {
if(this !== context) {
//context has been changed
}
}
var y = f.bind(thingy);
y(otherThingy, something);
You could also have a custom bind function and have a sort of a hack like this:
function bind(func, context) {
var newFunc = func.bind(context);
newFunc._this = context;
return newFunc;
}
function checkContext(func, context) {
return func._this !== context;
}

I think this is interesting question for those how love JavaScirpt and I hope this is response what you are looking for:
var isContextSet = function (fn) {
var testThis = {}; //unique object for testing what is this inside fn
return fn.call(testThis) !== testThis;
}
I try to "set" this inside fn: fn.call(testThis); and if that function returned reference to newly created object (testThis) then it is not binded. I hope you get it :)
EDIT:
This works when fn retuns this (as shown in question). Otherwise you can not define isContextSet properly.

Related

"this" in JavaScript objects vs. jQuery $(this)

I've stumbled over a problem. I have an object method foo defined as:
var obj = {
foo: function() {
$('.personName').mouseover(function() {
this.highlight($(this).attr('faceIndex'));
});
}
}
So what should happen is that whenever the mouse cursor is over an HTML object of type personName, the obj.highlight method should be called with the faceIndex value from the HTML object as an argument. However I apparently have a clash between two this's: the one of jQuery and the one of JavaScript (referencing to obj from inside obj).
What can (should) I do? Have I violated some good programming practice?
A typical pattern to work around this is to use a local variable to store the first this:
var obj = {
foo: function() {
var _this = this;
$('.personName').mouseover(function() {
_this.highlight($(this).attr('faceIndex'));
});
}
}
Using a language like TypeScript or an ES6 compiler makes it easier to use this pattern without having to write the _this by hand each time.
Short answer: do
$('.personName').mouseover(function(event) {
obj.highlight($(event.target).attr('faceIndex'));
});
Longer explanation:
Javascript doesn't really have a concept of this. At least not in the way you're used to thinking of it. Oh there's a keyword alright, and it kind of does the thing you expect a lot of the times but it doesn't work the way that you probably think.
The fact of the matter is that in javascipt, this is no different than any other parameter. Let me show you.
Most people are aware that in javascript you can invoke functions like this doSomething(param1, param2) or like this doSomething.call(null, param1, param2). If you wanted, you can write all function invocations using .call
See that null there? Anything you pass in there is what this gets set to.
doSomething.call(null, param1, param2);
doSomething.call(obj, param1, param2);
doSomething.call(window, param1, param2);
doSomething.call("foobar", param1, param2);
If you don't use .call the runtime just takes a guess at what value you want there.
So given this, consider that the only difference between this and any other parameter is that you don't get to give this a name! Your problem is that you have two function scopes and the inner one has a variable named this which hides the outer one's this.
Solution: don't use this. Most libraries in fact (jquery included), don't force you to use this and also pass in the value as a regular parameter
$('.personName').mouseover(function(event) {
obj.highlight($(event.target).attr('faceIndex'));
});
ambiguity solved!
Avoid using this in JavaScript, if at all possible. It is almost never necessary.
this in javascript is a very difficult thing to understand in callbacks because it may refer to virtually any instance. And that is because the callback is called from a different context.
The long story : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this
As an alternative to previous answers :
One way I prefer dealing with it is by using a bind, also known as a proxy (in JQuery). jQuery has one implemented here : jQuery.proxy.
It has the benefit of letting you chose who is your this in the callback function.
For example:
var obj = {
foo: function() {
$('.personName').mouseover($.proxy(function(event) {
// this refers here to obj instance
console.log(this);
// event is a jQuery decorated that holds the reference of your element
console.log(event);
}, this));
}
};
And the true benefit of it, is that it lets you construct components that don't have "ugly" nested callback anonymous functions:
var obj = {
foo: function() {
$('.personName').mouseover($.proxy(this.mouseOverCallback, this));
},
mouseOverCallback : function(event) {
// this refers here to obj instance
console.log(this);
// event is a jQuery decorated that holds the reference of your element
console.log(event);
}
};

Call another object's method in another object

How does one call another object's method in the current method?
Example:
function OjbectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
// How to call Object A's doWork() method
}
Current attempt:
// Call doWork
ObjectA.doWork();
Error: "Type Error: doWork() function is not defined.
Question:
What is the correct way to call the method of another object WITHIN the method. What about scoping?
Does ObjectA have to instantiated to call it's methods?
What about the apply() or call() method? I am confused how they apply in this situation.
Final remarks
I want to thank everyone's input in advance. I have only recently made the dive into javascript's OOP. This seemingly simple question is something that I have been struggling all day and I came on here as a final resort.
What is the correct way to call the method of another object WITHIN the method. What about scoping?
There is no one "correct" way. Presumably you want to be able to call a method of ObjectA instances (i.e. a method of ObjectA.prototype) but have an instance of ObjectB as this, so:
ObjectB.prototype.method = function() {
// How to call Object A's doWork() method
ObjectA.prototype.doWork.call(this);
}
That will call the method and set the instance of ObjectB as this.
Does ObjectA have to instantiated to call it's methods?
If you mean "does and instance of ObjectA have to instantiated to call its methods" then no, as shown above. You can call the method on the constructor's prototype directly.
What about the apply() or call() method? I am confused how they apply in this situation.
See the answer to the first question. Whether to use call or apply depends on the arguments that need to be passed and whether you intend do to any processing on them first.
Additional answers
Could you explain the mechanics of ObjectA.prototype.doWork.call(this) a little more?
It calls the method and sets its this to the supplied object. The rules for how a value is assigned to this are explained in EMCA–2626 §10.4.3.
Would ObjectA.prototype.doWork(this) work just the same way?
No. That calls the function, sets its this to ObjectA.prototype and supplies the value of this from the calling execution context as the first parameter. e.g. if it's global code in a browser, effectively:
ObjectA.prototype.doWork(window);
There is a typo, not ObjectA.doWork(); use objectA.doWork();
There really seems to be some confusion with JavaScript's general OOP model.
Every function has an underlying prototype, which is just an object. You may or may not add anything to it, but if you do, you probably plan to use that function as a constructor. That's what you see happening here:
function ObjectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
objectA.doWork();
However, in some instances, it might be more appealing to just create a function with some methods directly attached to it, rather than creating instances of it. Generally, these would be static methods as in other languages, or perhaps your function is really just a singleton object. In this case, you would omit the prototype, and just attach directly, like so:
function ObjectA() {}
ObjectA.doWork = function () {
alert('do work');
}
ObjectA.doWork()
Going back to the first example, if you define your function and add methods to its prototype, occasionally you may wish to actually call a function that you have defined in a different function's prototype. call and apply can be used to call any function with the value of this changing to the object which you pass into apply or call.
Remember that you are attaching methods to the prototype, so it may look a little funky, but here's an example:
function ObjectA() {}
ObjectA.prototype.doWork = function () {
console.log(this)
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
ObjectA.prototype.doWork.call(this);
}
var objectB = new ObjectB();
objectB.method()
// -> objectB will be logged to your console, bc
// it became the value of this in ObjectA's doWork method.
It's possible to call it from the prototype directly.
Using apply changes the value of this in the execution of the function to the supplied value, so its essentially forwarding this to be itself in the call.
You could also use call, the difference is just in how it takes its arguments, apply takes an array whereas call takes an argument list.
ObjectB.prototype.method = function() {
ObjectA.prototype.doWork.apply(this);
}
However of course an ObjectB does not necessarily have same properties as an ObjectA so make sure you write the method as generic as possible. In order words use a documented concept rather than internal implementation details.
Example again lies with how Array, it's generically applicable methods are documented as such and states what is required for it to work.
In the case you just want to expose a 'utility function', just put it on the object itself. e.g
ObjectA.doWork = function(obj) {
};
After all I found your typo:
function OjbectA() {}
Should be function ObjectA() {}
That's why you were facing error.
function ObjectA() {}
ObjectA.prototype.doWork = function () {
alert('do work');
}
var objectA = new ObjectA();
function ObjectB() {}
ObjectB.prototype.method = function() {
objectA.doWork()
}

"this" reference inside of object function

I have the following JavaScript code:
function PatternField(id, name, pattern) {
...
this.check = function () {
var field = this.elem.val();
...
};
this.elem.keyup(this.check);
this.elem.change(this.check);
}
When the execution comes to check function var field = this.elem.val(); it turns out that this points to elem rather than actual object.
How can I access real this from inside this object function?
this.check = function() {
var field = this.elem.val();
...
}.bind(this);
The important part being bind(this) which controls the scope of the function once it is invoked/called (note that the function is not invoked immediately when using bind, you are manipulating the definition, if you will...); in this case, retaining the scope of PatternField. Check the docs regarding bind at MDN.
In other words (in regards to some comment that magically deleted itself):
It makes sure that the scope of this.check (when called) will be whatever is passed to the first parameter of bind, overriding whatever might naturally occur. If the you want this to reference PatternField within the this.check method, the bind method of Function will enable this capability.
Like #zamnuts answered, you can use the ES5 bind method.
But if you want to do it the old way, i.e., supporting old browsers without a polyfill, you can use:
var that = this;
this.check = function () {
var field = that.elem.val();
...
};

JavaScript Proxy Pattern Explained

I study JavaScript Proxy Pattern, but I still do not get, where I can benefit from it. I would therefore like to provide you with two examples and kindly ask you to point at the difference between them.
Please, take a look at the code below:
What is the difference between the two addEventListener calls? One of them calls handleDrop in regular way. The other uses Proxy Pattern.
What will I gain using Proxy pattern approach?
I tested both functions, and they both call handleDrop successfully.
DndUpload.prototype.buildDropZone = function ()
{
var self = this,
this.dropZone.addEventListener('drop', function (e) { self.handleDrop.call(self, e) }, false);
this.dropZone.addEventListener('drop', self.handleDrop, false);
DndUpload.prototype.handleDrop = function (e)
{
alert("test");
...
};
}
You can provide me with good reference which contains very clear explanation of Proxy Pattern in JavaScript.
So what you're describing in your example isn't so much a demonstration of the Proxy pattern as much as a demonstration of confusion regarding the "calling object" and how it works in JavaScript.
In JavaScript, functions are "first-class." This essentially means that functions are data just like any other data. So let's consider the following situation:
var fn = (function () { return this.x; }),
a = {
x : 1,
fn : fn,
},
x = 2,
nothing = (function (z) { return z; });
So, we have an object a, which has two properties: fn and x. We also have variables x, fn (which is a function returning this.x), and nothing (which returns whatever it gets passed).
If we evaluate a.x, we get 1. If we evaluate x, we get 2. Pretty simple, eh? Now, if we evaluate nothing(a.x), then we get 1. That's also very simple. But it's important to realize that the value 1 associated with the property a.x is not in any way connected to the object a. It exists independently and can be passed around simply as a value.
In JavaScript, functions work the same way. Functions that are properties (often called "methods") can be passed as simple references. However, in doing so, they can become disconnected from their object. This becomes important when you use the this keyword inside a function.
The this keyword references the "calling object." That's the object that is associated with a function when that function is evaluated. There are three basic ways to set the calling object for a function:
If the function is called using the dot operator (e.g. a.fn()), the relevant object (in the example, a) is set as the calling object.
If the function is called using the function's call or apply properties, then you can explicitly set the calling object (we'll see why this is useful in a second).
If no calling object is set through method 1 or method 2, the global object is used (in a browser, this is typically called window).
So, back to our code. If we call a.fn(), it will evaluate as 1. That's expected because the this keyword in the function will be set to a due to the use of the dot operator. However, if we call simply fn(), it will return 2 because it is referencing the x property of the global object (meaning our global x is used).
Now, here's where things get tricky. What if you called: nothing(a.fn)()? You might be surprised that the result is 2. This is because passing a.fn into nothing() passes a reference to fn, but does not retain the calling object!
This is the same concept as what's going on in your coding example. If your function handleDrop were to use the this keyword, you would find it has a different value depending on which handler form you use. This is because in your second example, you're passing a reference to handleDrop, but as with our nothing(a.fn)() example, by the time it gets called, the calling object reference is lost.
So let's add something else to the puzzle:
var b = {
x : 3
};
You'll note that while b has an x property (and therefore satisfies the requirements for fn's use of this), it doesn't have a property referencing fn. So if we wanted to call the fn function with its this set to b, it might seem we need to add a new property to b. But instead we can use the aforementioned apply method on fn to explicitly set b as the calling object:
fn.apply(b); //is 3
This can be used to "permanently" bind a calling object to a function by creating a new function "wrapper." It's not really permanently binding, it's just creating a new function that calls the old function with the desired calling object. Such a tool is often written like so:
Function.prototype.bind = function (obj) {
var self = this;
return function() {
return self.apply(obj, arguments);
};
};
So after executing that code, we could do the following:
nothing(a.fn.bind(a))(); //is 1.
It's nothing tricky. In fact, the bind() property is built into ES5 and works pretty much like the simple code above. And our bind code is actually a really complicated way to do something that we can do more simply. Since a has fn as a property, we can use the dot operator to call it directly. We can skip all the confusing use of call and apply. We just need to make sure when the function gets called, it gets called using the dot operator. We can see how to do it above, but in practice, it's far simpler and more intuitive:
nothing(function () { return a.fn(); })(); //is 1
Once you have an understanding of how data references can be stored in closure scope, how functions are first-class objects, and how the calling object works, this all becomes very simple to understand and reasonably intuitive.
As for "proxies," those also exploit the same concepts to hook into functions. So, let's say that you wanted to count the number of times a.fn gets called. You can do that by inserting a proxy, like so (making use of some concepts from our bind code from above):
var numCalls = (function () {
var calls = 0, target = a.fn;
a.fn = (function () {
calls++;
return target.apply(a, arguments);
});
return (function () {
return calls;
});
}());
So now, whenever you call numCalls(), it will return the number of times a.fn() was called without actually modifying the functionality of a.fn! which is pretty cool. However, you must keep in mind that you did change the function referenced by a.fn, so looking way back to the beginning of our code, you'll notice that a.fn is no longer the same as fn and can't be used interchangeably anymore. But the reasons should now be pretty obvious!
I know that was basically a week of JavaScript education in a couple pages of text, but that's about as simple as it gets. Once you understand the concepts, the functionality, usefulness, and power of many JavaScript patterns become very simple to understand.
Hope that made things clearer!
UPDATE: Thanks to #pimvdb for pointing out my unnecessary use of [].slice.call(arguments, 0). I have removed it because it's, well, unnecessary.
Basically, passing self.handleDrop directly is functionally equivalent to passing the following function:
function() {
return self.handleDrop.apply(this, arguments);
}
because everything is passed through to the original function:
The this value
The arguments
The return value
With this in mind, compare your functions as follows:
function(e) { self.handleDrop.call(self, e) }
function() { return self.handleDrop.apply(this, arguments); }
The difference with your proxy way is:
It doesn't pass the return value through.
It doesn't pass all arguments through (only the first, e)
It doesn't pass the this value through, but uses a predefined one: self.
Now, the first two items don't make a difference here, because addEventListener doesn't care about the return value, and it also only passes one argument anyway.
But the third item is important: it sets a different this value in the function. By default, this is the element you bind the event to (it it set by the browser). Using the proxy way, you can set another this value.
Now, in your snippet it is not fully clear why you're setting a prototype function each time buildDropZone is called. Usually you define prototype functions only once. But when your handler handleDrop is called using the proxy way, this refers to the DndUpload instance, which is consistent with prototype functions in general.
Consider the code below:
function printThis() {
console.log(this);
}
var someObject = {
performTest : function() {
var self = this;
someOtherObject.higherOrderFunction(printThis);
someOtherObject.higherOrderFunction(function(){printThis.call(self)});
}
}
var someOtherObject = {
higherOrderFunction : function(f) {
f();
}
}
What will someOtherObject.higherOrderFunction(printThis) return?
How about someOtherObject.higherOrderFunction(function(){printThis.call(self)})
The answer to the first question depends on who and how you call someObject.performTest(). If I just call someObject.performTest() from a global context, it will probably print Window.
The second one will always print the someObject instance no matter what.
The closures or 'proxy pattern' as you call it comes in handy when you want to control exactly the execution context of a function.
Note: this in javascript does not behave like it does in other languages(in Java for example).

How to pass 'this' along with a function?

I want to delegate some function calls from one object to another:
objA.feature = objA.component.feature;
(Assuming feature is supposed to be a function both in objA and in its component)
But that clearly doesn't work, because the reference to this gets stripped from the function and ends up being a completely different object when it gets called (it actually is objA instead of objB.component).
You need to write something like this in order to get it to work:
objA.feature = function() {
objA.component.feature.apply(objA.component, arguments);
};
Is there a shorter (idiomatic) way to do that?
There's a function called "bind" on the Function prototype in newer runtimes:
var newFunc = someFunc.bind(somethingThatShouldBeThis);
will make this refer to "somethingThatShouldBeThis" when "newFunc" is called.
You can steal code from something like the Functional library to provide a "bind" function in environments that lack a native one.
edit — here's the code from Functional:
Function.prototype.bind = function(object/*, args...*/) {
var fn = this;
var args = Array.slice(arguments, 1);
return function() {
return fn.apply(object, args.concat(Array.slice(arguments, 0)));
}
}
Pretty simple, eh? It just returns a function back to you that, when invoked, will call the first argument as a function, and also pass along whatever arguments you pass in to the result (that is, to "newFunc" in the example above). The main wrinkle is that this one also saves extra arguments passed in originally, which can sometimes be handy.
Here is a great article on scope:
Binding Scope in JavaScript
However, most JavaScript frameworks (MooTools, jQuery) have built in methods for this. jQuery uses "proxy" and MooTools uses "bind", so be sure to check the documentation of whatever framework you're using.
Your best bet is to use a createDelegate-style method like some of the frameworks do. A bare-bones implementation was posted on OdeToCode a few years ago.

Categories