Scoping issue with jQuery Function Extend - javascript

I'm experimenting with having an object extended and that object containing multiple functions. I'm having trouble explaining it, so let me just show you my code. Let's start with what is working:
(function ($) {
$.fn.extend({
Hello: function() {
console.log("Well, hello back!");
console.log($(this));
}
});
})(jQuery);
In HTML:
<script>
$(document).ready(function() {
$('.target').Hello();
});
</script>
The console log of $(this) is giving me the callee element "target", as expected.
Now, let's try it this way:
(function ($) {
$.fn.extend({
Response: {
Hello: function() {
console.log("Well, hello back!");
console.log($(this));
}
}
});
})(jQuery);
In HTML:
<script>
$(document).ready(function() {
$('.target').Response.Hello();
});
</script>
This is still spitting out "Well, hello back!" in the console, but I'm no longer getting the callee when I use $(this). I'm instead getting the Hello function.
How do I get the callee? I've tried this.parent, which does not work. Please help!

As others have pointed out, you can't really do what you are asking for, but you can do something that looks almost the same.
By capturing 'this' with a closure, you can access it further down in your object structure:
$.fn.extend({
Response: function () {
var self = this;
return {
Hello: function () {
console.log(self);
}
};
}
});
$('.target').Response().Hello();

You can't really do that -- it's quite impractical.
There are special rules in JavaScript that dictate what the value of this is when a function is called. One of them is that whenever there is an expression of the form foo.bar() then bar is called and this evaluates to foo for the call.
So when you are run $('.target').Response.Hello() what happens is that this is equal to $.fn.Response, and not the jQuery object that wraps .target.
You could get the desired behavior by overriding the assignment of this by using e.g. Function.prototype.call:
var $target = $('.target');
$target.Response.Hello.call($target);
Of course this is cumbersome, but there's not much choice. The only other solution that would theoretically work I can think of involves the idea of injecting code into jQuery so that $$.Response resolves to something different for each jQuery instance $$. This is probably overkill if the aim of the question is simply to achieve a preferred syntax.

Unfortunately, there is no parent-child relationship between objects in JavaScript. The reason for this is that it is possible for the same object to have multiple parents. This can be difficult to grasp when you are dealing with nested objects (as is the case in the code example you have provided). Consider the following example:
var foo = {
bar: {
baz: 1,
biz: function() { console.log(this) }
}
}
foo.bar.biz();
=> { baz: 1, biz: [Function] }
var y = {};
y.foobar = foo.bar
y.foobar.biz();
=> { baz: 1, biz: [Function] }
In both cases, a call to biz will return only the immediately containing object. To attempt to access the parent of the bar object through the this keyword would be ambiguous because there are multiple parents that have been specified.
In your case, your best option would be to use the call function to explicitly specify the function context:
var $target = $('.target');
$.fn.Response.Hello.call($target);

Related

Binding "this" in JS object

I'm trying to "reverse-engineer" JS code of one of my favorite web game. I'm not beginner in web developing, but JS is not my strength (nor english, sorry), I'm more backend programmer.
The code is full of such "objects":
var Foo = {
prop: {...},
prop2: [...],
bar: function(val) {
this.prop.k = val;
Foo.doSomething();
},
doSomething: function() {
var my = Foo.prop;
...
return this.prop2;
},
};
...somehere on the page...
<input type="text" name="in" value="Pretty text" onclick="Foo.bar(this.value)" />
As far as I understand it, it's object Foo made from anonymous class, making it somewhat static. But I'm very confused by using this and Foo as object name. It seems to me randomly used, one or another. It's not related to properties or functions, both are used both ways. Even in the same method is used both. I think, that in this case are this and Foo the same. When I try to make such an objects and dump them in console, this and Foo returns the same.
Can anyone explain to me, where can be a difference, please? Or can it be just something lost in translation, because original code is minified?
Thanks.
var x = {
something: 'something',
log: function() {
return this.something
},
log2: function() {
return x.something
}
}
If you run the above code, you can see that the log() method and log2() method both return the same result. Which concludes that this and x refers to the same object in this scenario. Yours might be the same case if I'm not wrong.
Here are some cases when this and the name of the object are not referring the same object.
let Foo = {
prop: 'a',
log() {
console.log(
'this.prop is', this.prop, ', Foo.prop is', Foo.prop
);
}
},
Bar = {
prop: 'b',
mock: Foo.log
},
Baz = Object.create(Foo, {
prop: {
value: 'c'
}
});
Foo.log();
Bar.mock();
Baz.log();
// You can also bind the this reference when calling
Bar.mock.call(Baz);
Baz.log.apply(Bar);
In Baz case, the original Foo.prop preserves its value, since setting a property with the same name in an instance makes it an own property of that instance, the value of the property in the prototype is not overridden.
All of these scenarios help you to reuse already written code, hence reducing the code. Whether this was a goal in your favorite web game or not is not known, when reading the short examples only. With the given code, there's no difference.

