The way I figured, when creating a new function (that represents a class), it is considered a good practice to define additional functions with the help of the prototype. If functions are declared through this within an existing function, they get created for each instance, which we don't necessarily want.
So, my question is - if I want to have a property that is completely private and can be access only through getters and setters, is it even possible to achieve this by using the prototype?
Here's an example:
function Item() {
var title = '';
this.setTitle = function(_title) {
title = _title;
};
this.getTitle = function() {
return title;
};
}
var car = new Item();
car.setTitle('car');
console.log(car.getTitle()); //car
console.log(car.title); // undefined
/*
Alternative
*/
function _Item() {
this.title = '';
}
_Item.prototype.setTitle = function(_title){
this.title = _title;
};
_Item.prototype.getTitle = function() {
return this.title;
};
var _car = new _Item();
_car.setTitle('car 2');
console.log(_car.getTitle()); // car
console.log(_car.title); // car
as can be seen from the example above, in the case of Item, I declared getters and setters within a function - not a good practice. But in this way, I managed to keep the title property private. However, in case of _Item, I'm using the prototype approach, which is preferred, but my title property is not private at all.
So, what's the best approach at creating private properties of "classes" in JavaScript?
No, if you want a private property, which by definition is a variable local to the constructor, then obviously methods which access it must also be defined within the constructor.
Many people worry about the efficiency implications of defining a method once on a prototype, versus defining it once on every instance. This might have been a valid concern ten years ago, or today in applications that are creating thousands or millions of objects. Otherwise, realistically it's not something you need to worry about.
Related
I would like to set a design standard for class- as well as class-instance-creation. Combining lots of intel from multiple websites (e.g. from stackoverflow), there finally is a way to have a relative maximum of flexibility. My goal is exactly that in terms of having code-structures that behave similar to more defined classes of Java and the like.
Here is working codesnippet of what I have so far (including explanations):
var MyClass = function (prop1)
{
var _class = MyClass;
var _proto = _class.prototype;
// public member of constructed class-instance
this.prop1 = prop1;
// private static property as well as private member of class-instances
// (see getter below!)
var prop2 = this.prop1 * 10;
// need to use this. instead of _proto because the property prop2 of
// the class itself would be returned otherwise
this.getProp2 = function ()
{
return prop2;
}
// 1 function for all instances of the class
// reached by a fallback to the prototype
_proto.protoAlert = function ()
{
// must call this.getProp2() instead of using prop2 directly
// because it would use the private static member of the class
// itself instead the one of the class-instance
alert(this.prop1 + " " + this.getProp2());
}
};
var c1 = new MyClass(1);
c1.protoAlert();
var c2 = new MyClass(2);
c2.protoAlert();
c1.protoAlert();
This works well so far. However, there are some hurdles to take to not provoke errors and uncatched misbehavior of the script. The private property prop2 exists in both class and class-instances. It's a likely unintended double identity. Furthermore, the private property of class-instances are only properly reachable through setter- and getter-function. This is not the worst thing as it enforces a common way to access private variables. The downside is: Setters and getters have to be called with this. to actually reference to the prop2 of the class-instance then returning it. As for class inheritance - I didn't look into this topic with my current standard yet. Hopefully, it will work out as well.
Is there a more elegant solution or at least one that is less prone to possible errors?
Thank you in advance!
JavaScript does not really provide practical pattern for private properties. The pattern you're using does work only as long as you define all methods in constructor. You should keep in mind that this means every time you create the class, you create all the methods.
If you think about it, private variables are not serving any function in the program, they serve the programmer to keep in mind, that he should and what he should not be changing. As such, you can simply use some naming pattern. I've seen this a lot along other people's code:
function MyClass() {
// Private property
this._helloWord = "Hello word.";
}
// From outside, accessed as `helloWord`, without underscore
Object.defineProperty(MyClass.prototype, "helloWord", {
get: function() {console.log("helloWord getter");return this._helloWord;},
set: function(value) {console.log("helloWord setter");return this._helloWord = value;},
};
MyClass.prototype.alertProp = function() {
alert(this._helloWord);
}
// Accessing from the outside:
var instance = new MyClass();
alert(instance.helloWord); // will activate the getter function
Most people will instantly understand there is something special about _underscored variables. You can also make variable constant this way:
Object.defineProperty(MyClass.prototype, "helloWord", {
value: "Hello world",
writable: false // <----
};
Learn more about Object.defineProperty. You should also get to understand that the structure of Javascript is a little bit different than in OOP languages. If you try to push other languages' patterns on it, it will cause performance and structural problems.
Below I've got a simple little inheritance chain in JavaScript:
var Base =(function(){
function Base(config){
this.name = function(){
return config.name;
}
this.department = function(){
return config.department;
}
}
Base.prototype.calculate = function(){
return this.name().length + this.department().length;
}
return Base;
})();
var base = new Base({
name: 'me',
department: 'this one'
});
console.log(base.calculate());
//inheritance
var Concrete = (function(){
Concrete.prototype = Base.prototype;
function Concrete(config){
Base.apply(this,arguments);
this.number = function(){
return config.number;
}
}
return Concrete;
})();
var concrete = new Concrete({
name: 'concrete',
department: 'the best',
number: 3
});
console.log(concrete.number()); //3
console.log(concrete.name()); //concrete
and it works as expected. I'm curious, though about how correct it would be to place method properties on the prototype of an object. Canonically I know that instance data should go with the instance of the class and the methods the object actually uses should be on the prototype, but what about the situation where the properties themselves are methods (like name and department in Base in this example)? In the interest of keeping things immutable I'd rather not let users change the properties of one of these objects after they've been initialized. In this case does it make any sense to use the prototype instead of the constructor to add functionality to an object?
Or it is only correct to place properties in the constructor so you have access to them when you do something like Base.prototype.whatever?
what about the situation where the properties themselves are methods? In the interest of keeping things immutable I'd rather not let users change the properties of one of these objects after they've been initialized.
I wouldn't call these "properties" any more, but "accessor" or "getter" methods.
In this case does it make any sense to use the prototype instead of the constructor to add functionality to an object?
Yes, if you mean functionality like calculate. If you mean getters like name, department or number you need to place them in the constructor as they need privileged access to the config.
Canonically I know that instance data should go with the instance of the class and the methods the object actually uses should be on the prototype
It's a bit different actually:
Everything instance-specific (data, accessor methods with distinct scopes) needs to go on the instance and is usually set up in the constructor
Everything that is shared amongst all instances (typically methods, but also data in some rare cases) should go on the prototype.
Concrete.prototype = Base.prototype;
No! Use Concrete.prototype = Object.create(Base.prototype); instead.
The heading of your question is a bit misleading.
A direct answer to your heading - Yes, prototype properties are encouraged. They might not make a lot of difference wrt writing the code and the usage of the code, but internally, how JS manages things, like memory, accessing the variables inside closures etc it much better when done via prototype properties.
Now your actual question, is hiding immutable configurations using closures and private scoped variables the only way to do things ?
Right now - I think yes, as ES6 is still not supported completely by every browser yet.
But soon, the support will spread out in all release version of browsers and then you can use this nifty ES6 data type WeakMap . Just like a Map but here the keys are objects. So your Base definition can be written like:
var Base = (function() {
var properties = new WeakMap(); // You have to keep variable private
function Base(config) {
properties.set(this, config);
}
Base.prototype = {
name: function() {
return properties.get(this).name;
},
department: function() {
return properties.get(this).department;
},
calculate: function() {
return this.name().length + this.department().length;
}
};
return Base;
})();
Yes, you still need to keep the variable properties out of reach, so the outer closure. But the number of closures have decreased by 1 in this case.
Similar approach can be for ES6 Symbol but the outer closure will still be required.
What we truly need here are classes which will truly solve the issue, as explained in this very well written blog
The problem with functional inheritance is that if you want to create many instances then it will be slow because the functions have to be declared every time.
The problem with prototypal inheritance is that there is no way to truly have private variables.
Is it possible to mix these two together and get the best of both worlds? Here is my attempt using both prototypes and the singleton pattern combined:
var Animal = (function () {
var secret = "My Secret";
var _Animal = function (type) {
this.type = type;
}
_Animal.prototype = {
some_property: 123,
getSecret: function () {
return secret;
}
};
return _Animal;
}());
var cat = new Animal("cat");
cat.some_property; // 123
cat.type; // "cat"
cat.getSecret(); // "My Secret"
Is there any drawbacks of using this pattern? Security? Efficiency? Is there a similar pattern out there that already exists?
Your pattern is totally fine.
There are a few things that you'd want to keep in mind, here.
Primarily, the functions and variables which are created in the outermost closure will behave like private static methods/members in other languages (except in how they're actually called, syntactically).
If you use the prototype paradigm, creating private-static methods/members is impossible, of course.
You could further create public-static members/methods by appending them to your inner constructor, before returning it to the outer scope:
var Class = (function () {
var private_static = function () {},
public_static = function () {},
Class = function () {
var private_method = function () { private_static(); };
this.method = function () { private_method(); };
};
Class.static = public_static;
return Class;
}());
Class.static(); // calls `public_static`
var instance = new Class();
instance.method();
// calls instance's `private_method()`, which in turn calls the shared `private_static();`
Keep in mind that if you're intending to use "static" functions this way, that they have absolutely no access to the internal state of an instance, and as such, if you do use them, you'll need to pass them anything they require, and you'll have to collect the return statement (or modify object properties/array elements from inside).
Also, from inside of any instance, given the code above, public_static and Class.static(); are both totally valid ways of calling the public function, because it's not actually a static, but simply a function within a closure, which also happens to have been added as a property of another object which is also within the instance's scope-chain.
As an added bonus:
Even if malicious code DID start attacking your public static methods (Class.static) in hopes of hijacking your internals, any changes to the Class.static property would not affect the enclosed public_static function, so by calling the internal version, your instances would still be hack-safe as far as keeping people out of the private stuff...
If another module was depending on an instance, and that instance's public methods had been tampered with, and the other module just trusted everything it was given... ...well, shame on that module's creator -- but at least your stuff is secure.
Hooray for replicating the functionality of other languages, using little more than closure.
Is it possible to mix functional and prototypical inheritance together and get the best of both worlds?
Yes. And you should do it. Instead of initializing that as {}, you'd use Object.create to inherit from some proto object where all the non-priviliged methods are placed. However, inheriting from such a "class" won't be simple, and you soon end up with code that looks more like the pseudo-classical approach - even if using a factory.
My attempt using both prototypes and the singleton pattern combined. Is there a similar pattern out there that already exists?
OK, but that's something different from the above? Actually, this is known as the "Revealing Prototype Pattern", a combination of the Module Pattern and the Prototype Pattern.
Any drawbacks of using this pattern?
No, it's fine. Only for your example it is a bit unnecessary, and since your secret is kind of a static variable it doesn't make much sense to me accessing it from an instance method. Shorter:
function Animal(type) {
this.type = type;
}
Animal.prototype.some_property = 123;
Animal.getSecret = function() {
return "My Secret";
};
I want to create a simple class in Javascript with only one public function as follows:
function A(myTitle) {
var title = "";
this.getTitle = function() {
return title;
};
title = myTitle;
};
var anInstance = new A("first");
console.log("anInstance.getTitle(): '"+anInstance.getTitle()+"'");
// expecting to return "first"
This does work as expected.
Now I want to add this class as a prototype to a new class, that includes a new title variable, so that the getTitle() method returns the value of the variable instead:
var myA = new Object();
myA.title ="second";
myA.prototype = anInstance;
console.log("myA.getTitle(): '"+myA.getTitle()+"'");
// expecting to return "second"
But instead of the expected "second", it results in the following error:
TypeError: 'undefined' is not a function (evaluating 'myA.getTitle()')
What is the problem with this function access?
Update:
The key point for my question is the following: In my application I will create several thousand instances of type "A" and several more of other comparable types. Thus memory efficiency and performance do matter. So I thought it would be great to create the according methods (several more will follow, getTitle is only one example) only once and the "data objects" reference these methods. Is this possible?
If all you want is instance variables (and that's all I see you using), what's wrong with idiomatic JavaScript:
function A(title) {
this.title = title;
};
A.prototype.getTitle = function() {
return this.title;
};
var anInstance = new A("first");
var myA = new A("second");
You can implement both Self-like prototypal OO and Smalltalk-like class-based OO on top of JavaScript, but this only makes sense in case of inheritance hierarchies, where the flat model of JS (which favors composition over inheritance - it's easy to add new methods to the prototype or apply() arbitrary constructor functions, but you'll have to jump through some hoops to make inheritance work properly) is not sufficient.
As to why your code can't work: your getTitle() method returns a lexical instead of an instance variable, which takes no part in property resolution via the prototype chain and thus can't be overwritten your way; also, .prototype is a property of constructor functions which is used to initialize the internal [[Prototype]] property of newly created instances - setting .prototype on general objects has no effect whatsoever on property resolution.
Firstly JavaScript is not a class based language.
This works just as well and am unsure what you are trying to achieve with your solution:
http://jsfiddle.net/jRtD2/
I'm trying to get my head around JS inheritance using the "Pseudo-classical inheritance" style. I've done many Google searches and have read the classic articles. I'm familiar with Java's class structure and am trying to understand JS's prototypal style. I'm looking for vanilla JS since I want to understand the basics first.
I have a simple parent/child test class setup and need some help with the scoping rules.
1.) When do I define methods in the class vs outside of the class?
2.) How do I access private variables and private functions when I create methods using the prototype style?
function superClass(name){
this.name = name;
var privateValue = "I'm Private";
this.outputPrivate2 = function(){
alert(privateValue); //works fine
}
}
superClass.prototype.outputPrivate = function(){
alert(this.privateValue); //outputs undefined..
alert(superClass.prototype.privateValue) //also undefined
}
3.) How Can child objects call private functions or access private variables of the parent?
4.) When should the child object manually call the parent constructor?
subClass2.prototype = new superClass(); // Define sub-class
subClass2.prototype.constructor = subClass2;
function subClass2(name) {
this.name = name;
this.Bye = function() {
return "Bye from subClass - " + this.name;
}
this.testm = function(){
superClass.prototype.SomeParentMethod.call(this, "arg1", "arg2");
}
}
var parent = new superClass("parent");
var child = new subClass("child1");
parent.outputPrivate(); //undefined
parent.outputPrivate2(); //I'm private
child.outputPrivate(); //undefined
child.outputPrivate2(); //I'm private
I had three objects where 80% of the code was duplicated so I created a parent object and three child objects. The child objects have methods that use and manipulate private data from the parent. The only way I've gotten this to work is make all variables public which I don't like. Again, my familiarity is with Java so I might be trying too hard to make JS work like Java.
You're addressing some interesting points of object oriented JavaScript here.
1) When you define a method in the class, a new function will be created every time you call the constructor. This may lead to performance issues if you use a lot of objects. When you attach a method to the prototype object, the function is created only once.
2) But the advantage of defining functions inside the constructor is that you can use "private" methods/properties. In Javascript, there isn't really something like a private variable. Instead, you are creating a closure which contains some variables.
If you need to use these variables anyway outside the constructor, you need to make them public.
3) Same problem.
4) Although your question is not totally clear, I would do something like this:
function parent(){
this.a = 1;
}
function child(){
parent.call(this);
this.b = 2;
}
obj = new child();
// now obj.a == 1, obj.b == 2