I have a Javascript "class" defined like so:
var Welcomer = function(name) {
var pName = name;
var pMessage = function() {
return "Hi, " + pName + "!";
};
return {
sayHi: function() {
alert(pMessage());
}
};
};
new Welcomer('Sue').sayHi();
Is there a way to "subclass" Welcomer in such a way that I can redefine the public methods and have access to the private methods and variables? The following will give me access to the public methods, but not to the private ones:
var UnhappyWelcomer = function(name) {
var pSadMessage = function() {
// won't work, b/c I don't have access to pMessage
return pMessage() + " Miserable day, innit?";
};
return {
sayHi: function() {
alert(pSadMessage());
}
};
};
UnhappyWelcomer.prototype = Welcomer(); // failed attempt at inheritance
new UnhappyWelcomer().sayHi();
The simple answer to your question is No.
You can't do anything to gain access to those var defined things, unless your function is in the same scope, or you somehow 'make public' the information (by returning it, or setting it on this).
If you have access to edit the original function though, you could rewrite things in such a way that those functions could be "passed" into an extending function, which can alter the "protected" scope of the object. The following code should give a good idea of what I am proposing.
var Welcomer = function(name) {
var _protected = {
name: name,
message: function() {
return "Hi, " + _protected.name + "!";
}
};
return {
extendWith: function(extender) {
extender.call(this, _protected);
return this;
},
sayHi: function() {
alert(_protected.message());
}
};
};
var UnhappyWelcomer = function(name) {
var self = Welcomer(name).extendWith(function(_protected) {
_protected.sadMessage = function() {
return _protected.message() + " Miserable day, innit?";
};
// extending the public while still having scope to _protected...
this.sayHi = function() {
alert(_protected.sadMessage());
};
});
return self;
};
UnhappyWelcomer('bob').sayHi();
That "class" pattern is not a "class" pattern, it's known as a Module Pattern. It returns an object that has no ties to the function that created it other then availability of it's private variables. The returned object is NOT an instance of the function that created it.
When you call 'new Class()' it does create an instance of that function, but it also returns another object. Any further operations is actually on the returned object and not the instance.
In order to use inheritance, you really need to use prototypical inheritance properly, I suggest you read:
Prototypical Inheritance by Douglas Crockford
Private Members in JavaScript by Douglas Crockford
Prototypes and Inheritance in JavaScript by Scott Allen (note: proto is not standard)
Further reading:
Classical Inheritance in JavaScript
http://javascript.crockford.com/inheritance.html
Sorry to leave you with reading material, but it seems to me you are exploring possibilities. These articles will give a deeper insight on the matter.
Once you know more on the matter, you will most likely ignore private members alltogether and use the _ prefix and just make it a public member like everyone else ;) It's just easier and private members are pointless anyways.
If you really need inheritance, there are some libraries out there that will help immensely. One option is trait.js, which may actually become a standard part of javascript at some point anyway. If that doesnt float your boat, libraries like jQuery and prototype have helpers for inheritance.
If you want to go with a minimal/from-scratch approach, I strongly suggest you use the prototype model for everything. You will see a large performance increase over the pattern you have in your examples.
To more directly address your question, no. You will have an easier time if you design your 'classes' so private functions aren't relied upon.
Related
I read some tutorials for AngularJS and noticed, that everyone is using a slightly different approach how to define a service. I'm wondering whats the best method, or what drawbacks could arise when using a specific approach.
The first difference I noticed, is in using an anonymous function OR a named function:
angular.module('myApp').service('myService', function myService() {
var _var1 = "foo";
var public_methods = {
doSomething: function() {
return "bar";
},
var1: _var1
};
return public_methods;
});
angular.module('myApp').service('myService', function() {
var _var1 = "foo";
var public_methods = {
doSomething: function() {
return "bar";
},
var1: _var1
};
return public_methods;
});
Is there any difference in this two methods?
Does angular provide the myService named function? And how?
The second difference is in defining the "public methods", e.g. what is visible to the outside:
angular.module('myApp').service('myService', function myService() {
var _var1 = "foo";
var public_methods = {
doSomething: function() {
return "bar";
},
var1: _var1
};
return public_methods;
});
angular.module('myApp').service('myService', function myService() {
var _var1 = "foo";
this.doSomething = function() {
return "bar";
};
this.var1 = _var1
});
The first one returns an object, which acts like an interface and defines what is visible to the public. The second one, defines its methods and properties with this.
Are there any drawbacks?
Why would I prefer one method over the other?
The third difference is on defining services like this:
var Session = function() {};
Session.prototype.doSomething = function() {
return "bar";
};
Session.prototype.var1 = "foo";
angular.module('myApp').service('myService', Session);
Here, I only see one drawback, that privat variables cannot be shared with other functions. But does this method has any big advantages? I could imagine that for factories (not services) the performance would be better, because the prototype functions only has to be defined once, and not everytime a new object is created (because a service is a singleton, a factory not).
Defining and using factories: I'm also unsure, if the following method is best practise when using factories:
angular.module('myApp').factory('User', function() {
var User = function(data) {
angular.extend(this, {
id: null,
email: null,
name: null
}, data);
};
return User;
});
And when using the factory, I'm writing new User(data). data gets merged with some default variables etc. What do you think about this method? Is there a big drawback? Or am I using factories in a wrong way?
I think that by and large most of what you're asking - and the reason that you're seeing it done differently - is that these are stylistic differences that are all completely legit JavaScript. There's no real best practices here.
The first question - it makes no difference.
The second question - both work, I have a strong personal preference for the first because it's more flexible; there are nifty tricks you can do that way, object manipulation kind of stuff. You could probably do all of them operating on "this" but it feels unnecessary to me. Again, personal preference.
The third question - this is just a feature of JavaScript which supports first class functions. It's just a language feature and it's going to come down to how you prefer to design things. I inline them but keep each service in its own file. I think that you see people doing it this way because the Angular Documentation on Services shows them doing it that way because it was easier to read in documentation. But it's not much different really.
I don't have a problem with how you're using that factory, but make sure you don't actually want $resource.
I'm trying to find a simple way to refer to the current instance of an object from the object methods itself (similar to this keyword in any decent language).
I've tried many variations of "storing a pointer for itself" (like window.window.window do), but always something go wrong. For example:
function ClassA() {
var mySelf = this;
this.myMethod = function() {
console.log(mySelf); //Once you extend this class, mySelf will not be available
}
}
function ClassB() {
this.mySelf = this; //Ok, now you can extend this and mySelf will be there
this.myMethod = function() {
console.log(mySelf);//"mySelf is not defined" because it's a property now
console.log(this.mySelf);//Value of 'this' and 'self' will vary
console.log(RandomContainer.ClassBInstance.mySelf);//I can't use a defined path
}
}
Since everything about OOP in JavaScript is hackish, I have to ask...
Is there any magic to refer to the current object that a method is being called from?
EDIT
A lot of possible solutions in the comments, thanks guys!
But I still need to improve my question. So I'll add some piece of code with my failed attempts, and then try out the proposed solutions...
function BaseController()
{
var myPriv = 42;
return {
getAnswer: function() {
return myPriv;
}
};
}
function SomeController()
{
return {
showAnswer: function()
{
var answer;
answer = myPriv; //I need some way to access this
answer = getAnswer(); //Also a way to refer to my own methods
//(I don't even find a way to call 'showAnswer' from this context)
console.log('The answer is ' + answer);
}
};
}
//That's how I was extending my classes so far...
var someControllerInstance = jQuery.extend(
new BaseController(),
new SomeController()
);
someControllerInstance.getAnswer(); //Works!
someControllerInstance.showAnswer(); //Reference errors...
take time to learn the idiosyncrasies of js, be warned though, it's like marmite.
If you'll allow me to be blunt for a moment, you are approaching JavaScript with the wrong frame of mind. It is not designed for classical inheritance, nor for protected properties or methods, and there is no benefit in bending it that way. To be honest I find towering stacks of inheritance a pain to read and navigate, unless you have a singing-all-dancing IDE that may take a week to load. The closer to flat and open you can achieve — whilst still keeping things flexible — the better you are at coding, and the more other coders that may take over your work will thank you. (obviously that is opinion)
For more information on prototype inheritance read the following informative post:
http://davidwalsh.name/javascript-objects-deconstruction
Below is an example of prototype inheritance, it should be noted that Object.create and isPrototypeOf are relatively new and do not exist for older JavaScript interpreters. Approximate polyfills can be used in most cases however.
Put simply JavaScript becomes much more powerful when you think in terms of objects borrowing methods from wherever they may be found, and not instances rigidly inheriting from slightly less specific instances; or worse, constructors that keep rebuilding the same functions again and again.
The following is just an example, and across my 16 years of coding ECMAScript I have barely ever needed anything that approaches classical inheritance, nor have I needed objects that heavily inherit on the prototype chain either. More often than not my js is basically just a number of newly created objects, properly name-spaced, that borrow methods from fixed pools of functions; any type detections are duck-typed, and I'm careful to keep everything as local as possible.
Anyway, here's something I don't often use:
var Make = function(construct){
return Object.create(construct);
};
var Extend = function(proto, props){
var instance = Object.create(proto);
for ( var i in props ) { instance[i] = props[i]; }
instance.super = proto; // this should never be needed really
return instance;
};
var Animal = {
keepBreathing: function(){
console.log('animal', this);
}
};
var Monkey = Extend(Animal, {
climbTree: function(){
console.log('monkey', this);
console.log('monkey', this.super);
}
});
var KeyserSoze = Make(Monkey);
KeyserSoze.keepBreathing(); /// animal, instance of KeyserSoze
KeyserSoze.climbTree(); /// monkey, instance of KeyserSoze
console.log('an instance of monkey', KeyserSoze);
console.log('has animal as proto', Animal.isPrototypeOf(KeyserSoze)); // true
console.log('has monkey as proto', Monkey.isPrototypeOf(KeyserSoze)); // true
Whilst the above does follow a kind of classical layout i.e. Monkey inherits methods from Animal, you could approach things in a different way. The following is more open to dynamic changes, in the fact you could switch out the behaviours object for another interface entirely. Again, this is just an illustration that you don't have to construct things in a fixed way.
Something I'm more likely to use:
var AnimalBehaviours = {
keepBreathing: function(){
(this.breathCount === undefined) && (this.breathCount = 0);
this.breathCount++;
}
};
var ApeLikeDescendant = (function( behaviours ){
return {
create: function( config ){
return Object.create(this).prep(config);
},
prep: function( config ){
/// do your instance specific set up here
return this;
},
climbTree: function(){
console.log('ape-like', this);
},
keepBreathing: function(){
return behaviours.keepBreathing.apply(this, arguments);
},
switchBehaviours: function(newBehaviours){
behaviours = newBehaviours;
}
};
})(AnimalBehaviours);
var DouglasAdams = ApeLikeDescendant.create({});
You could adapt the above to behave more in a manner similar to mixins i.e. you'd take the behaviours, step through them and merge them to the ApeLike object... it's really quite open to whatever your goal is.
Something that I use regularly:
var ElementEdgeCases = {
makeWorkOnNetscape47: function(){
this.target; /// Intentionally left almost blank.
}
};
var ElementFinagler = (function(){
var finagle = {
target: null,
prep: function( element ){
this.target = element;
return this;
},
addClass: function(){
var c = this.target.getAttribute('className'); /// and so on ...
return this;
},
elaborate: function( mixin ){
for ( var i in mixin ) {
if ( mixin.hasOwnProperty(i) ) {
this[i] = mixin[i];
}
}
return this;
}
};
return function( element ){
return Object.create(finagle).prep(element);
};
})();
var elm = document.getElementsByTagName('body')[0];
ElementFinagler(elm)
.elaborate(ElementEdgeCases) // extend the object if we need
.addClass('hello world')
;
The main thing to keep in mind with JavaScript is that no function is owned by anything, not really. Every time you execute a function, the function's context is implied by the way you call that function — the context is computed at call time. This allows a great deal of flexibility, and whilst you mention that calling function.apply(context, args) or function.call(context, arg, arg, ...) every time is cumbersome; it is very easy to codify your own system for hiding that repetition away.
Oh, and before I forget, one other thing to take away from the code above is that there is no duplication of function creation. Every instance shares the same functions in memory. This is an important thing to bear in mind if you are planning to create large scale applications, as you can quickly eat up memory with multiple instances of functions.
So just to recap:
Forget inheritance, it's rarely required for many js projects.
Create flexible objects that can be extended when required.
Borrow methods when you need them from other objects, using apply or call to change context.
Keep your code open, there is no need for private; open is more extensible.
Private no, but having properties not enumerable is a different story, see defineProperty.
Make sure you do not duplicate functions — unless you have to — instead create them once and reference.
this referrers to the dom node that an event originated from, or the javascript object it is a child of. In that order.
this.parentNode referrers the dom node's parent (Not sure if it works in object context).
When I write javascript I'll usually try to leverage the html's dom itself, nesting things mindful of how the JS needs to reference them.
When i create a function inside the class, TS compiler makes that function as prototyped function for example.
class MyClass {
getExample()
{
}
}
the resultant is
var MyClass = (function() {
function MyClass() {}
MyClass.prototype.getExample = function() {};
return MyClass;
})();
but what i need is
function MyClass() {
this.getExample = function() {
}
}
is it possible to get a function like this ?
Take a look at this JQFAQ.com link, here is the answer for your question 'How to create a function in class that is not going to the prototyped function in TypeScript?', and there are more FAQs available.
I had a look at TypeScript (like the online playground... prefer writing my own JS, though :P)As far as I can tell, what you want to do can be done quite easily, I've tried a few things myself and this worked like a charm for me:
class Greeter {
greeting: string;
closureMethod;
constructor (message: string) {
this.greeting = message;
var that = this;
var closureMethod = function()
{
console.log(that.greeting);
};
this.closureMethod = closureMethod;
}
greet() {
return "Hello, " + this.greeting;
}
}
var greeter = new Greeter("world");
var another = new Greeter('Foobar');
var button = document.createElement('button');
button.innerText = "Say Hello";
button.onclick = function()
{
greeter.closureMethod();
another.closureMethod();
}
document.body.appendChild(button)
Which worked, but even shorter (and this works, too)
class Greeter {
greeting: string;
closureMethod;//define property here, no type
constructor (message: string) {
this.greeting = message;
var that = this;
this.closureMethod = function()
{
console.log(that.greeting);
};
}
greet() {
return "Hello, " + this.greeting;
}
}
Both produce the same result: a constructor that defines a method over and over, for each new instance (which, honestly, is not a great idea).
As you can see, it accesses the instance using that, rather than this, which is the only upside of creating the same method over and over... as long as you have a good reason to do so. But I'm not going off in a rant on this.
The code above works, it generates a constructor function like the one you wanted.
Methods you add to the constructor in TypeScript will be added as instance methods.
Methods you add outside the constructor and within the class will be added to the prototype of the object. This is the preferred way if you are "newing" up several instances of the class as it saves on memory. But when you do this you need to make sure you have access that you need to instances memebrs and the proper "this", which you can do by setting them in advance.
I recommend considering prototypes first, then falling back to instance if you truly need them for methods. If its a singleton object, then it really doesn't matter.
However ... when you create classes in TypeScript the concept of private and public does not translate to the emitted JavaScript. So keep this in mind as you are exposing every instance member in JavaScript. I prefer to use a pattern like the Module Pattern in JavaScript, which hides internal variables/methods and exposes only what I want to be accessible. You can get this with TypeScript by creating a function that returns the accessible members of an object (no classes). Just thought I'd mention the alternative.
You can do it like this:
class MyClass {
static getSomething() {
}
}
The static keyword means it is not a prototype method and you won't need to call it on an instance - just call it with:
MyClass.getSomething();
Of course, this may not be what you want - but you'll need to share why you need it to make that clearer.
In our code base, I find that many developers use underscores as the first letter of a member variable to discourage public use. Normally, a better practice is just to declare a local variable that's accessible to an object's methods, but in our case, this doesn't seem possible because all the methods are defined on the prototype. Here's an example.
MyContrivedWidget = function(container) {
this._container = jQuery(container);
}
MyContrivedWidget.prototype = {
draw: function() {
var link = jQuery(document.createElement('a'))
.html('some contrived text')
.attr('href', '#')
.appendTo(this._container);
}
}
We have multiple reasons for using the prototype object, but the most compelling is probably that using the prototype chain allows for easy inheritance and overriding of methods. This is good for us because we have multiple products on one platform that may want to reuse a lot of JavaScript while overriding specific functionality.
So my question is, how can we get all the benefits of the prototype chain without allowing variables that should be private to be publicly accessible?
Simply spoken: ECMAscript edition 3 has no possibility to create "private" variables using prototypal inheritance or the prototype chain.
It's a little different in ES5. You've got methods like .defineProperties()help there which, are able to "hide" properties within an object.
But even if you hide the propertys from enumaration for instance, one would still be able to access those if he knows they are available. As you mentioned, the only real privacy in ECMAland is, to invoke closures. Better said, using a method-pattern by invoking a function(-context) which returns an object that contains methods as propertys. Those methods have access (since it's context closes over the parent context) to the declared variables in the outer (parent) scope. No other object can access those variables after. This looks like:
var Animal = function( args, priv, shared ) {
shared = shared || { };
shared.speed = 2;
shared.legs = 4;
shared.name = args.name || 'unknown';
priv = priv || {
run: function() {
console.log(shared.name, ' is running ', shared.speed, ' meters');
return this;
},
die: function() {
console.log(shared.name, ': wwuuaarhhhck.. aahahsd sd..aahsd.....');
return this;
}
};
return priv;
};
var Dog = function( args, priv, secret ) {
secret = secret || { };
priv = Animal( args, priv, secret ) || { };
priv.addSomeMethod = function() { };
return priv;
};
var bello = Dog({name: 'Bello'});
bello.die(); // "Bello: wwuuaarhhhck.. aahahsd sd..aahsd....."
There are some great patterns out there which bring this idea to an extend, which are also offer inheritance and shared objects + super methods. A good start to this kind of programming is still Douglas Crockfords "Javascript: the good parts".
Are there any downsides to using a JavaScript "class" with this pattern?
var FooClass = function()
{
var private = "a private variable";
this.public = "a public variable";
var privatefn = function() { ... };
this.publicfn = function() { ... };
};
var foo = new FooClass();
foo.public = "bar";
foo.publicfn();
What you're doing in your example isn't the "class" pattern people think of in JS -- typically people are thinking of the more "normal" class model of Java/C#/C++/etc which can be faked with libraries.
Instead your example is actually fairly normal and good JS design, but for completeness i'll discuss behaviour differences you'll see between the private and public "members" you have
var private = "a private variable";
this.public = "a public variable";
Accessing private from within any of your functions will be quite a lot faster than accessing public because the location of private can be determined reasonably well just with a static lookup by the JS engine. Attempts to access public require a lookup, most modern JS engines perform a degree of lookup caching, but it is still more expensive than a simple scoped var access.
var privatefn = function() { ... };
this.publicfn = function() { ... };
The same lookup rules apply to these functions as with the above variable accesses, the only real difference (in your example) is that if your functions are called, say privatefn() vs this.publicfn(), privatefn will always get the global object for this. But also if someone does
f = foo.publicfn;
f();
Then the call to f will have the global object as this but it will be able to modify the private variable.
The more normal way to do public functions however (which resolves the detached public function modifying private members issue) is to put public functions on the prototype, eg.
Foo.prototype.publicfn = function() { ... }
Which forces public functions to not modify private information -- there are some times where this isn't an option, but it's good practice as it also reduces memory use slightly, take:
function Foo1() {
this.f = function(){ return "foo" };
}
vs
function Foo2() {
}
Foo2.prototype.f = function(){ return "foo" };
In Foo1 you have a copy of the function object for every instance of Foo1 (not all the emory, just the object, eg. new Foo1().f !== new Foo2().f) whereas in Foo2 there is only a single function object.
That's good so far, but there's another access level you've left out.
this.publicfn is really a priveleged method as it has access to private members and functions.
To add methods which are public but not priveleged, modify the prototype as follows:
FooClass.prototype.reallypublicfn = function () { ... };
note that this method does not have access to private members of FooClass but it is accessible through any instance of FooClass.
Another way of accomplishing this is returning these methods from the constructor
var FooClass = function()
{
var private = "a private variable";
this.public = "a public variable";
var privatefn = function() { ... };
this.publicfn = function() { ... };
return {
reallypublicfn: function () { ...}
}
};
var foo = new FooClass();
foo.public = "bar";
foo.publicfn();
Basically, these methods of data hiding help you adhere to traditional OOP techniques. Generally speaking, improving data-hiding and encapsulation in your classes is a good thing. Ensuring low coupling makes it much easier to change things down the road, so publicly exposing as little as possible is really to your benefit.
See https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript for a simple overview and http://www.crockford.com/javascript/private.html for details on how to accomplish these things.
The main downside is that you'll wind up with a copy of publicfn for each instance of FooClass. If you'll be creating a lot of FooClass objects, it would be more efficient to
write
FooClass.prototype.publicfn = function() { ... };
It depends on your needs and relative performance. Javascript isn't the most type-safe language and isn't very strong with regards to member visibility. Traditionally you can have "private", "public privileged", and "public" visibility within a Javascript type.
You can declare private and public privileged members using:
function FooClass()
{
var privateVar = 1;
function privateFn()
{
return privateVar; // etc...
}
this.publicVar = 2;
this.publicFn = function()
{
return privateFn();
}
}
This example uses a function closure, which consists of a function declaration that includes values from the scope where the function is defined. This is acceptable when member visibility is necessary but can lead to overhead. The JavaScript interpreter cannot reuse the privateFn or publicFn definitions for every instantiation since they refer to variables or functions in the outer scope. As a result every instance of FooClass results in additional storage space for privateFn and publicFn. If the type is uses infrequently or in moderation the performance penalty is neglegible. If the type is used very often in the page, or if the page is more of an "AJAX" style where memory isn't freed as frequently since the page is not unloaded then the penalty can be more visible.
An alternative approach is to use prototype members. These are unprivleged public members. Since Javascript is not entirely type-safe and is relatively easy to modify after it's loaded, type safety and member visibility aren't as reliable for controlling access to type internals. For performance reasons, some frameworks like ASP.NET Ajax instead using member naming to infer visibility rules. For example, the same type in ASP.NET Ajax might look like:
function FooClass2()
{
this._privateVar = 1;
this.publicVar = 2;
}
FooClass2.prototype =
{
_privateFn : function()
{
return this._privateVar;
},
publicFn : function()
{
return this._privateFn();
}
}
FooClass2.registerClass("FooClass2");
In this case the private scoped members are private in name only, the "_" prefix is considered to mean a private member variable. It has the downside of preventing the member from being truly private, but the upside of allowing in-memory patching of the object. The other main benefit is that all functions are created once by the interpreter and engine and reused over and over for the type. The "this" keyword then refers to the instance of the type even though the function reference itself is the same.
One way to see the difference in action is to try this with both types (if you don't have ASP.NET Ajax, you can ignore the last line in FooClass2 that calls registerClass())
var fooA = new FooClass(), fooB = new FooClass();
alert(fooA.publicFn===fooB.publicFn); // false
var foo2A = new FooClass2(), foo2B = new FooClass2();
alert(foo2A.publicFn===foo2B.publicFn); // true
So its a matter of type safety and member visibility vs. performance and the ability to patch in memory
Also, if I may mention something useful to this - With prototype you are able to add additional methods later on in the code to extend the function from an extern scope. As a tiny benefit, the whole body with all the methods won't be rendered every time, hence it speeds up compiling performances. If you have all the declared methods inside the function already, this slightly would take more time to render. So, my advice, apply these later only when they become relevent in the current code.
Example:
// inside
function fn(arg) {
this.val = arg;
fn.prototype.getVal =()=> {
console.log(this.val);
}
}
var func = new fn('value');
func.getVal();
// declare extern methods
function fn2(arg) {
this.val = arg;
}
fn2.prototype.getVal =()=> {
console.log(this.val);
}
var func2 = new fn2('value');
func2.getVal();