Use a variable both as function and object instance

I was wondering how does JQuery use "$" both as a function to return a new instance and an instance itself.
I guess that it's not exactly the case but I mean, we can use $(element).method and for exemple $.ajax without brackets (.ajax will still be a method).
EDIT :
I think that I misspoke. I know how objects work in JavaScript and my question was not about that.
JQuery allows us to use $ without the key word new. It has a function that returns a new instance automatically. So my question was about how it can use $ both as a function to instanciate a new object and an object itself.
Let's say we have
(function() {
var jQ = function (arg){
this.own = arg;
};
jQ.prototype = {
foo : function (){
alert("Foo");
},
bar : function (){
alert("Bar");
}
};
window.jQ = window.$ = jQ;
return jQ;
}());
In this exemple, i have to go througth the key word new if I want to use my object.
So how does JQuery do to avoid us this step ?
Function is an object in javascript: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function You can check this code:
var f = function () { alert(1); };
f.func1 = function () { alert(2); };
f.func2 = function () { alert(3); };
and you can call f(), f.func1() and so on...
It's not jQuery. In JavaScript functions are objects.
In the case of $(element).method you are passing a parameter element into the jQuery function, where with the $.ajaxcall you are calling the ajax function inside of the $ jQuery object. In both cases we are talking about the same piece of code, but we are using it two different ways.
Have a look at the raw source code for jQuery and that should help to visualize this a little: https://code.jquery.com/jquery-2.1.1.js
Note: the jQuery function that is used repeatedly is aliased at the bottom of the page.
Remember that in JavaScript, functions are objects. So, using the specific functions you called out in your question, you could create them like this:
var $ = function(selector) {
...
};
$.ajax = function(url) {
...
};
EDIT: To respond to your edited/clarified question, you don't have to use prototyping to make constructor functions in javascript. Remember, all a constructor is doing is returning an object - here's the equivalent of your prototyping code, but without having to use the new operator to instantiate the object:
(function() {
var jQ = function (arg){
return {
own: arg,
foo: function (){
alert("Foo");
},
bar: function (){
alert("Bar");
}
}
};
window.jQ = window.$ = jQ;
return jQ;
}());
I believe this style is actually preferred by Douglas Crockford because forgetting to use the new keyword won't throw an error but you'll get some very unexpected behavior.
JQuery allows us to use $ without the key word new. It has a function that returns a new instance automatically.
Nothing magical here. The jQuery function simply returns an instance of another constructor (source):
// Define a local copy of jQuery
jQuery = function( selector, context ) {
// The jQuery object is actually just the init constructor 'enhanced'
// Need init if jQuery is called (just allow error to be thrown if not included)
return new jQuery.fn.init( selector, context );
},
The only magic going on in the code (not shown in the example) is that jQuery.fn.init.prototype = jQuery.prototype. But jQuery.fn.init is a different function than jQuery.
Applied to your example:
var jQ = function (arg){
return new jQ.prototype.init(arg);
};
jQ.prototype = {
init: function(arg) {
this.own = arg;
},
// ...
};
jQ.prototype.init.prototype = jQ.prototype;

JavaScript: A dictionary of functions: Can a function reference functions from its dictionary?

In the code below, when somethingUseful.thisUsefulThing is called from setTimeout, can it reference somethingUseful.thatUsefulThing?
var somethingUseful = {
thisUsefulThing: function() {
this.thatUsefulThing();
},
thatUsefulThing: function() {
console.log("I am useful!");
}
}
setTimeout(somethingUseful.thisUsefulThing, 1000);
Right now, I am getting this error:
Uncaught TypeError: Object [object global] has no method 'thatUsefulThing'
To simply answer your question, YES, thisUsefulThing CAN access thatUsefulThing
But as your code currently runs, 'this' is not actually global, it is a reference to somethingUseful to all direct descendants itself.
When I am working with literal objects, I usually reference them by name rather than with 'this', so in your case I would replace 'this.thatUsefulThing()' with somethingUseful.thatUsefulThing()
Why? Because it works globally, anyway!
EDIT:
As plalx pointed out in his comment to my answer, best practices for implementing this class (with an example class member) would use functional classes / prototypes and look something like this:
function SomethingUseful () {
this.member = 'I am a member';
}
SomethingUseful.prototype.thisUsefulThing = function () {
this.thatUsefulThing();
}
SomethingUseful.prototype.thatUsefulThing = function () {
console.log('I am useful, and ' + this.member);
}
usefulObject = new SomethingUseful();
usefulObject.thisUsefulThing(); // logs fine with access to this.member
setInterval(usefulObject.thisUsefulThing.bind(usefulObject), 1000); // has access to this.member through bind()
Just bind the this value to somethingUseful.
setTimeout(somethingUseful.thisUsefulThing.bind(somethingUseful), 1000);

