Reputation: 21
var obgect = function (constructorOptions) {
var privateFunction1 = function (v1) {
return 'You said: ' + v1;
};
this.willHaveAccessToPrivate = function () {
return 'This function will have access to privateFunction1(), but will I be on prototype chain?';
};
obgect.prototype.anotherPublicFunction = function () {
var s = privateFunction1('I have access to you.');
return 'Adding on prototype from within the constructor.';
};
};
obgect.prototype = new Object();
obgect.prototype.outsidePublicFunction = function () {
var s = privateFunction1('I will fail here because you are not accessible.');
return 'Standard practice';
};
var instance = new obgect({
'gurusWanted': true,
'hurtsMyHead': true,
'discouragesMe': false
});
var outside = instance.outsidePublicFunction(); // will fail here.
var anotherInside = instance.anotherPublicFunction(); // will work!
Upvotes: 0
Views: 67
Reputation: 1074475
1. Is there anything wrong with writing public functions for an object inside its constructor function?
No, it's fairly common practice. It does mean that every instance gets its own copy of each function, which could have some memory impact, but unless you're creating thousands of them that's not necessarily an issue. You just have to know you're doing it.
2. Is there anything wrong with adding functions to prototype chain inside constructor function?
Yes, big time. It creates cross-talk between instances, because an instance created earlier will end up using the function assigned to the prototype by an instance created later. Very, very much something to avoid. Consider this much simpler example:
function Example(data) {
var privateData = data;
Example.prototype.doSomethingWithPrivateData = function() {
console.log(privateData);
};
}
var e1 = new Example(1);
e1.doSomethingWithPrivateData(); // "1"
var e2 = new Example(2);
e2.doSomethingWithPrivateData(); // "2"
So far, so good, right? But:
e1.doSomethingWithPrivateData(); // "2"
Oops! e1
is using e2
's private data now, because e2
was created after e1
and rewired the prototype.
Functions on the prototype cannot have access to "private" functions created the way you're creating them (in the constructor).
3. Alternatives to this?
That's probably too broad a question to answer, but the rules above should help you decide how to proceed.
But if having private features of instances is an important thing to you, there is a pattern you can use for it while still getting function reuse. I detail it in this blog post, but here's the gist:
In ES6, we'll have "private Name
objects" which can be used as property keys, so you can store data in instances that cannot be accessed unless you have that special Name
object. Now, we can't do that in ES5, but we can get close by using a Name
function that returns semi-random names, like this:
var Name = function() {
var used = {};
function Name() {
var length, str;
do {
length = 5 + Math.floor(Math.random() * 10);
str = "_";
while (length--) {
str += String.fromCharCode(32 + Math.floor(95 * Math.random()));
}
}
while (used[str]);
used[str] = true;
return new String(str); // Since this is called via `new`, we have to return an object to override the default
}
return Name;
}();
Then here's how we have (nearly) private members using that:
// Nearly-private properties
// ***No `import` here (once the final form is determined, we'll probably be able to feature test for it)
var Foo = (function() {
// Create a random string as our private property key
var nifty = new Name();
// Our constructor
function Foo() {
// We can just assign here as normal
this[nifty] = 42;
}
// ***On ES5, make the property non-enumerable
// (that's the default for properties created with
// Object.defineProperty)
if (Object.defineProperty) { // Only needed for ES3-compatibility
Object.defineProperty(Foo.prototype, nifty, {
writable: true
});
}
// ***End change
// Methods shared by all Foo instances
Foo.prototype.method1 = function() {
// This method has access to `nifty`, because it
// closes over the private key
console.log("Truly private nifty info: " + this[nifty]);
};
Foo.prototype.method2 = function() {
// Also has access, for the same reason
console.log("Truly private nifty info: " + this[nifty]);
};
return Foo;
})();
var f = new Foo();
f.method1(); // Can use nifty!
f.method2(); // Can too! :-)
// Both `method1` and `method2` are *reused* by all `Foo` objects
Nothing outside Foo
can readily use the nearly-private data, because the property name keeps changing.
Upvotes: 4