Coffeescript 'this' inside jQuery .each() - javascript

I have some coffeescript like the following:
class foo:
#bar = 'bob loblaw'
processRows: ->
$("#my-table>tr").each ->
id = $(this).attr("id")
#processRow id
processRow: (id) ->
console.log #bar + id
So my problem is: I need this to reference the .each context inside the loop to get at id, but I also would like this to reference the class instance inside foo.processRow()---which it does not currently do.
Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.
Any thoughts? Am I missing something obvious? Thanks!

jQuery.each passes the current element as second parameter of the callback, so you don't have to reserve this for jQuery:
processRows: ->
$("#my-table>tr").each (index, element) =>
id = $(element).attr("id")
#processRow id
Notice the use of the fat arrow (=>) syntax for the callback function; it binds the function's context to the current value of this. (this in the callback function is always the same this as the one at the time you defined the function.)

You say
Using something like _this = this outside the .each function and passing it around isn't a great solution, either, since I reference many class variables inside processRow.
This is the most efficient solution, though. JavaScript's this is a strange beast; you can keep it fixed inside of a nested function using the => operator, as arnaud576875 sugests in his answer (which is elegant but inefficient), or you can copy this to another variable (which is efficient but inelegant). The choice is yours.
Note that some modern browsers support a bind method on every function, which is more efficient than CoffeeScript's =>. There's an open ticket to have => use the native bind when available: https://github.com/jashkenas/coffee-script/pull/1408
Addendum: Of course, a more efficient alternative than any of the above would be to write
for element, index in $('#my-table>tr')
...
which would also solve your this problem.

Your code...
class foo
#bar = 'bob loblaw'
processRows: ->
$("#my-table>tr").each ->
id = $(this).attr("id")
#processRow id
processRow: (id) ->
console.log #bar + id
Is transpiled to...
var foo;
foo = (function() {
function foo() {}
foo.bar = 'bob loblaw';
foo.prototype.processRows = function() {
return $("#my-table>tr").each(function() {
var id;
id = $(this).attr("id");
return this.processRow(id);
});
};
foo.prototype.processRow = function(id) {
return console.log(this.bar + id);
};
return foo;
})();
Which has assumed much about about the current context that it is translating to. Unfortunately, since jQuery manages context, you'll have to be explicit or declare a reference to your class's this.
Incidentally, there are other issues with that generated code, take a look at this reduced case:
class foo
#bar = 'bob loblaw'
getBar: () ->
#bar
Transpiles to:
var foo;
foo = (function() {
function foo() {}
foo.bar = 'bob loblaw';
foo.prototype.getBar = function() {
return this.bar;
};
return foo;
})();
The results of attempting to use this piece of code:
> foo.bar;
"bob loblaw"
> var f = new foo();
undefined
> f.getBar();
undefined
Your code seems to expect that #bar is an own property, but it's being created as a static property of the foo function

Related

function argument vs this performance

In Javascript, which provides more performance:
Passing pointer to a large data structure as argument to a function
OR
Using this variable to get pointer in a class structure
Example:
Option 1:
function() {
function(Ob) {
// do something with Ob
};
}
Option 2:
function() { // Class structure
this.Ob = { foo: "bar" }; // bar is a big data structure
this.Fn = function() {
var x = this.Ob
// Use x
};
}
I find Option 1 to be more readable - but Option 1 becomes too verbose once your function needs a lot of variables.
Your two examples differ in the scope.
Your first example, the inner function have the parent function scope, and it will be not accessible outside.
Your second example have the parent object scope, but you can access outside with the object instance:
function parent() {
function child() {
// only accessible inside parent() function
}
}
var parent = function() {
this.child = function() {
alert("Yeah");
};
};
var p = new parent();
p.child(); // alerts Yeah
First of all, performance depends on browser and user PC ofc.
Both examples are almost the same.
First one can be faster, because you have direct reference on the object.
In other words, the less you use '.' the better performance you get.
So:
this.Obj // do something
is slower than:
Obj // do something
but you will not notice the difference :)
If you want to find out more, try to get this book:
http://shop.oreilly.com/product/9780596802806.do

JavaScript: that vs this