How can I access what a function was called on?

I am assuming that $('thing1') or document.getElementById('thing1') will return the node or object representing <div id="thing1"></div> But how do I access that in myFunc()?
HTML:
<div id="thing1"></div>
JS:
var foo = $('#thing1').myFunc();
var myFunc = function() {
console.log(this); // I want to log $('#thing1')
}
I am trying to figure out how various api's work, take highcharts for example, they do something like this:
$('#dailyKPIChart').highcharts({
chart: {
zoomType: 'x',
spacingRight: 20
}
});
And the chart will load in $('#dailyKPIChart')
How does that work?
There is no way to (programatically) know which variable (or which function call) was used to get the object upon which a method was called.
A debugger will tell you (set a break point, and then look at the stack) but that won't be useful if you think you need to know the name in your code.
$a_jquery_object.selector will (in older versions of jQuery) hold the selector used to construct a jQuery object, which might help for your particular example.
And the chart will load in $('#dailyKPIChart')
How does that work?
It doesn't need to know about $() or '#dailyKPIChart', it only needs the object that you get when calling it, which is available through this, which your earlier example code already uses.
There are several ways to invoke a function in javascript and perhaps you are after call (or its cousin apply):
Supposing you define your funciton as:
var myFunc = function() {
console.log(this); // I want to log $('#thing1')
}
You can call it while at the same time you specify the context. For example, you can do this:
var foo = $('#thing1');
var myFunc = function() {
console.log(this);
}
myFunc.apply(foo);
Or via call:
var foo = $('#thing1');
var myFunc = function() {
console.log(this);
}
myFunc.call(foo);
If you have arguments to pass, you can do so by specifying an argument list or an array of arguments. For example:
var foo = $('#thing1');
var myFunc = function(one, two) {
console.log(one);
console.log(two);
console.log(this);
}
myFunc.apply(foo,[2,3]);
Or with call:
myFunc.apply(foo,2,3); //foo is the calling context
Fiddle

Using tricks to enforce private inheritance in javascript

So I came up with something sort of hackish to check and see if a function is called from within the object itself. Can someone give me some good reasons not to do something like this?
function Poo(){
this.myFunc=function(){
for(x in this)
{
if (this.myFunc.caller==this[x]) {
alert(this.myFunc.caller==this[x]);
return;}
}
alert(false);
}
this.myFunc2=function(){this.myFunc();}
}
var mine=new Poo();
mine.myFunc(); //calling directly not allowed prints false
mine.myFunc2(); //called from a member function allowed prints true
You can do whatever you want, however, I can show you a case where you method doesn't work:
function Poo(){
this.myFunc = function () {
for(x in this) {
if (this.myFunc.caller == this[x]) {
console.info('internal call, accepted');
return;
}
}
console.error('no external calls allowed');
};
this.myFunc3 = function () {
var self = this;
// this is a standard way of
// passing functions to callbacks
// (eg, ajax callbacks)
this.myFunc4(function() {
self.myFunc();
});
}
this.myFunc4 = function (callback) {
// do stuff...
callback();
};
}
var mine = new Poo();
mine.myFunc3();
myFunc3 is within the object, so I assume you would expect the call to myFunc in the callback it gives to myFunc4 (also in the object) to work. However, caller doesn't do well with anonymous functions.
Also, iterating through the entire instance methods and attributes while comparing functions is definitely not the "Object Oriented" way of doing it. Since you're trying to emulate private methods, I'm assuming that OO is what you're looking for.
Your method is not taking any advantage of the features JS offers, you're just (re)building existing functionality in an inelegant way. While it may be interesting for learning purposes, I wouldn't recommend using that mindset for shipping production code.
There's another question on stackover that has an answer that you may be interested in:
Why was the arguments.callee.caller property deprecated in JavaScript?
edit: small change on how I call myFunc from the callback, in the anonymous function this was not the instance.
I cant't give you a good reason not to do this, but a lot easier solution.
function Poo() {
var myFunc = function() {
alert('myfunc');
};
this.myFunc2 = function() {
myFunc();
}
}
var mine = new Poo();
var mine.myFunc(); // Won't work
var mine.myFunc2(); // Will work
Why not use something like the module pattern to hide the implementation of your "private" methods.
var poo = function(){
var my = {},
that = {};
my.poo = function() {
// stuff
};
that.foo = function(){
my.poo(); //works
// more stuff
};
return that;
};
poo.foo(); // works
poo.poo(); // error

Categories