I am new to prototype, and I just made a simple example that won't work. From the code below its obvious what I want - a counter. But for some reason the output is always 5, I guess that the bind is making a deep copy of the this object, which is then bound to the function. There is an obvious solution where I make everything public, but I would like to know if there is a more elegant solution. (Or you may correct my and tell me that there is no deep copy, but some other bug). The documentation didn't help me.
The code:
<!DOCTYPE html>
<html>
<body>
<input type="button" value="click" onclick="javascript: doTest();" />
<div id="canvas"></div>
<script>
var ClassA = function (position, element) { // constructor
this.field1 = position;
this.target = element;
};
ClassA.prototype = function () {
// private functions
var _aPrivateMethod = function(){
console.log(this);
this.field1 += 1;
return this.field1;
};
var _aPublicMethod = function(){
this.target.innerHTML = _aPrivateMethod.bind(this)();
};
return { // interface
constructor: ClassA,
aPublicMethod : _aPublicMethod
};
}();
function doTest() {
var obj = new ClassA(4, document.getElementById('canvas'));
obj.aPublicMethod();
}
</script>
</body>
</html>
Here are a number of issues. First you call doTest each time. A new object is created on each click, so there's no way to increment field1.
As I understood you want field1 to be private. In the way you initialize it, it cant be private. You can do something like:
function Person() {
var counter = 0;
this.increment = function () {
return ++counter;
}
}
In that way you can't access the counter from outside the function scope.
Another issue is that you don't call the private method with the right context. You should use _aPrivateMethod.call(this) as pimvdb have mentioned.
Here is an example of:
function Person() {
var age = 0;
function incrementAge() {
return ++age;
}
function eatCake() {
console.log('Yey. I\'ll eat cake!');
}
this.birthday = function () {
eatCake();
return incrementAge();
}
}
var p = new Person();
p.birthday(); //'Yey. I'll eat cake!', returns 1
p.birthday(); //'Yey. I'll eat cake!', returns 2
In that way eatCake, incrementAge and age are all private because of the functional scope.
The bad thing in the example is the way I've declared the function birthday. For each instance of Person a new copy will be created.
The right way is:
Person.prototype.birthday = function () { ... }
My declaration is not like this one because I want to use a private data members. Actually not private just local for the function (age, eatCake, incrementAge).
There's no way to access them from a function which is declared in the prototype, so that's why for the example above I've choose that approach.
Related
I've been investigating multiple leveles of inheritance with "private" variable in each "class" in JavaScript, but run into this peculiar singularity:
function Ammo() {
var a = 0;
this.get_ammo = function() {
return a;
};
this.add_to_ammo = function() {
a = a+1
return a;
};
this.clean_ammo = function() {
return a=0;
}
}
function Weapon() {
var a =0;
}
function Gun() {
var a = 0;
this.fire = function(){
console.log("Bang");
}
}
Weapon.prototype = new Ammo();
Weapon.prototype.constructor = Weapon();
Gun.prototype = new Weapon();
Gun.prototype.constructor = Gun();
var a = new Ammo();
var w = new Weapon();
var g = new Gun();
a.add_to_ammo()
a.add_to_ammo()
a.add_to_ammo()
console.log(w.get_ammo())
// At this point I get 0, as expected. But after
w.add_to_ammo()
w.add_to_ammo()
w.add_to_ammo()
console.log(g.get_ammo())
// But here I get 3!
Can somebody explain why I get 3 after
console.log(g.get_ammo())
I thought that objects a, w, g are independent, so are their fields.
Also I found out that if I change
var a = 0;
to
this.a = 0;
I get expected result. fields of the object are unbound to their parents fields.
var a is defined in Ammo, but var a in the other constructors does absolutely nothing. The a that's being modified when you call the method no matter which instance is always the same a that was captured in the closure in Ammo.
You can't have private variables like you want in JavaScript, and that's ok. The most common way to do it is to make the variable public, and prefix it with an underscore, to mark it as "internal":
function Ammo() {
this._ammo = 0;
}
Then add the methods to the prototype and use this._ammo to reference that variable:
Ammo.prototype.getAmmo = function() {
return this._ammo
}
Then you can inherit with Object.create:
Weapon.prototype = Object.create(Ammo.prototype);
And in the constructor "call super":
function Weapon() {
Ammo.call(this) // gets own "_ammo"
}
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
I don't have enough rep points to comment on #elclanrs answer, so forgive me.
His answer is all correct, but the most pertinent piece of information is the last
Also, you are not setting up the constructor function properly. You should assign a function, not call it:
Weapon.prototype.constructor = Weapon;
Gun.prototype.constructor = Gun;
your variables that are declared inside the scope of the function closure ARE IN FACT PRIVATE! however, you never properly instantiated you subclass objects, so you had a frankenstein thing going on: one object, lots of body parts.
Other than that there is nothing inherently wrong with your code, it's just not the way people usually write "Classes" and I won't explain why in the context of this question.
I was just not sure how to search this out despite many tries, so forgive me if this has been answered before.
The question is simple: can I create an instance of class window.A.class() as window.B?
To clarify, I have an object literal holding all my data for a browser game:
var gameName = {
environment: function() {
this.place = "...";
// ...
// ...
},
game: function() {
this.player = function() {
// ...
}
}
// and so on...
}
Could I create a window-level gameName.environment() instance with var A = new gameName.environment()? Are there any restrictions to creating an object-bound class's instance outside the class' parent object?
It doesn't really matter in this case how/where a function is defined. Consider these two examples:
function Foo() {}
var obj = {
bar: Foo
};
and
var obj = {
bar: function () { }
};
As far as the function and the object are concerned, those two examples are equivalent. So no, there is no problem calling a function assigned to an object property with new. All you need is a reference to the function, it doesn't matter how you get that reference.
You could do
var Environment = gameName.environment;
var A = new Environment();
if you like that better, but that's totally unnecessary.
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 have this piece of code:
var Human=function(name){
this._name=name;
};
Human.prototype.Shout=function(){
alert(this._name);
};
var tom=new Human("tom");
var john=new Human("john");
alert(tom.Shout===john.Shout);
Right now ._name is not "private". I want to make ._name "private", but at the same time i do not wish to create additional functions for each instance of Human (in other words tom.Shout Must be === to john.Shout) because creating additional functions for each instance is just well.. unnecessary (ok offtopic - we can debate this on another thread)
My conclusion is that what I'm trying to achieve (having ._name be "private" and at the same time having tom.Shout===john.Shout) is impossible.
But I just want to be 200% sure before jumping into any conclusions.
(I welcome any hacks as long as the requirements are met, i.e no creating of additional functions for each instance)
If we have to create additional functions to do scoping that's fine but that number should be a fixed number and that number should not increase with each additional instance of Human.
Update
Your looking for #name which is an instance variable. Pray it's in es.next, but we don't have it yet. Maybe in two years.
If you care about a clean API then here is your solution:
function Class(foo) {
Class.priv(this).foo = foo;
}
Class.priv = (function() {
var cache = [],
uid = 1;
return function(obj) {
if (!this.__id) {
this.__id = uid;
cache[uid++] = {};
}
return cache[this.__id];
};
}());
Class.prototype.bar = function() {
console.log(Class.priv(this).foo);
}
Store all the data in a cache as a function of the constructor. No data is cluttered on the object.
Original
However there is no such thing as "private".
All you can do is create a local variable inside a function.
The constructor function
var Human = function(name) {
// local variable.
var _name = name;
}
Has a local variable that by very definition of being local is not usable outside of the constructor function.
This means that you cannot access it in external code like the prototype.
What you can do however is make it read only using ES5
var Human = function(name) {
Object.defineProperty(this, "name", { value: name });
}
If you can truly achieve what your asking, you'd make a huge breakthrough in js. I've attempted to do just that for many hours.
A different pattern would be :
var Human = function(name) {
this.name = name;
return {
Shout: this.Shout.bind(this)
};
}
Human.prototype.Shout = function() {
console.log(this.name);
}
This has the overhead of calling .bind and creating a new object for every instance though.
how about this ?
var Human = function (name) {
var _name = name;
this.getName = function () {
return _name;
}
};
Human.prototype.Shout = function () {
alert(this.getName());
};
var tom = new Human("tom");
var john = new Human("john");
tom.Shout(); // tom
john.Shout(); // john
alert(tom.Shout === john.Shout); // true
EDIT:
the former creates another function for GET property,
it is not possible without creating additional functions.
Did read the question, didn't understand, because this._name is just not private, so the question is a bit weird. This is how in my test the prototype methods are added once and available to all instances. I repeat: this._name is not private here. If you add a local variable, and want to access it via a closure in a prototype method, calling the value of the local variable will result in the same value for all instances.
Anyway, with this constructor function the this._name getter and shout methods are added to the prototype chain once and thereby available for all instances of Human.
function Human(name) {
if (!(this instanceof Human)){
return new Human(name);
}
this._name = name;
if (!Human.prototype.Name){
Human.prototype.Name = function(val){
if (val){
this._name = val;
return this;
}
return this._name;
};
Human.prototype.shout = function(){
alert(this._name);
}
}
}
If I create a constructor function BlahWidget and give it 2 public methods: publicHello and secondHello. I assign publicHello directly inside the widget using 'this' but use the prototype object to assign the secondHello method, what difference does that really make to the behaviour of the 2 methods on the widget?
var BlahWidget = function(){
this.publicHello = function(){
alert("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
alert("Second Hello");
}
My understanding was that using .prototype allows it to be called by inherited objects. But turns out that this is not the case. Both methods can be called by the inherited function objects, as shown below:
var MiniBlah = function(){
this.callSupers = function(){
this.publicHello();
this.secondHello();
}
}
MiniBlah.prototype = new BlahWidget();
MiniBlah.prototype.constructor = MiniBlah;
var x = new MiniBlah();
x.callSupers();//calls both publicHello and secondHello
The difference is that functions declared on the prototype object are shared across instances of objects created by a constructor function whereas functions declared inside of the body of a constructor function are not, they belong to the object constructed from the function.
What this means in practice is that you could create a load of objects from a constructor function with a function on the prototype doing X, then change that function on the prototype to do Y and all object instances will get the new functionality of the function.
An example
var BlahWidget = function(){
this.publicHello = function(){
console.log("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
console.log("Second Hello");
}
var blah1 = new BlahWidget();
var blah2 = new BlahWidget();
blah2.publicHello = function() {
console.log("Goodbye");
}
blah1.secondHello(); // logs SecondHello
blah2.secondHello(); // logs SecondHello
BlahWidget.prototype.secondHello = function(){
console.log("Second Goodbye");
}
blah1.secondHello(); // logs Second Goodbye
blah2.secondHello(); // logs Second Goodbye
blah1.publicHello(); // logs Hello
blah2.publicHello(); // logs Goodbye
Every single instance of "BlahWidget" will have its own distinct copy of the "publicHello" function.
Also, though this is just academic, I'm not sure I'd say that "prototype" is a keyword; it's more like a "special property name".
In JavaScript Functions are so powerful to build OOPs and modular concepts. Following concepts are implemented using Function only in JavaScript:
Method
Class
Constructor
Module
Below code shows the code which create class MyClass and it has private members:
function MyClass(a) {
var count = 3; // private member
// this check function is private function
function check() {
if (count > 0) {
count--;
return true;
}
else {
return false;
}
}
this._a = a;
this.get = function () {
if (check()) { // use of private function
return this._a;
}
else {
return "Thullu"; // after invoking get method 3 times in the object this else will be executed
}
}
}
In the above code variable, count is private as any object created from MyClass will not have this variable similarly function check() is private function as this function is not part of this in the MyClass. When we create an object of MyClass using new keyword this is returned. This concept is possible in JavaScript because of lexical scoping (functional scoping).
When we create object of this class MyClass, and call the get method more than 3 times:
I would like to write few points regarding new keyword.
When a function is called with the new operator, a new object is created with prototype members and assigned to this.
Above statement is true only if there is no explicit return value in the function. If explicit return is present in Class (function), then same return will be assigned to the object.
I would like to give here one more example with very basic functionality like in all OOP languages we have. We declare private field and then use public properties to expose the private field, in more formal and OOPs way we create Get and Set method to update private field or retrieve private member of class.
Same get and set functionality for private variables in JavaScript we can achieve as shown in below example:
// private class with get and set methods
function MyClass() {
var _privateField = 0; // It is private field as it is not part of "this"
this.GetPrivateField = function () {
return _privateField;
};
this.SetPrivateField = function (value) {
_privateField = value;
};
}