Difference between Date.prototype.newFunction and Date.newFunction? - javascript

What would the difference be between Date.prototype.newFunction and Date.newFunction? I'm aware of how prototypal inheritance works in Javascript so I understand the prototype example, but the Date.newFunction throws me.

As I think you know, the prototype contains properties that will be automatically inherited by objects created via the constructor.
Date.newFunction is just a property on the constructor itself and it can only be accessed via Date.newFunction. It is not inherited by objects created via the constructor and is not accessible via a particular instance created by the constructor.
Some would say that Date.newFunction is analogous to a class static method in other languages. It's not a method attached to a particular instance, but more like a helper function for that object type. These types of methods typically do not operate on instance data and they could just as easily be global utility functions, but it is often cleaner from a namespace point-of-view to assign them as properties of the constructor.
For example, on the Javascript Date object, methods such as Date.now() and Date.parse() are examples of this type of static methods. You don't create an instance to use them, you just call them directly:
var tStart = Date.now();
One thing to remember is that any function in Javascript is an object too, so it can have arbitrary properties beyond just the .prototype property and using that capability for static methods is just one use.

Date.a = function () {
return 'Date.a';
};
Date.prototype.a = function () {
return 'Date.prototype.a';
};
Date.a(); // return 'Date.a'
var b = new Date();
b.a(); // return 'Date.prototype.a'

Related

What is a difference between an object literal and a class with values in constructor in javascript?

