I'm sure there's a simple answer to this, but it's Friday afternoon and I'm tired. :(
Not sure how to explain it, so I'll just go ahead and post example code...
Here is a simple object:
var Bob =
{ Stuff : ''
, init : function()
{
this.Stuff = arguments[0]
}
, doSomething : function()
{
console.log( this.Stuff );
}
}
And here it is being used:
$j = jQuery.noConflict();
$j(document).ready( init );
function init()
{
Bob.init('hello');
Bob.doSomething();
$j('#MyButton').click( Bob.doSomething );
}
Everything works, except for the last line. When jQuery calls the doSomething method it is overriding 'this' and stopping it from working.
Trying to use just Stuff doesn't work either.
So how do I refer to an object's own properties in a way that allows jQuery to call it, and also allows the object to work with the calling jQuery object?
i.e. I would like to be able to do things like this:
doSomething : function()
{
console.log( <CurrentObject>.Stuff + $j(<CallerElement>).attr('id') );
}
(Where <CurrentObject> and <CallerElement> are replaced with appropriate names.)
This is not jQuery's fault, it is integral to the way JavaScript handles objects.
Unlike in most other object-oriented languages, ‘this’ is not bound on a per-method level in JavaScript; instead, it's determined purely by how the function is called:
Bob= {
toString: function() { return 'Bob!'; },
foo: function() { alert(this); }
};
Brian= {
toString: function() { return 'Brian!'; },
};
Bob.foo(); // Bob!
Bob['foo'](); // Bob!
Brian.foo= Bob.foo;
Brian.foo(); // Brian! NOT Bob
var fn= Bob.foo;
fn(); // window NOT Bob
What you are doing in the case of:
$j('#MyButton').click( Bob.doSomething );
is like the last example with fn: you are pulling the function doSomething off Bob and passing it to jQuery's event handler setter as a pure function: it no longer has any connection to Bob or any other object, so JavaScript passes in the global window object instead. (This is one of JavaScript's worst design features, as you might not immediately notice that window isn't Bob, and start accessing properties on it, causing weird and confusing interactions and errors.)
To remember Bob, you generally make a function as in nickyt's answer, to keep a copy of ‘Bob’ in a closure so it can be remembered at callback time and used to call the real method. However there is now a standardised way of doing that in ECMAScript Fifth Edition:
$j('#MyButton').click( Bob.doSomething.bind(Bob) );
(You can also put extra arguments in the bind call to call doSomething back with them, which is handy.)
For browsers that don't yet support Fifth Edition's bind() method natively (which, at this point, is most of them), you can hack in your own implementation of bind (the Prototype library also does this), something like:
if (!Object.bind) {
Function.prototype.bind= function(owner) {
var that= this;
var args= Array.prototype.slice.call(arguments, 1);
return function() {
return that.apply(owner,
args.length===0? arguments : arguments.length===0? args :
args.concat(Array.prototype.slice.call(arguments, 0))
);
};
};
}
Change
$('#MyButton').click( Bob.doSomething );
to
$('#MyButton').click( function() { Bob.doSomething() } );
You could also add to your Bob object a private field var that = this and use that everywhere in members instead of this if you really want to avoid the anonymous function.
e.g.
var Bob = new function() {
// Private Fields
var that = this;
// Public Members
this.Stuff = '';
this.init = function() {
that.Stuff = arguments[0];
}
this.doSomething = function() {
console.log( that.Stuff );
}
}
The identity of this is a common problem in javascript. It would also break if you tried to create a shortcut to doSomething:
var do = Bob.doSomething;
do(); // this is no longer pointing to Bob!
It's good practice to not rely on the identity of this. You can do that in a variety of ways, but the easiest is to explicitly reference Bob instead of this inside of doSomething. Another is to use a constructor function (but then you lose the cool object-literal syntax):
var createBob = function() {
var that = {};
that.Stuff = '';
that.init = function() {
that.Stuff = arguments[0];
};
that.doSomething = function() {
console.log( that.Stuff );
};
return that;
}
var bob = createBob();
You could always try doing something like this:
$j('#MyButton').click(function(event) {
Bob.doSomething(event, this);
});
Now doSomething will still have Bob for its this, and using the function arguments, it will have the event object, and the element it was triggered on.
Related
I'm designing an OOP inheritance pattern for many applications I'm building. Javascript has many ways of doing this, but I stumbled on a pattern I really like. But now I'm struggling with the need for a separation of classes and instances.
I have a base object called Root. And it has a main method called inherit. To create a new object you use
var Person = Root.inherit({
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
Then to create an "instance" you would
var sally = Person.inherit({
name : "sally",
height : "5'6"
});
sally can .talk() and she can walk() and she has a .name and a .height
You can make more people the same way.
If you want a constructor you use
var Person = Root.inherit({
_construct : function() {
// do things when this object is inherited from
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
It also has the ability to have init, when the object is first defined in code (singletons use this)
var Person = Root.inherit({
_init : function() {
// called at runtime, NOT called if an object is inherited from me
},
name : "",
height : 0,
walk : function() {},
talk : function() {}
});
So as you can see, everything uses .inhert(). There are no classes and no instances really. Everything is an instance of something. The only real problem I found so far is that there is no concept of "type", but you can always just check for a method if you need to. Also you can't protect a 'class', as a 'class' can be changed during execution if the developer accidentally changed it, or meant to change it.
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
No there's no need since Javascript is a Prototypal based language, meaning that classes are not involved. You are just creating clones of the objects.
http://en.wikipedia.org/wiki/Prototype-based_programming
As far as the concept of type, the type is object.
A good read for more info about this would be Javascript Patterns by Stoyan Stefanov he has several different creational patterns that address your concerns, including examples that implement Design Patterns from the gang of four's design patterns.
http://www.amazon.com/JavaScript-Patterns-Stoyan-Stefanov/dp/0596806752
So my question is: Is there a need in javascript to have an explicitly and controlled separation of class structure and instances of the class? Are there any issues with treating every object as an instance?
Not really, if you're happy with it, it's fine.
The more normal form of JavaScript inheritance does much the same thing. You'll frequently see structures like this (severely cut down for brevity):
function Base() {
}
Base.prototype.foo = function() {
};
function Derived() {
}
Derived.prototype = new Base();
...and of course, new Base() is also how you create instances of Base. So your system is quite similar.
Again, the above is a sketch, not a full example. For one thing, usually you'd see construction and initialization separated out, so you don't literally see Derived.prototype = new Base() so much as something that creates an object with Base's prototype but without actually calling Base (which Derived would do later), but you get the idea. Granted that statement somewhat weakens the similarity with your system, but I don't think it breaks it at all.
At the end of the day, it's all about objects (instances), which are either used directly (your sally) or indirectly by providing features to other objects (Person, Root) by cloning or by setting them up as the prototype of the other object.
Javascript's inheritance is prototypical which means everything object is an instance. You actually have to do extra work to get the classical inheritance.
This is how I work in javascript
// this is class
function person(){
// data is member variable
this.name = null;
this.id = null;
//member functions
this.set_name = _set_name;
this.get_name = _get_name;
this.set_id = _set_id;
this.get_id = _get_id;
function _set_name(name){
this.name = name;
}
function _get_name(name){
return this.name;
}
function _set_id(id){
this.id = id;
}
function _get_id(id){
return this.id;
}
}
// this is instance
var yogs = new person();
yogs.set_id(13);
yogs.set_name("yogs");
hope it may help
Start with some basic object...
// javascript prototypes - callback example - javascript objects
function myDummyObject () {
that = this;
} // end function myDummyObject ()
// begin dummy object's prototype
myDummyObject.prototype = {
that : this,
// add a simple command to our dummy object and load it with a callback entry
say : function () {
var that = this;
console.log('speaking:');
that.cb.run("doSay");
}
} // end myDummyObject proto
extend with a sub prototype..
// here we addon the callback handler... universally self sufficient object
var cb = {
that : this, // come to papa ( a link to parent object [ myDummyObject ] )
jCallback : new Array(new Array()), // initialize a javascript 2d array
jCallbackID : -1, // stores the last callback id
add: function(targetFnc, newFunc) {
var that = this;
var whichID = that.jCallbackID++;
// target, addon, active
that.jCallback[that.jCallback.length] = { 'targetFunc' : targetFnc, 'newFunc' : newFunc, 'active' : true, 'id': whichID };
return whichID; // if we want to delete this later...
}, // end add
run: function(targetFnc) {
var that = this;
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['targetFunc'] == targetFnc && that.jCallback[i]['active'] == true )
that.jCallback[i]['newFunc'](); // run callback.
}, // end run
remove: function (whichID) {
var that = this;
console.log('removing:' + whichID);
for(i=0;i <= that.jCallback.length - 1;i++) // go through callback list
if( that.jCallback[i]['id'] == whichID )
that.jCallback[i]['newFunc'](); // run callback.
} // end remove
}
// add the object to the dummy object...
myDummyObject.prototype.cb = cb;
Example:
var testing = new myDummyObject();
testing.cb.add('doSay', function () { console.log('test: 213123123'); } );
// test remove...
var testid = testing.cb.add('doSay', function () { console.log('test: 12sad31'); } );
testing.cb.remove(testid);
testing.cb.add('doSay', function () { console.log('test: asdascccc'); } );
testing.cb.add('doSay', function () { console.log('test: qweqwe'); } );
testing.cb.add('doSay', function () { console.log('test: d121d21'); } );
testing.cb.add('doSay', function () { console.log('test: wwww'); } );
testing.say();
This always seemed the easiest for me to understand... Just create a new instance of the inherited class and then loop through its variables and methods and add them to the main one.
var myPerson = new Person()
var myPerson.firstName = 'john';
var myPerson.lastName = 'smith';
var myPerson.jobTitle = 'Programmer';
var Person = function(){
//Use this to inherit classes
this._extendedClass = new Person_Job();
for(var i in this._extendedClass){
this[i] = this._extendedClass[i];
}
delete this._extendedClass;
this.firstName = '';
this.lastName = '';
}
var Person_Job = function() {
this.jobTitle = '';
}
I have a Javascript object literal:
var Toolbar = {
init: function(toolbar) {
this.Bar = $(toolbar); // scope is Toolbar object literal
this.Bar.find('clearButton').click(function() {
this.trigger('clear'); // doesn't work!
this.Bar.trigger('clear'); // works!
}
}
Toolbar.init($('div.toolbar'));
Toolbar.bind('clear', function() { ... }); // doesn't work!
Toolbar.Bar.bind('clear', function() { ... }); // works!
I'd like to be able to trigger the clear event on the Toolbar object literal rather than the toolbar DOM object referenced in the literal. Is this possible, and if so, how would I do it?
This should work:
var Toolbar = {
init: function(toolbar) {
this.Bar = $(toolbar); // scope is Toolbar object literal
this.Bar.find('.clearButton').click($.proxy(function() {
$(this).trigger('clear'); // should work now
this.Bar.trigger('clear'); // still works
}, this));
}
};
Toolbar.init($('div.toolbar'));
$(Toolbar).bind('clear', function() {
console.log('Toolbar');
}); // should work now
Toolbar.Bar.bind('clear', function() {
console.log('Toolbar.Bar');
}); // still works
You need to maintain the this reference in the click function. I used $.proxy; some folks use var self = this;
Toolbar is not a jQuery object so it should be wrapped in $() to access jQuery's functions. Also wrap the this that refers to a Toolbar instance in the click function.
How about this? :
var Toolbar = {
init: function(toolbar) {
this.Bar = $(toolbar); // scope is Toolbar object literal
this.trigger =
function() { this.Bar.trigger.apply(this.Bar, arguments); };
this.bind = function() { this.Bar.bind.apply(this.Bar, arguments); };
this.Bar.find('clearButton').click(function() {
this.trigger('clear');
}
};
Toolbar.init();
Toolbar.bind('clear', function() { ... });
If you want, you can readily create a function to handle the wrapping; either of these, as you prefer:
function wrapperitize(wrapper, wrappee, method /*, more_methods...*/)
{
wrapper[method] = function() { wrappee[method].apply(wrappee, arguments); };
for(var i = 3; i < arguments.length; ++i)
wrapperitize(wrapper, wrappee, arguments[i]);
}
function wrapperitize(wrapper, wrappeeProp, method /*, more_methods...*/)
{
wrapper[method] = function()
{
wrapper[wrappeeProp][method].apply(wrapper[wrappeeProp], arguments);
};
for(var i = 3; i < arguments.length; ++i)
wrapperitize(wrapper, wrappeeProp, arguments[i]);
}
where the former would be called as wrapperitize(this, this.Bar, 'trigger', 'bind') and the latter as wrapperitize(this, 'Bar', 'trigger', 'bind') (the difference being that the former will make this into a wrapper for whatever this.Bar currently is, whereas the latter will make this into a wrapper for whatever this.Bar might ever become in the future.
(Note, by the way, the tiny bit of recursion. This is to avoid problematic variable capture, due to the way closures work in JavaScript.)
If you want to be able to call a method on the Toolbar object, you'll need to define it there. If you don't need to add very many of those methods this way, you can just define each of them in the Toolbar object itself:
var Toolbar = {
clear: function() { this.Bar.trigger('clear'); }
init: function(toolbar) {
this.Bar = $(toolbar); // scope is Toolbar object literal
this.Bar.find('clearButton').click(function() {
this.clear();
}
}
However, if you need to call very many of them this will quickly get ugly. If you really want to be able to call all of the methods available of the jquery object on the Toolbar object, you could try to loop through all of them with a for in loop and add them to the Toolbar object, but this would be tedious, annoying to read, inefficient, and potentially cause some bugs. I would just use $(toolbar) whenever you wanted to call a method on that object as it gets rid of all those disadvantages. :D
Here is a (very) simplified version of my code:
function Ctor() {
this.i = 0;
this.increment = function() { this.i++; },
this.decrement = function() { this.i--; },
this.display = function() { alert(this.i); }
};
The problem is, when the code is run, under some circumstances this now points to something else. I do more or less understand that this changes context from one function to another, but I though my increment function (and the others) would, by the magic of closures, "remember" what this is supposed to be.
I tried just eliminating this altogether, and simply referencing i in the functions. That failed also.
What should these functions look like?
You can not rely on what's in this in JavaScript. More on this topic.
I see you probably want to introduce private attributes like in OOP languages. John Resig described this issue very well.
function Field(val){
var value = val;
this.getValue = function(){
return value;
};
this.setValue = function(val){
value = val;
};
}
var field = new Field("test");
field.value
// => undefined
field.setValue("test2")
field.getValue()
// => "test2"
JavaScript works a lot differently than conventional languages like Java, C++ or PHP. But you can get used to it :)
In the instances where this changes, you can do this:
function() { obj.display(); }
Example:
var obj = new Ctor();
function foo(fn) {
fn();
}
foo(function() {
obj.display();
});
An alternative is to modify foo() to accept the context to execute the function with, like this:
function foo(fn, context) {
fn.call(context);
}
wish to extend define and/or execute new methods against an object using its private methods - exactly as if I were to define the method within the original declaration - except these new methods apply only to this object to be executed one time, not to the Klass itself.
for example:
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
var k = new Klass();
console.log( k.publicFn1() ); // prints 16
suppose I wish to create and/or execute a new method on Klass, sum2(), that will add 2 to the privateFn.
have tried the brain-dead
k.publicFn2 = function() { return privateFn()+2 }
console.log( k.publicFn2() );
and it makes perfect sense that it does not work, but what does?
as a note, since functions are very long, attempting to maintain the syntax of privateFn() rather than self.privateFn() - this might be asking too much, but one hopes.
There is no such thing as private in ECMAScript
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
}
privateFn is a local variable which publicFn1 has access to due to scoping rules (and closures).
You cannot access privateFn outside the scope of function Klass
If you want to access privateFn outside the scope of function Klass then you have to expose it through a proxy or inject it further up the scope chain.
A proxy would be something like
this._private = function() {
return privateFn;
}
Injecting further up the scope chain would be something like
var Klass = function() {
var privateFn = function() { return 15 };
this.publicFn1 = function() { return privateFn()+1; };
this.uid = Klass.uid++;
Klass.instances[this.uid] = {
privateFn: privateFn
};
}
Klass.uid = 0;
Klass.instances = [];
k.publicFn2 = function() { return Klass.instances[this.uid].privateFn()+2 }
Both are ugly.
The reason they are ugly is because you are emulating classical OO
Please use prototypical OO instead.
Shameless prototypical OO plug
Javascript is a prototype-based object-oriented language. That means if you wish to user instance-specific variables, you can do it by extending the prototype object of that object. Using it any other way is unnatural and leads to problems such as yours that require an extreme hack to overcome. Why not just use the language as it was intended?
The correct structure of your code would be more like the following:
function Klass(nr) {
this.nr = nr;
};
Klass.prototype.publicFn = function() {
alert(this.nr);
};
var inst = new Klass(13);
inst.publicFn();
There are no private functions in JS and there won't be. You can "hack" the similar effect, but at the cost of either hacking something on your own or using other libraries.
It makes little sense to try to bend the language to suit you. Instead you should learn the language as it is.
I came across this Q/A on javascript code organisation.
var DED = (function() {
var private_var;
function private_method()
{
// do stuff here
}
return {
method_1 : function()
{
// do stuff here
},
method_2 : function()
{
// do stuff here
}
};
})();
Currently I do this,
var DED = new Object;
DED = {
sidebar : {
method_1 : function (data){
//some stuff
},
method_2 : function(data){
//do more
}
},
main : {
//.......
},
globalVariables : {
//...
}
}
What is the advantage of one over the other?
Warning: newbie here.
As indicated, that method uses closures to implement private functions and data. It's an alternative to the constructor method (below). E.g.
var DED = new (function()
{
var private_var;
function private_method()
{
// do stuff here
}
this.method_1 = function()
{
// do stuff here
};
this.method_2 = function()
{
// do stuff here
};
})();
With the DED method shown in your question, there is no constructor. Rather the function returns an object created from an object literal. The functions in that object have the private variable and method closed into them.
What you return from the anonymous self-calling function (function(){})() is the interface you publish for your "module" (DED).
DED.method_1() is public. private_method/private_var are not accessible from outside but everything inside of your self-calling function has access to them.
If you like this kind of access-control this is a good way to prevent other developer from accidentally messing with the internals of your module. In a lot of cases i'd just go for a naming convention like a leading underscore to indicate internals.
Javascript is very dynamic and if someone really wants to mess with code they have no write-access to they will be able to do so. Edit: This turns out to be a wrong assuption and not the case for private data in constructors or closures. Please, see: http://www.crockford.com/javascript/private.html