I have been looking into design patterns in Javascript and found http://tcorral.github.com/Design-Patterns-in-Javascript/Template/withoutHook/index.html to be a great source.
Can anyonne explain the significance of using ParentClass.apply(this)
var CaffeineBeverage = function(){
};
var Coffee = function(){
CaffeineBeverage.apply(this);
};
Coffee.prototype = new CaffeineBeverage();
PS: I tried commenting the CaffeineBeverage.apply(this), but no effect was there. Here is a link to jsfiddle http://jsfiddle.net/pramodpv/8XqW9/
It simply applies the parent constructor to the object being constructed. Try adding some stuff to the CaffeineBeverage constructor and you'll see what I mean.
var CaffeineBeverage = function(){
this.tweakage = '123';
};
var Coffee = function(){
CaffeineBeverage.apply(this);
};
Don't do this: Coffee.prototype = new CaffeineBeverage(). Do this instead:
Coffee.prototype = Object.create(CaffeineBeverage.prototype);
For more information on that, see this article, which also provides a shim for older browsers, which don't have Object.create.
Testing it out:
var drink = new Coffee();
console.log(drink.tweakage); // 123
Instead of looking at that example, let's flesh out our own:
var Room = function()
{
this.doors = 1;
};
Much like call, apply will execute the function, but allow you to specify what this is. In the example above, I'm specifying this.doors = 1, which makes doors a member when we've created our instance of Room.
Now, if I do this:
var ComputerRoom = function()
{
Room.apply(this);
// I can now access the this.doors member:
this.doors = this.doors + 1;
};
I'm actually saying that this in the context of the Room constructor, is actually the instance of ComputerRoom, which is why I pass it into the apply command: Room.apply(this).
The reason you are calling apply in the sub-"class" constructor is to inherit all instance properties.
Here's an example:
var CaffeineBeverage = function (caffeine) {
this.caffeineContent = caffeine || "100"; // 100mg / cup is an average
};
var Espresso = function (caffeine) {
// inherit instance properties
CaffeineBeverage.apply( this, arguments );
};
// do prototype dance to inherit shared properties
var protoCarrier = function () {};
protoCarrier.prototype = CaffeineBeverage.prototype;
Espresso.prototype = new protoCarrier;
var espressoCup = new Espresso(50);
espressoCup.caffeineContent; // 50
This is why you call apply. Also, apply allows you to send the arguments (with our example of caffeine). Arguments are put in array-like object in JavaScript, and apply accepts an array to pass arguments to the function that is being invoked. This explains why to use apply over call in this case (otherwise, call is faster and should be used when your code doesn't require array of arguments).
This could help you: https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/apply
Apply calls a function with a given this value and arguments provided as an array.
In your example you will be calling the CaffeineBeverage function, but when this is referenced within that function it will be the same Object as the this which is passed to it.
Source
Related
Learning Javascript I am finding different ways for creating objects. Seems that the way forward is using Object.create()
It's pretty hard to find a solid answer on best practises for using Object.create() as even the specific Object.create() articles seem to do things slightly different.
What I want to do is create multiple objects with their own encapsulated data.
I like to use encapsulation and what seems to work for me is something like
function Foo() {
var message = "Hello";
return {
bar:bar
}
function bar(){
return message;
}
}
World = (function(){
var obj = Foo();
var tank = Object.create(obj);
return {
baz:baz
}
function baz(){
alert(tank.bar());
}
})();
Running World.baz() works as expected but I am still not sure if I am doing this right.
All answers will be appreciated, thanks.
Generally in javascript you want to create objects like so:
var obj = {};
obj.someProperty = 'someValue';
obj.someOtherProperty = 'someOtherValue';
Or, you could use object literal notation, like this:
var obj = {
someProperty: 'someValue',
someOtherProperty: 'someOtherValue'
};
The Object.create function is an interesting one. Yes, it does create an empty object, but it isn't like the objects defined above. Instantiating and object with Object.create will give the new empty object inheritance up to the parameter you give the Object.create function. For instance, if we define an object as:
var actions = {
shout: function(message){
console.log(message.toUpperCase() + '!');
}
}
And then create a new object with Object.create():
var newObject = Object.create(actions); // creates a new object: newObject = {};
newObject will not contain any of it's own properties, but it will be able to access the properties of the parent actions object. After defining those object, try this out:
newObject.hasOwnProperty('shout'); // returns false
newObject.shout('Hello!'); // logs 'HELLO!!'
This example just goes to show how inheritance works from the newly created object to it's parent. This can be extremely useful, but make sure you specifically want that behavior before creating objects with Object.create-- otherwise, better be safe and use one of the two other methods above.
Hope that helps!
Edit:
Alternatively, if you're just trying to create many separate instances of the same object, you can create a constructor and invoke it with the new keyword, like this:
var Tank = function(speed, durability){
this.speed = speed;
this.durability = durability;
this.location = 0;
this.shoot = function(){
console.log('Pew pew');
};
this.move = function(){
this.location += speed;
};
}
var myTank = new Tank(5, 15); // creates new tank with speed 5 and durability 15,
// that also has all the default properties and methods,
// like location, shoot, and move.
var yourTank = new Tank(7, 12); // instantiates a different tank that myTank, with it's
// own speed and durability properties, but also has the
// default location, shoot, and move properties/ methods
var enemyTank = new Tank(10, 25);// instantiates yet another, unique tank with it's own
// unique values for speed and durability, but again with
// the default location, shoot, and move properties/methods
Try this approach for creating javaScript objects that encapsulating data. As you can see each instance of Foo has its own properties and state.
var Foo = function() {
var Foo = function Foo(customMessage) {
this.message = customMessage || "Hello";
}
Foo.prototype.message;
Foo.prototype.bar = function(){
return this.message;
}
return Foo;
}();
var tank1 = new Foo();
var tank2 = new Foo("Goodbye");
alert(tank1.bar());
alert(tank2.bar());
I would suggest using constructors to encapsulate data. If you really need to use Object.create(), you need to create a constructor-prototype system with Object.create(). However, in any case, you're just calling .bar() from the result of Foo() in the .baz() method of World. That does not mean World should point to the result of Foo().
Object.prototype.__construct = function() {
//This is the default constructor from any new object. We change it to change the constructor of objects as we go along. We could make no __construct method on Object.prototype because it doesn't do anything, so we're not going to call it, but we're going to define it anyway since we want all objects to have a __construct method, even if they don't define a new one on top of the default.
};
//Object.prototype is our default object. We add methods to object to change the prototype of objects as we go along.
var Foo = {}; //Any object that doesn't inherit from anything must inherit from Object.prototype. We do this by just setting it to {} (or new Object()).
//If we're going to define a new constructor, we need to call it _after_ we've defined it.
Foo.__construct = function() {
var message = "Hello!";
this.bar = function() {
return message;
}
};
Foo.__construct();
Foo.bar() //returns "Hello!"
//Note that message is encapsulated and _cannot_ be accessed through Foo itself.
var World = {}; //World _does not_ point to Foo. It simply calls a method of Foo in one of its methods.
World.__construct = function() {
//Now, if the method of Foo we're going to call in the method of World is going to alter Foo, then we should make a copy of Foo using Object.create(). The method we're going to call isn't _actually_ going to alter Foo, but it's good practice to make a copy because it _could_ if we made it so.
var obj = Object.create(Foo);
//Because Foo has been constructed and obj is a copy of Foo, we don't need to construct obj. We only need to construct an object if we define a new constructor property.
this.baz = function() {
alert(obj.bar());
};
};
World.__construct();
World.baz() //alerts "Hello!"
//Note that obj is encapsulated within World. obj points to Foo, but again, World _does not_ point to Foo.
I have a commercial application that has an existing JavaScript object structure using prototype chains. I have had success extending this API by adding more methods to the prototypes of objects. However, I realize that it would be best to add a namespace in front of my methods in case the application vendor decides to name a new method the same as one of my methods in a future release.
If I have an existing object called State, I would add a method called getPop like so:
State.prototype.getPop = function(){return this.pop;};
var Washington = new State('Washington',7000000);
Washington.getPop(); //returns 7000000
What I want to do is add a namespace called 'cjl' before my custom method to avoid name collision so that I can call it like so:
Washington.cjl.getPop();
I tried:
State.prototype.cjl = {};
State.prototype.cjl.getPop = function(){return this.pop;};
The problem is this. It doesn't point to the instance but instead points to the 'cjl' object.
I tried various methods, including using .bind() but none of them seemed to work. I finally found an answer here: Is it possible to organise methods on an object's prototype into namespaces? This works using the Object.defineProperty() method. The problem is the commercial application only works in compatibility mode in IE which doesn't support the Object.defineProperty() method for non-DOM elements.
Is there another way to accomplish this? I don't want to have to call multiple functions, which is the result of some techniques, e.g.:
Washington.cjl().getPop();
You could namespace in the following way, reading your comments I see that you can't change the original constructor so you'll have to replace the original with your own and save the original in a closure.
Every state instance will have it's own cjl instance but that only has a reference to current State instance, all the cjl functions are shared as they exist only once:
[UPDATE]
Forgot to get State.prototype in myState's prototype chain.
//the original constructor
function State(name, pop){
this.name=name;this.pop=pop;
}
State.org="original constructor";
//original constructor is available through
// closure and window.State is replaced with
// your constructor having the cjl namespace
(function(State){
//cjl namespace
function cjl(stateInstance){
this.stateInstance=stateInstance;
};
//cjl functions
cjl.prototype.getPopInThousands=function(){
//do not use this, instead use this.stateInstance
return this.stateInstance.pop/1000;
}
function myState(){
//apply State constructor
State.apply(this,arguments);
//create a clj instance, all methods
// are on cjl.prototype so they're shared
this.cjl = new cjl(this);
}
//inherit from State (use polyfil for older browsers)
myState.prototype = Object.create(State.prototype);
//replace window.State with your constructor
window.State=myState;
}(State))
var s = new State("Wasington", 7000000);
console.log(s.cjl.getPopInThousands());
//non standard, name
console.log("constructor name",s.constructor.name);
console.log("constructor tostring",s.constructor.toString());
More on constructor functions and prototype can be found here: https://stackoverflow.com/a/16063711/1641941
I have to agree with friend and cookie that pre fixing the function names may be the better solution but if you want to use the same methods for an object named Country then you may think of using the previous code as you can re use the cjl object.
Instead of defining State.prototype.cjl outside of the function, try to set the cjl "namespace" inside the constructor function.
function State(){
var thisObject = this;
this.cjl = {
getPop: function(){
return thisObject.pop;
}
};
}
Then you can do Washington.cjl.getPop();.
Try:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
return this.cjlDefs[method].apply(this, Array.prototype.slice.call(arguments, 1) );
};
State.prototype.cjlDefs = {
getPop: function() {return this.pop;}
};
var Washington = new State('Washington', 80000);
console.log( Washington.cjl('getPop') );
https://jsfiddle.net/ghbjhxyh/
Or another shape if you prefer:
var State = function(name, pop) {
this.name = name;
this.pop = pop;
};
State.prototype.cjl = function(method) {
this.cjlDefs.obj = this;
return this.cjlDefs;
};
State.prototype.cjlDefs = {
assertObj: function() { /* Make sensible assertion */ },
getPop: function() { this.assertObj(); return this.obj.pop; }
};
var Washington = new State('Washington', 75000);
console.log( Washington.cjl().getPop() ); // 75000
https://jsfiddle.net/7vjrz2mn/
I found different ways that seem to work.
Mostly recommended way in textbooks and the internet:
var Person = function() {
this.age = 23;
}
Tony = new Person();
This also seems to work:
function Person() {
this.age = 23;
}
Tony = new Person();
Is there a difference? And an additional question: Usually you cannot simply leave out parentheses. Here it is possible (new Person instead of new Person()). This is because of using the new keyword, right?
A third odd way that I just tried out looks like this:
function Person() {
return {age: 2};
}
Tony = new Person();
Tony = Person(); // both ways work! It seems that you can leave out 'new' here.
Here I don't get an object with the name of my class, but my property is also accessible and it seems like it was quite similar to both above approaches.
What shall I use and what are the technical differences? Thank you!
JavaScript is a classless language. Classes don't exist, but objects may inherit properties from each other by using prototypes. This means you are not limited to implementing inheritance in a class-like manner. Personally, I like to use a BackboneJS-inspired method (code requires UnderscoreJS):
var BaseObject = function(){}; //Create a function so that we may use the new operator.
//There may be code in the constructor
BaseObject.extend = function(obj) { //Add a static function to the BaseObject to extend it
var base = this; //Save a reference for later
//Create the constructor for the sub object. We need to extend it, so we can't use the base constructor. AFAIK, this is the only way to clone the base constructor, i.e. by creating a new function that calls it
var SubObject = _.extend(function(){
base.apply(this, arguments); //Call base constructor
}, this);
SubObject.prototype= _.extend({}, this.prototype, obj); //Create new prototype that extends the super prototype, but does not overwrite it.
return SubObject; //Return the new constructor + prototype
};
This allows you to do cool class-like stuff like this:
var Car = BaseObject.extend({
speed: 0,
acceleration: 5,
accelerate: function(){
this.speed += this.acceleration;
}
});
var RaceCar = Car.extend({
acceleration: 10,
});
var car = new Car();
var raceCar = new RaceCar();
car.accelerate();
raceCar.accelerate();
if(raceCar.speed > car.speed){
console.log('raceCar won');
}else{
console.log('car won');
}
For more information on inheritance in JavaScript, I strongly recommend reading JavaScript: The Good Parts by Douglas Crockford.
Regarding your examples:
The difference between 1 and 2 is minimal. For more information see this question.
In 3, you are just returning an object literal. The new keyword only has influence on the this keyword within the function, which you are not using, and so using new has no effect. For more information, see this quesion
1 and 2 (var x = function vs function x) are very similar. 3 is a completely different thing.
The difference between 1 and 2 has nothing to do with classes and has been asked before on SO (several times). I think the most complete answer is this one:
https://stackoverflow.com/a/338053/1669279
In short, the first x points to an anonymous function and some debugging tools might have problems with that. The first one is available from the line it was defined on while the second is available in the entire scope. Read the linked answer for details.
The 3rd "solution" is not a class at all. It is simply a function that returns an object (might be called a Factory method).
It is not a good idea to return things from your constructors, especially return this. You should only return things if you want to override the normal process of creating objects (like implementing the singleton pattern for example).
As a side-note, you should always use new when you instantiate a class. Here is what happens when you try to be smart and save characters:
function X () {
return this;
}
console.log(X()); // outputs the window object
The parenthesis after calling the constructor with no parameters are optional, but it is frowned upon to avoid them because it results in slightly more confusing code.
To sum it up, i usually use pattern 1. Pattern 2 is also ok.
One problem with pattern 2 can be this one:
var x = new X(); // works
console.log(x.message); // works, I am X
x.method(); // doesn't work, method hasn't been defined yet
function X() {
this.message = 'I am X';
}
X.prototype.method = function() {
console.log(this.message);
};
this is how i do mine:
;(function (window) {
"use strict";
//-- Private Vars
var opt, obj, rm, Debug;
//-- construtor
function App(requestedMethod) {
//-- set up some vars
if(typeof requestedMethod !== 'undefined') {
rm = requestedMethod;
}
opt = {
rMethod: (typeof rm !== 'undefined') ? (rm != null) ? rm : false : false
}
//-- containe resulable objects
obj = {}
//-- call the init method
this.init();
}
/** Public Methods **/
/**
* The Init method called on every page load
*/
App.prototype.init = function () {
var om = opt.rMethod;
//-- Once all init settings are performed call the requested method if required
if(om) {(typeof App.prototype[om] == 'function') ? App.prototype[om]() : _DB('Call to Method [' + om + '] does not exsist.');}
};
/**
* testmethod
*/
App.prototype.testmethod = function () {
};
/** Private Methods **/
function PrivateMethod(){
}
/**
* A console output that should enable to remain enable js to work in IE
* just incase i forget to remove it when checking on those pesky IE browsers....
*/
function _DB(msg){
if(window.console && window.console.log){
var logDate = new Date();
window.console.log('------------------- ' + logDate + ' ----------------------------------');
window.console.log(msg);
}
};
window.App = App;
})(window);
then call it like:
<script src="ptha/to/your/app.js"></script>
<script>$(function() { new App('testmethod'); });</script>
When the code is loaded the new App() will then run once all page load data has completed
Hope this helps.To get access to it outside add the new to a var
var App = new App('testmethod);
then you can access things like
App.testmethod()...
var Person = function() {
this.age = 23;
}
Person is a variable that contains(is referenced) an anonymous function
function Person() {
this.age = 23;
}
but here you declare a function called "Person"
function Person() {
return {age: 2};
}
and so you declare a function that returns a new static object.
The best way depends on the needs, if you want to declare classes use the second, while to create the modules uses the third. For the first method look here: http://helephant.com/2008/08/23/javascript-anonymous-functions/
This is my first stab at OOP, so please bear with me:
(function(){
var Ship = function(){
this.passengers = [];
this.hasAliens = function() {
return this.passengers.some(function(passenger){
return passenger.isAlien()
});
}
};
var Passenger = function(){};
Passenger.prototype.isAlien = function(){
return this instanceof Alien;
};
Passenger.prototype.board = function(ship) {
ship.passengers.push(this)
}
var Alien = function() { Passenger.call(this); }
var Human = function() { Passenger.call(this); }
Alien.prototype = Object.create(Passenger.prototype);
Human.prototype = Object.create(Passenger.prototype);
Alien.prototype.constructor = Alien.constructor;
Human.prototype.constructor = Human.constructor;
var ship = new Ship();
var john = new Human();
var zorg = new Alien();
//simple testing
john.board(ship);
console.log("Ship does not have aliens ", ship.hasAliens()===false);
zorg.board(ship);
console.log("Ship has aliens ", ship.hasAliens()===true);
})();
This works fine. However, I'd like to know how to pass the Passenger.isAlien() method to save me that nasty nested anonymous function. I'm trying to do it like this:
var Ship = function(){
this.passengers = [];
this.hasAliens = function(){
return this.passengers.some(Passenger.isAlien);
};
};
But that gives me "undefined is not a function"
http://jsfiddle.net/WYyxY/
As I said, isAlien is a property of the prototype, i.e. an instance of the constructor function, and not the constructor function itself. Passenger.isAlien is indeed undefined (nowhere in your code is Passenger.isAlien = function....).
There is not really a more concise way to do this. Think about what a callback passed to .some is doing: It has to take an element of the array as argument and then do something with it. In your case you want to execute a method of that element.
One way to call a method and pass the object it should be called on as parameter is to use .call [MDN]. Unfortunately, as with all functions in JavaScript, you cannot just get a reference to Passenger.prototype.isAlien.call, because .call looses its context (it does not know which function it refers to). You'd have to bind it to Passenger.prototype.isAlien first
this.passengers.some(
Passenger.prototype.isAlien.call.bind(Passenger.prototype.isAlien)
);
and personally I find that not more readable.
Stick with the anonymous function, your intend is much clearer. Or if you want to, you can let another function create that function:
function callOn(funcName) {
return function(obj) {
return obj[funcName]();
};
}
this.passengers.some(callOn('isAlien'));
For doing OOP with javascript, I strongly recommend checking out prototypeJS. Your code becomes much more readable, and it also supports inheritance!
Here's a quick look at it
I was reading an article here:
http://javascriptweblog.wordpress.com/2010/03/16/five-ways-to-create-objects/
It tells about five ways of creating objects. But my question is one of his way (3) is:
myApp.Notepad = function(defaultFont) {
var that = {};
that.writeable = true;
that.font = defaultFont;
that.setFont = function(theFont) {
that.font = theFont;
}
return that;
}
myApp.notepad1 = myApp.Notepad('helvetica');
As per author, we can use it when multiple instances are needed we can use any pattern from 3 (above) to 5.
But as far as I know, we do need to use this keyword which reflects back newly created instances and refers to only that instance. However above, author uses that object instead of this and also there is no new keyword used above. How will it apply to multiple object instances ? Is it essentially same as using this?
In your example, that is a new object created by this line:
var that = {};
The function then proceeds to set the properties of this object.
On the other hand, this is used with a constructor function -- when called using new, a new object is automatically created and passed to the function as this. The same example could be written as:
myApp.Notepad = function(defaultFont) {
this.writeable = true;
this.font = defaultFont;
this.setFont = function(theFont) {
this.font = theFont;
}
}
myApp.notepad1 = new myApp.Notepad('helvetica');
One advantage of the using the object literal constructor (your code) that hasn't been pointed out yet is that when you are creating a new instance of an object, the new keyword is not necessary. Or in other words, if you simply forget to use the new keyword, your code will still run as intended as you are no longer relying on the use of the new keyword to give the scope of this to your newly created object in your constructor function; The that object is now taking care of the scope for you.
This is the approach that the YUI library (and Douglas Crockford) takes for constructors.
Consider the following simple constructor:
var Car = function(model){
this.model = model;
};
If you were to call Car('Dodge Viper'); or even var MyCar = Car('Dodge Viper');, the this in the function would actually refer to the global window object. So now the property Model above is actually a global variable, which is probably not what was intended.
var Car = function(model) {
var that = {};
that.model = model;
return that;
};
// Both work the same.
var MamsCar = new Car("Mini Cooper"); // with 'new'
var DadsCar = Car("Bugatti Veyron"); // without 'new'
alert("Mam's car is a " + MamsCar.model + " and dad's car is a " + DadsCar.model);