I am trying to understand better the use of that and this in JavaScript. I am following Douglas Crockford's tutorial here: http://javascript.crockford.com/private.html
but I am confused regarding a couple of things. I have given an example below, and I would like to know if I am making a correct use of them:
function ObjectC()
{
//...
}
function ObjectA(givenB)
{
ObjectC.call(this); //is the use of this correct here or do we need that?
var aa = givenB;
var that = this;
function myA ()
{
that.getA(); //is the use of that correct or do we need this?
}
this.getA = function() //is the use of this correct?
{
console.log("ObjectA");
};
}
function ObjectB()
{
var that = this;
var bb = new ObjectA(that); //is the use of that correct or do we need this?
this.getB = function()
{
return bb;
};
that.getB(); //is the use of that correct or do we need this?
}
Note this is just an example.
this in JavaScript always refers to current object, method of which was called. But sometimes you need to access this of your object in deeper. For example, in callbacks. Like so:
function MyClass() {
this.a = 10;
this.do = function() {
http.get('blablabla', function(data) {
this.a = data.new_a;
});
};
}
It will not work, because this in callback may refer to http, to some dom element or just window(which is really common). So, it is common solution to define self or that, an alias for this or your object, so you can refer it anywhere inside.
function MyClass() {
var self = this;
this.a = 10;
this.do = function() {
http.get('blablabla', function(data) {
self.a = data.new_a;
});
};
}
This should give you vision why it is used and how it should be used.
There is no other reasons(currect me if I'm wrong) to create special variable, you can use this to send your object to other objects and do things, many assignments, such logic, wow...
ObjectC.call(this); //is the use of this correct here or do we need that?
The first thing you need to understand is how the this keyword works. It's value depends on how the function/method/constructor is called.
In this case, function ObjectA is a constructor, so you can just use this inside the code of it. In fact, with var that = this; you declare them to be absolutely identical (unless you use that before assigning to it).
function myA() {
that.getA(); //is the use of that correct or do we need this?
}
Again, it depends on how the function is called - which you unfortunately have not show us. If if was a method of the instance, this would have been fine; but but it seems you will need to use that.
this.getA = function() //is the use of this correct?
As stated above, using that would not make any difference.
var bb = new ObjectA(that) //is the use of that correct or do we need this?
var that = this;
that is undefined when it is used here. And it would be supposed to have the same value as this anyway. Better use this.
that.getB(); //is the use of that correct or do we need this?
Again, both have the same effect. But since you don't need that, you should just use this.
Everything is correct except for :
function ObjectB()
{
var bb = new ObjectA(that) //this is wrong
var that = this;
this.getB = function()
{
return bb;
};
that.getB();
}
You are missing ; and that isn't declare.
You need that (in your case, this is the variable name you use) when you want to use this in another scope :
function ObjectB()
{
var that = this;
// here 'this' is good
function()
{
// Here 'this' doesn't refer to the 'this' you use in function ObjectB()
// It's not the same scope
// You'll need to use 'that' (any variable from the ObjectB function that refers to 'this')
};
// Here 'that' = 'this', so there is no difference in using one or another
}
What "that" is in this context is simply a variable that is equal to "this". That means saying "that" is exactly the same as saying "this", which makes in unnecessarily complicating.
This code:
var that=this;
that.getA();
Will yield the same result as this code:
this.getA();
Having a variable to represent "this" just complicates things when you can just say "this".

Javascript function object with this reference to itself

I can't seem to find an example of what I'm trying to achieve, although I'm sure it has been done many times before...
I want to create an object which will have a set of properties and member functions but that I can also call directly. In the same way the jQuery object allows you to call $("selector") or $.method(...)
Here's a slimmed down version of what I'm trying to achieve :
var foobar = function(param) {
return "FOO : " + this.lookup(param);
}
foobar.vals = {
1: "one",
2: "two"
};
foobar.lookup = function (param) {
return "BAR : " + this.vals[param];
}
foobar.lookup("1")
// returns "BAR : one"
foobar("1")
// returns error since 'this' points to global scope
// I'd want it to return "FOO : BAR : one"
I've also tried various approaches with function prototype but can't seem to find a method which gives me everything I want...
var foobar = function(param) {
return "FOO : " + foobar.lookup(param);
}
will return you what you want
To understand this, maybe you should take a look at the basics of JavaScript. What are functions how to instanciate an object and what are objects...
To get something like JQuery this is not very difficult, the JQuery main object is simply a function which also has "static" functions.
to declare a variable as function you do
var myFunc = function(){};
to use the variable and extend it with static stuff you simply assign it via
myFunc.staticFunc = function(){};
this doesn't mean that myFunc.staticFunc can be accessed with this in any instance of myFucn because you didn't add the function to the prototype...
To define a class like object which can be instanciated you also define it as function and then extend the prototype. Prototype is your class definition which is used to construct the object's instance:
myFunc = function(){
// ctor
this.lala = "blub";
} ;
myFunc.prototype.objectFunc = function() {
return this.lala;
}
now the object myFunc has a function objectFunc. I have to initialize it with new...
alert(new myFunc().objectFunc());
instances can access itself with this...
To do something like jquery you'll have to do some tricks. Your global variable must be a function which returns an instance of your "real" object, which can implement whatever...
Then you can call your variable as if it is a function, e.g. myFunc()...
Hope the following example makes it more clear how this works: (can be found on jsfiddle)
(function ($) {
var myRealObj = function (outId, printText) {
this.text = printText;
$("#" + outId).append("<li>" + this.text + "</li>");
};
myRealObj.prototype.objectFunc = function () {
return this.lala
};
var myFunc = function (out, txt) {
return new myRealObj(out, txt);
};
myFunc.someFunc = function () {
myFunc("out", "myFunc.someFunc got called");
};
myFunc.static = {};
myFunc.static.someFunc = function () {
myFunc("out", "myFunc.static.someFunc got called");
};
window.$$ = myFunc;
})($);
$$("out", "test obj function");
$$.someFunc();
$$.static.someFunc();
You could add:
foobar = foobar.bind(foobar);
to make the variable refer to a bound version of the function. Any call to the (updated) "foobar" would have this bound to the original function object. You'd also have to mirror the properties if you wanted to get at them directly, which is sort-of a mess.
In the jQuery implementation, there's a separate internal function that handles the basic routing of the master $() function.
Note also that the "global" $.whatever() functions don't really have much to do with the set of methods supported by jQuery instances (objects returned from the $() function). The $ object just serves as a namespace so that those global utilities don't pollute the global (window) namespace.
you declare var foobar = function(param) {... in the global scope so this will always be a window

Local Instance Reference

In javascript say I have:
var Person = (function () {
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
}
return Person;
})();
Person.prototype.getName = function () {
return this.name;
};
...if I understand the 'this' keyword correctly in javascript, it can refer to pretty much anything from the window object to itself to anything in-between (e.g. callers of the object). My question is how the heck do I write methods like .getName() so that I know I'll always have a reference to the value stored in the person object's name property if I never can be sure what 'this' will refer to in that method? Say that .getName() is called and 'this' references the window object - how the do I get the value I need then?
I'm asking because I've inherited some code using pretty heavy prototyping and I'm running into all kinds of issues trying to reference properties and methods on objects from within themselves. Seems like I'm missing something but I've been looking into scope, closures, and other patterns all day and I can't get around this.
The value of this is set by the language according to how a function/method is called.
If you have an object with a method and you do:
obj.method()
Then, this will be set to point to the object inside of the method() function.
But, if you just get that method by itself like this:
var p = obj.method;
p();
Then, because there is no object reference in the actual function call, this will be set to either window or undefined depending upon whether you are in strict mode or not.
Additionally, the caller can specify exactly what they want this to be set to using obj.method.call() or obj.method.apply() or even p.call() or p.apply() from the previous example. You can look these methods up on MDN to see more details about how they work.
So, in your previous code, this should work:
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
}
Person.prototype.getName = function () {
return this.name;
};
var p = new Person({name:"John"});
var n = p.getName(); // will return "John"
Working demo: http://jsfiddle.net/jfriend00/a7MkP/
If you needed to pass getName() to a third party library that won't call it with the object context, then there are a few options like this:
Anonymous function:
var myPerson = new Person("John");
callThirdParty(function() {
// callback that calls getName with the right object context
return myPerson.getName();
});
Using .bind() (not suported in some older browsers):
var myPerson = new Person("John");
var boundFn = myPerson.getName.bind(myPerson);
callThirdParty(boundFn);
From your own method:
var self = this;
callThirdParty(function() {
// callback that calls getName with the right object context
return self.getName();
});
FYI, there really is no reason for the self-executing function you have surrounding your Person constructor function. It just makes the code more complicated and adds no value in this case.
Yes, you are understanding the this keyword correctly.
how the heck do I write methods like .getName() so that I know I'll always have a reference to the value stored in the person object's name property
You can only do so by not using this, and in not using prototyping. Give each object a unique function that always refers to the original object:
function Person(data) {
data = $.extend({
name: "",
age: 0
}, data);
this.name = data.name;
this.age = data.age;
var that = this; // a reference variable always pointing to this instance
this.getName = function() {
// using the variable from the constructor closure
return that.name; // a quite useless getter
};
}
var john = new Person({name:"John"}),
getter = john.getName;
getter(); // "John"
I'm running into all kinds of issues trying to reference properties and methods on objects from within themselves
So with the above you can solve it by making all methods instance-specific. However, that undoes all the advantages of prototyping, and should not be used.
Instead, the one who calls a function (or a method) should be responsible to call it in the correct context:
john.getName();
If you really have to pass a function to someone which ignores that (like addEventListener), you can use magic stuff like .bind() or just apply the above pattern:
// from
addEventListener("click", john.sayHello); // will call the function in context of the DOM
// to
addEventListener("click", function() {
john.sayHello(); // correct thisValue
});