I've been working on end to end test in testcafe and in their documentation I found following solution for Page Model:
class Page {
constructor () {
this.nameInput = Selector('#developer-name');
}
}
export default new Page();
I've been doing some research and I cannot get my head around why it is not resolved with an object literal:
export const Page = {
nameInput: Selector('#developer-name');
}
What are consequences of using each of them?
The difference is significant but fundamentally both are JavaScript objects, albeit with different properties and values. Listing all differences on the level of the language would be a long story and you'd be wise to read and understand on JavaScript prototype-based inheritance, but the most important differences are:
Page is a prototype object: whenever you create an object of class Page with new Page(), the constructor function is called with this referring to the object being created, not Page itself. Any property you access on the object is searched along the so-called "prototype chain", including the so-called prototype object. This prototype object can be accessed with Page.prototype and in fact, all methods you define in the class Page are also properties of this prototype object. Unlike own properties designed to refer to unique objects or primitives specific to an object, functions in JavaScript don't have to be bound to an object during object or function creation and can be shared between objects (belonging to the same class, for instance) and are called on the actual instance, not the prototype to which they may belong. In other words, this.nameInput in your constructor actually adds a property named nameInput to the object being created with new Page(), not the prototype, while the constructor itself (constructor) and any non-static methods you might add to Page will be added as properties of Page.prototype. The constructor is accessed as Page.prototype.constructor, by the way, as you'd naturally expect. Page.prototype.constructor === Page evaluates to true, by the way.
An expression of the form like { nameInput: ... } creates an object which prototype is Object.prototype, in practice the most basic form of object with "no prototype" and thus no superclass or any traits beyond what the fundamental object prototype object could provide. Any properties any such { ... } object may seem to have through its prototype chain, including methods, are properties of Object.prototype. This is why you can do ({}).toString() or ({}).hasOwnProperty("foobar") without actually having toString or hasOwnProperty properties in your object -- toString and hasOwnProperty are properties of Object.prototype referring to two distinct methods called toString and hasOwnProperty, respectively, and JavaScript creates a special property on your object called __proto__ referring to Object.prototype. This is how it knows how to "walk the prototype chain". The names of functions themselves do not matter like that, by the way -- I may add a property on an object referring to an anonymous function: var foo = ({}); foo.bar = function() { }; and call said unnamed function with foo.bar().
One mistake you appear to be making is confusing an object of a class with the class, otherwise you wouldn't compare export default class Page { ... } to export const Page = { nameInput: Selector(...) } -- the former creates a class accessible as Page which is used as the prototype object whenever objects of the class are created, while the latter creates an object accessible as Page which contains nameInput referring to result of evaluating expression Selector("#developer-name") (calling Selector with the sole argument "#developer-name"). Not the same thing at all, not to mention that former has Page refer to a class (invariably a prototype in JavaScript), while latter has Page refer to an object that does not seem to fit the pattern of a class.
The interesting things start when you realize that since a class is an object like any other in JavaScript, any object can be used as a class if you know how prototype-based inheritance works:
new (function() { this.nameInput = Selector("#developer-name"); })();
What happens here? You create a new object with an unnamed function as the object constructor. The effect is absolutely equivalent to otherwise creating the object with new Page with Page being your original ES6 class (ECMAScript 6 is the language specification that adds class syntax to JavaScript).
You can also do this, again equivalent to if you defined Page with class Page ...:
function Page() {
this.nameInput = Selector("#developer-name");
}
var foo = new Page();
Page.prototype will be the prototype object for foo, accessible as foo.__proto__ and otherwise making it possible for you to call instance methods on foo like foo.bar(), provided you define bar property on at least Page.prototype:
function Page() {
this.nameInput = Selector("#developer-name");
}
Page.prototype.bar = function() {
console.log(this.nameInput);
}
var foo = new Page();
foo.bar();
In fact, the above is what browser would do internally if it had to interpret the following code:
class Page {
constructor() {
this.nameInput = Selector("#developer-name");
}
bar() {
console.log(this.nameInput);
}
}
It is beyond the scope of my answer to list differences between the two last approaches (isn't the same thing as the two approaches you proposed), but one difference is that with class Page ..., Page is not a property of window in some user agents while with function Page ... it is. It's partly historical reasons, but rest assured that so far defining constructors and prototype using either approach is pretty much the same, although I can imagine smarter JavaScript runtimes will be able to optimize the latter form better (because it's an atomic declaration, and not just a sequence of expressions and statements).
If you understand prototype-based inheritance at the heart of all of this, all your questions about this will fall away by themselves as very few fundamental mechanisms of JavaScript support 99% of its idiosyncrasies. You'll also be able to optimize your object design and access patterns, knowing when to choose ES6 classes, when not to, when using object literals ({ prop: value, ... }) and when not to, and how to share fewer objects between properties.
Classes can be thought of as a blueprint, they both provide an object in the end. But as the object literals name implies, you literally create it there and then with this 'literal' syntax. A class however, we would use to instantiate new instances from 1 base blueprint.
let x = { myProp: undefined }
let y = { myProp: undefined }
x.myProp = "test";
y.myProp // undefined
Here we see we make two separate instances, but we will have to repeat code.
class X { }
let x = new X();
let y = new X();
A class does not need to repeat the code, as it is all encapsulated in the idea of what X should be, a blueprint.
Similar to above [in the literal] we have two separate instances but it's cleaner, more readable, and any change we wish to make to every instance of this 'X' object can now be changed simply in the class.
There's a plethora of other benefits and even a paradigm dedicated to Object-Oriented Programming, read here for more:
https://www.internalpointers.com/post/object-literals-vs-constructors-javascript
To go further into the constructor question... In other languages we have fields.
I believe when you assign a field in the constructor, it just creates an underthehood like field (I say underthehood like because JavaScript is prototype based, and the class syntax is syntactical sugar to help write prototypes easier for programmers familiar with class syntax in other languages).
Here is an example in C#.
public class X{
private int y;
X() {
this.y = 5;
}
}
It's more a convention to assign fields in the constructor in other languages, so I assume this has something to do with it in JavaScript.
Hope this helps.
By declaring it as a Class you can later identify what type of object it is with .constructor.name:
class Page {
constructor () {
this.nameInput = "something";
}
// No comma
anotherMethod() {
}
}
const pageClass = new Page();
const pageLiteral = {
nameInput: "something"
, // must have a comma
anotherMethod() {
}
}
console.log("Name of constructor for class: ", pageClass.constructor.name); // Page
console.log("Name of constructor for literal: ", pageLiteral.constructor.name); // Object

Difference between Factory function and Constructor [duplicate]

Can someone clarify the difference between a constructor function and a factory function in Javascript.
When to use one instead of the other?
The basic difference is that a constructor function is used with the new keyword (which causes JavaScript to automatically create a new object, set this within the function to that object, and return the object):
var objFromConstructor = new ConstructorFunction();
A factory function is called like a "regular" function:
var objFromFactory = factoryFunction();
But for it to be considered a "factory" it would need to return a new instance of some object: you wouldn't call it a "factory" function if it just returned a boolean or something. This does not happen automatically like with new, but it does allow more flexibility for some cases.
In a really simple example the functions referenced above might look something like this:
function ConstructorFunction() {
this.someProp1 = "1";
this.someProp2 = "2";
}
ConstructorFunction.prototype.someMethod = function() { /* whatever */ };
function factoryFunction() {
var obj = {
someProp1 : "1",
someProp2 : "2",
someMethod: function() { /* whatever */ }
};
// other code to manipulate obj in some way here
return obj;
}
Of course you can make factory functions much more complicated than that simple example.
One advantage to factory functions is when the object to be returned could be of several different types depending on some parameter.
Benefits of using constructors
Most books teach you to use constructors and new
this refers to the new object
Some people like the way var myFoo = new Foo(); reads.
Drawbacks
Details of instantiation get leaked into the calling API (via the new requirement), so all callers are tightly coupled to the constructor implementation. If you ever need the additional flexibility of the factory, you'll have to refactor all callers (admittedly the exceptional case, rather than the rule).
Forgetting new is such a common bug, you should strongly consider adding a boilerplate check to ensure that the constructor is called correctly ( if (!(this instanceof Foo)) { return new Foo() } ). EDIT: Since ES6 (ES2015) you can't forget new with a class constructor, or the constructor will throw an error.
If you do the instanceof check, it leaves ambiguity as to whether or not new is required. In my opinion, it shouldn't be. You've effectively short circuited the new requirement, which means you could erase drawback #1. But then you've just got a factory function in all but name, with additional boilerplate, a capital letter, and less flexible this context.
Constructors break the Open / Closed Principle
But my main concern is that it violates the open/closed principle. You start out exporting a constructor, users start using the constructor, then down the road you realize you need the flexibility of a factory, instead (for instance, to switch the implementation to use object pools, or to instantiate across execution contexts, or to have more inheritance flexibility using prototypal OO).
You're stuck, though. You can't make the change without breaking all the code that calls your constructor with new. You can't switch to using object pools for performance gains, for instance.
Also, using constructors gives you a deceptive instanceof that doesn't work across execution contexts, and doesn't work if your constructor prototype gets swapped out. It will also fail if you start out returning this from your constructor, and then switch to exporting an arbitrary object, which you'd have to do to enable factory-like behavior in your constructor.
Benefits of using factories
Less code - no boilerplate required.
You can return any arbitrary object, and use any arbitrary prototype - giving you more flexibility to create various types of objects which implement the same API. For example, a media player that can create instances of both HTML5 and flash players, or an event library which can emit DOM events or web socket events. Factories can also instantiate objects across execution contexts, take advantage of object pools, and allow for more flexible prototypal inheritance models.
You'd never have a need to convert from a factory to a constructor, so refactoring will never be an issue.
No ambiguity about using new. Don't. (It will make this behave badly, see next point).
this behaves as it normally would - so you can use it to access the parent object (for example, inside player.create(), this refers to player, just like any other method invocation would. call and apply also reassign this, as expected. If you store prototypes on the parent object, that can be a great way to dynamically swap out functionality, and enable very flexible polymorphism for your object instantiation.
No ambiguity about whether or not to capitalize. Don't. Lint tools will complain, and then you'll be tempted to try to use new, and then you'll undo the benefit described above.
Some people like the way var myFoo = foo(); or var myFoo = foo.create(); reads.
Drawbacks
new doesn't behave as expected (see above). Solution: don't use it.
this doesn't refer to the new object (instead, if the constructor is invoked with dot notation or square bracket notation, e.g. foo.bar() - this refers to foo - just like every other JavaScript method -- see benefits).
A constructor returns an instance of the class you call it on. A factory function can return anything. You would use a factory function when you need to return arbitrary values or when a class has a large setup process.
A Constructor function example
function User(name) {
this.name = name;
this.isAdmin = false;
}
let user = new User("Jack");
new creates an object prototyped on User.prototype and calls User with the created object as its this value.
new treats an argument expression for its operand as optional:
let user = new User;
would cause new to call User with no arguments.
new returns the object it created, unless the constructor returns an object value, which is returned instead. This is an edge case which for the most part can be ignored.
Pros and Cons
Objects created by constructor functions inherit properties from the constructor's prototype property, and return true using the instanceOf operator on the constructor function.
The above behaviors can fail if you dynamically change the value of the constructor's prototype property after having already used the constructor. Doing so is rare, and it can't be changed if the constructor were created using the class keyword.
Constructor functions can be extended using the extends keyword.
Constructor functions can't return null as an error value. Since it's not an object data type, it is ignored by new.
A Factory function example
function User(name, age) {
return {
name,
age,
}
};
let user = User("Tom", 23);
Here the factory function is called without new. The function is entirely responsible for the direct or indirect use if its arguments and the type of object it returns. In this example it returns a simple [Object object] with some properties set from arguments.
Pros and Cons
Easily hides the implementation complexities of object creation from the caller. This is particularly useful for native code functions in a browser.
The factory function need not always return objects of the same type, and could even return null as an error indicator.
In simple cases, factory functions can be simple in structure and meaning.
Objects returned do not generally inherit from the factory function's prototype property, and return false from instanceOf factoryFunction.
The factory function can't be safely extended using the extends keyword because extended objects would inherit from the factory functions prototype property instead of from the prototype property of the constructor used by the factory function.
Factories are "always" better. When using object orientated languages then
decide on the contract (the methods and what they will do)
Create interfaces that expose those methods (in javascript you don't have interfaces so you need to come up with some way of checking the implementation)
Create a factory that returns an implementation of each interface required.
The implementations (the actual objects created with new) are not exposed to the factory user/consumer. This means that the factory developer can expand and create new implementations as long as he/she doesn't break the contract...and it allows for the factory consumer to just benefit from the new API without having to change their code...if they used new and a "new" implementation comes along then they have to go and change every line which uses "new" to use the "new" implementation...with the factory their code doesn't change...
Factories - better than all anything else - the spring framework is completely built around this idea.
Factories are a layer of abstraction, and like all abstractions they have a.cost in complexity. When encountering a factory based API figuring out what the factory is for a given API can be challenging for the API consumer. With constructors discoverability is trivial.
When deciding between ctors and factories you need to decide if the complexity is justified by the benefit.
Worth noting that Javascript constructors can be arbitrary factories by returning something other than this or undefined. So in js you can get the best of both worlds - discoverable API and object pooling/caching.
I think the factory function is superior to the constructor function. Using new with the constructor function, we are binding our code to one specific way of creating an object, while with a factory, we are free so we can create more different instances without binding ourselves. Let's say we have this class:
const file = new CreateFile(name)
If we want to refactor CreateFile class, creating subclasses for the file format our server supports, we can write an elegan factory function:
function CreateFile(name) {
if (name.match(/\.pdf$/)) {
return new FilePdf(name);
} else if (name.match(/\.txt$/)) {
return new FileTxt(name);
} else if (name.match(/\.md$/)) {
return new FileMd(name);
} else {
throw new Error("Not supprted file type");
}
}
with factory functions, we can implement private variables, hide the information from the users which is called encapsulation.
function createPerson(name) {
const privateInfo = {};
// we create person object
const person = {
setName(name) {
if (!name) {
throw new Error("A person must have a name");
}
privateInfo.name = name;
},
getName() {
return privateInfo.name;
},
};
person.setName(name);
return person;
}
For the differences, Eric Elliott clarified very well,
But for the second question:
When to use one instead of the other?
If you are coming from the object-oriented background, Constructor function looks more natural to you.
this way you shouldn't forget to use new keyword.

differences between prototype and namespace

In namespace we can use something like this:
var namespace = {};
namespace.something.nested.namespacing();
And also in prototype we can use same like name the namespace:
something.prototype.method();
In both types we are using . notation. So, how can we determine the code is using namespace or prototype?
JavaScript doesn't have namespaces. What you're calling a namespace is just an object. It's fairly common to use objects to stand in for namespaces.
Your code:
var namespace = {};
namespace.something.nested.namespacing();
...creates an object and a variable that refers to that object called namespace. Then you add properties to that object (it looks like you've added a property, something, which is also an object, which has a property, nested, which is also an object, which has a property called namespacing which refers to a function).
Your code:
something.prototype.method();
...is also using an object. The above would actually be a really unusual thing to do, you're calling a function (method) by directly referring to the prototype property of what I assume is a function (something). That's not normally what you would do. Normally you'd create an object via the function:
var s = new something();
...and then use the prototype that got assigned to s implicitly:
s.method();
The prototype property on functions can be confusing to people new to JavaScript. It's just a normal property like any other property, which is on function instances. The only thing that makes it special is the new operator: When you call a function via new:
var s = new something();
...the JavaScript engine creates a new, blank, object, then sets its underlying prototype (sometimes called __proto__ but that's not in the spec [yet]) using something.prototype, like this:
// pseudo-code for `var s = new something()`
var tmp = {}; // New, blank object
tmp.__proto__ = something.prototype; // Assign a prototype to the new object
something.call(tmp); // Call `something` with `this` referring to `tmp`
s = tmp; // Assign the result to `s`
(There's a detail I left out in the above to avoid confusing matters, to do with the special case where something has an explicit return statement in it that returns an object reference.)
Well, namespaces are just objects and prototype objects are objects, so from a syntactic point of view, there is no difference how you access them (foo.bar is called dot notation().
However, they serve two fundamentally different purposes:
Namespaces are used to structure your code and to avoid global namespace pollution.
Prototypes are used to share methods between multiple instances of the same constructor function.
So you usually don't call a method directly on the prototype because it most likely won't work. The purpose of this method is to be called on an instance of the corresponding constructor function. For example:
function Something() {}
Something.prototype.foo = function() {};
var s = new Something();
s.foo();
The . notation is a very general purpose tool used in javascript for accessing any properties of any object.
var x = {};
x.val = 2;
Your reference to a namespace is just a general purpose object in javascript as there is no actual namespace type in javascript. In other words, plain objects are used to create namespace-like things in javascript. So, as such, object properties are used to keep track of names in the namespace.
The . notation's use with the prototype is one specific instance of accessing properties on a specific type of object (the prototype). A prototype is used on a function object and has a very specific use when creating new instances of that function.
function foo() {
}
foo.prototype.talk = function() {
alert("hello");
}
var y = new foo();
y.talk();

understanding simple class emulator in JavaScript

Recently I started to learn a bit more advanced JavaScript (as far I only used jQuery for some simple tasks) and bought a book of Alex MaxCaw "JavaScript Web Applications". The first chapter treats about creating simple class emulator. I understand almost everything except for two lines of code marked with comments down below:
var Class = function(parent) {
var _class = function() {
this.init.apply(this, arguments);
};
if(parent) {
var subclass = function() {};
subclass.prototype = parent.prototype;
_class.prototype = new subclass();
};
_class.prototype.init = function() {};
_class.fn = _class.prototype;
//????
_class.fn.parent = _class;
//????
_class._super = _class.__proto__;
return _class;
};
Can anyone tell me what is purpose of these two lines? I'll be very thankfull.
Walking through the code:
Class is defined as a function that calls init with the arguments provided it. This means you can call it with standard constructor syntax using new eg. var instance = new Thingy() and get the init function called with the proper this value.
If you pass a parent class in, your class gets that class's prototype property added to the prototype chain of a new empty object which it uses as its prototype property. A more succinct way of doing this in modern browsers is _class.prototype = Object.create(parent.prototype);
The init function is defined. This should likely be overridden with more useful initialization code after a _class instance is created (or the code should be changed to allow the passing in of an init function when you create a Class... or allow the instance to walk the prototype chain to look for other init functions.
_class.fn is created to provide a reference to the _class constructor's prototype function.
_class.fn.parent is created to provide a reference back to the constructor. This may be useful if you are applying the prototype in some other context and want a reference back to the prototype's constructor.
_class._super is assigned the internal, non-standard __proto__ property of the constructor. Remember that constructors are functions and, in Javascript, functions are objects. This means they have their own internal prototypes. The earlier references to prototype are the prototype assigned to objects created with this constructor NOT the constructor's prototype itself. All functions inherit from Function.prototype, which is where they get bind, apply, etc. _super in this case is just a reference to Function.prototype.
As to when this type of _super is used, one could imagine doing the following:
function Maker(){ //this will be called as a constructor, ie. with new
var fun = function(){}; //Make a function
fun.__proto__ = this.__proto__; //yuck. Set the function's this value to the instance
return fun; //return the function
}
Maker.prototype={say:function(){console.log("Javascript is fun!.. And weird.")}};
var fun = new Maker();
fun.say() //"Javascript is fun!.. And weird."
console.log(fun.__proto__) // Object{say:function}
console.log(fun.bind) // undefined!!
Woah! What just happened?
In fact, you replaced your functions internal prototype with an Object. This allows you to build up interesting prototype chains and interact with both functions and objects in a similar way. Note, however, that the link with Function.prototype has been severed, which is why we don't have access to bind. However let's fix it with more prototype magic!
function FunctionConnector(obj){
for (var prop in obj){
if(obj.hasOwnProperty(prop){
this.prop=obj.prop
}
}
}
FunctionConnector.prototype=Function.prototype;
Maker.prototype=new FunctionConnector({say:function(){
console.log("Javascript is fun!.. And weird.")
}});
var fun = new Maker();
fun.say() //"Javascript is fun!.. And weird."
console.log(fun.__proto__) // Object{say:function}
console.log(fun.bind) // function bind(){ [native code] }
Now what is that FunctionConnector? It takes an object and, when called as a constructor, returns an object that both has all the properties of the passed object AND inherits from Function.prototype. As you can see, our access to bind has returned (Of course we also could have made do with our original implementation and just Function.prototype.bind.called our way to victory).
With this new pattern in hand it may be clearer what _super in your code does, namely it references the built in prototype of the _class constructor you are making (In our example the instance of FunctionConnector would be _super). This reference could be used to patch the prototype at runtime, call methods with apply or anything else you can due with a reference to an object.
This is, as you may have noticed a little hackish, especially since __proto__ is nonstandard. But it's also somewhat neat if you enjoy the patterns it allows. I'd recommend only doing something like this if you are very confident in your knowledge of Javascript inheritance, and perhaps not even then unless you are in charge of your entire code base.
From what i know, fn is just an alias to the prototype property
And about the _super, that one is for referencing to the "class" from which you are inheriting
Here's more about the use of _super and js inheritance: article

JavaScript Code Architecture - Use Constructor Functions Or Not

Please help me decide whether I should use a function's prototype object and the "new" keyword or completely stay away from constructor functions.
Situation:
Function called widget() that will be called 10-15 times to initialize each widget on the page. widget() contains quite a few internal methods.
Each time widget() is called, the function needs to return an object that acts as an API to operate on the widget.
Question
1) Do I put all the internal methods inside Widget() under its prototype property? It does not make sense but the main reason for this is to not re-instantiate the internal functions every time widget() is called.
But if I do put the internal functions in prototype, each instantiated w object (w = new Widget();) has access to internal private methods.
2) If I stay away from constructor functions and new keyword and structure my code as down below, how do I fix the performance concern of the internal functions getting re-instantiated every time widget() is called.
function widget()
{
var returnObj = {};
/* Add internal functions but this will be re-instantiated every time */
return returnObj;
}
You have a bit of a tradeoff here. As you seem to already understand, methods you put on the .prototype are publicly available, but that is the most efficient places to put methods as they are automatically added to all new copies of that object in a very efficient manner. When using .prototype for methods, there is only one copy of your methods and a reference to that single copy is automatically added to all new instantiations of that object.
But, javascript doesn't have private methods built-in and the only work-around for that involves not using the .prototype for them or for any methods that need to call the private methods.
This article by Doug Crockford is a pretty good description of how you can create privacy for either data or methods in any object.
In either case, I don't see any reason to avoid using the new keyword to create new objects. You can make either .prototype or private methods work with new.
But, if you want to achieve truly private methods, then you can't use .prototype for either the private methods or any methods that need to access them so you have to decide which is more important to you. There is no single correct answer because your need for privacy is situation-specific.
In my coding, I generally don't enforce privacy and I do use .prototype and new. I designate "non-public" methods on the prototype by starting their name with an underscore. This is a notational convention, not an access enforcement scheme.
In answer to your second question about avoiding the new operator and reinstantiating methods, I'd just ask why you're doing this? What are you gaining? I'm not aware of any downsides to using new. As best I understand your decision about whether to use .prototype vs. manually create/assign methods in your constructor should be about the need for private methods.
FYI, 15 objects is hardly going to create a significant difference in performance either way here. I would evaluate your need for true privacy and make your decision based on that. If you HAVE to enforce privacy, then go with the Crockford method for implementing private methods. If you don't HAVE to have true privacy, then use .prototype. I don't see a reason here to avoid using new in either case.
You can use a metaconstructor* pattern to get around this.
function defineCtor(metaCtor) {
var proto = new metaCtor();
var ctor = proto.hasOwnProperty('constructor') ?
proto.constructor : new Function();
return (ctor.prototype = proto).constructor = ctor;
}
Now you have a function that constructs constructors (or more accurately constructs prototypes and returns constructors).
var Widget = defineCtor(function() {
function doInternalStuff() {
// ...cant see me
}
// this function ends up on the prototype
this.getFoo = function() { return doInternalStuff(); };
});
// ...
var myWidget = new Widget();
Explanation
defineCtor takes a single anonymous function as a property. It invokes the function with new, creating an object. It assigns the object as the prototype property of a new constructor function (either an empty function, or the generated prototype object's own constructor property), and returns that function.
This provides a closure for your internal functions, addressing your question 1, and sets up the constructor/prototype pair for you, addressing question 2.
Comparison
Compare the defineCtor technique to the following two examples.
This example uses the prototype, and has problem 1: the internal stuff is not encapsulated.
function Widget(options) {
this.options = options;
}
Widget.prototype = {
getFoo: function() {
return doInternalStuff();
}
};
// How to encapsulate this?
function doInternalStuff() { /* ... */ }
This example sets up everything in a constructor, and has problem 2: each time it constructs an object, it instantiates new function objects for each property.
function Widget(options) {
this.options = options;
function doInternalStuff() { /* ... */ }
this.getFoo = function() {
return doInternalStuff();
};
}
This example uses the technique described above to provide encapsulation while still leveraging the prototype:
var Widget = defineCtor(function() {
// ^
// This function runs once, constructing the prototype.
// In here, `this` refers to the prototype.
// The real constructor.
this.constructor = function(options) {
// In function properties, `this` is an object instance
// with the outer `this` in its prototype chain.
this.options = options;
};
function doInternalStuff() { /* ... */ }
this.getFoo = function() { return doInternalStuff(); };
});
// ...
var myWidget = new Widget();
This approach has a few benefits, some more immediately obvious than others.
It provides encapsulation. You could do this by wrapping the first "comparison" example in an immediately invoked function, but this approach may be cleaner and more easily "enforced" in a team setting.
It's extensible. You can give your "metaconstructor" functions their own prototypes, with function properties like "extends", "mixin", etc. Then, inside the body of metaCtor, you can write things like this.extends(BaseWidget). The defineCtor API never needs to change for any of this to happen.
It "tricks" Google Closure Compiler, Eclipse, jsdoc, etc. into thinking you are defining the actual constructor function rather than a "meta function." This can be useful in certain situations (the code is "self-documented" in a way these tools understand).
* As far as I know, the word "metaconstructor" is completely made up.

Categories

Resources