wrapping plain javascript object in jquery $({})

I have this fragment of code from a book I am reading. And want to understand what $({}) means and what is its use exactly.
I tried searching on several search engines and even on SO. $({}) wasn't a search-friendly term.
var Events = {
bind: function(){
if ( !this.o ) this.o = $({});
this.o.bind.apply(this.o, arguments);
},
trigger: function(){
if ( !this.o ) this.o = $({});
this.o.trigger.apply(this.o, arguments);
}
};
I did find a similar question about $([]) but I don't think it is quite the same thing.
You're just wrapping a basic javascript object as a jQuery one.
From jquery documentation :
Working With Plain Objects
At present, the only operations supported
on plain JavaScript objects wrapped in jQuery are:
.data(),.prop(),.bind(), .unbind(), .trigger() and .triggerHandler().
The use of .data() (or any method requiring .data()) on a plain object
will result in a new property on the object called
jQuery{randomNumber} (eg. jQuery123456789).
// define a plain object
var foo = {foo:'bar', hello:'world'};
// wrap this with jQuery
var $foo = $(foo);
// test accessing property values
var test1 = $foo.prop('foo'); // bar
// test setting property values
$foo.prop('foo', 'foobar');
var test2 = $foo.prop('foo'); // foobar
// test using .data() as summarized above
$foo.data('keyName', 'someValue'); console.log($foo); // will now contain a
// jQuery{randomNumber}
// property
// test binding an event name and triggering
$foo.bind('eventName', function (){
console.log('eventName was called');
});
$foo.trigger('eventName'); // logs 'eventName was called'
Should
.trigger('eventName') be used, it will search for an 'eventName'
property on the object and attempt to execute it after any attached
jQuery handlers are executed. It does not check whether the property
is a function or not. To avoid this behavior,
.triggerHandler('eventName') should be used instead.
$foo.triggerHandler('eventName'); // also logs 'eventName was called'
Here's a (not really useful) example :
​var a =$({});
a.data('b', 3);
console.log(a.data('b')); // this prints 3
If you keep your object created with $({}), you may use it as callee for data, bind, and so on. This is probably the minimal non DOM keepable jquery object you can make.
this really has more to do with javascript syntax than jQuery.
{} is for objects like so:
//makes an empty object
var myObject = {};
//makes an object containing 'foo' and 'bar' as 'firstItem' and 'secondItem'
var myObject = { firstItem : foo, secondItem : bar };
[] is for arrays like so:
//makes a blank array
var myArray = [];
//makes an array containing 'foo' and 'bar' at postions 0 and 1
var myArray = [foo, bar];
() is for functions (which jQuery generally is). This is abit more complicated because it can have multiple meanings.
//running an existing function
myFunction();
//running an anonymous function
(function(){
//doSomething }
)();
//running a function with an argument
myFunction(arg);
jQuery is generally just a function called $ instead of myFunction so...
//runs jQuery as a function on 'arg'
$(arg);
The argument you pass jQuery can be almost anything. If you pass it a string like '#myDiv' jQuery will use that argument as a selector to get an element from the html. If you pass it something else like an object or an array, it can still do some things with it like: http://api.jquery.com/jQuery/ as #dystroy said.
So $({}) is the same as $(myBlankObject), for example:
var myBlankObject = {};
$(myBlankObject);
//is the same as
$({});
and
var myObjectWithStuff = { firstItem : foo, secondItem : bar };
$(myObjectWithStuff);
//is the same as
$({ firstItem : foo, secondItem : bar });
$('selector') works. $({'selector'}) or $(['selector']) does not, because you are not passing jQuery a string, but another data type.

Categories