How to ensure durable-object's private members are truly private - javascript

Trying to learn how to create a durable object with JavaScript, but as you can see from the example below one can easily access any of the Person instance's members - What am I doing wrong?
function Person(name, age, job){
"use strict";
//create the object to return
var o = new Object();
//optional: define private variables/functions here
o.name = name;
o.age = age;
o.job = job;
//attach methods
o.sayName = function(){
alert(name);
};
//return the object
return o;
}
var newGuy = Person("Guy", 21, "Seeker");
newGuy.name; // "Guy" <- Shouldn't this return an error or "undefined"?

You get "Guy" because you set it as name property of o, and then return o to the outside, making it public.
If you want private variables, you can use
function Person(name, age, job){
"use strict";
// name, age, job are private variables
// sayName is a privileged method
this.sayName = function(){
alert(name);
};
}
var newGuy = new Person("Guy", 21, "Seeker");
newGuy.name; // undefined
Note you don't need to create a new o object and return it, just call the constructor with new operator and assign public/privileged properties to this.
I suggest reading Private Members in JavaScript, by Douglas Crockford.

There are a lot of different ways to create private properties. They all find ways to take advantage of the fact that variables are scoped locally within functions, but can be captured in functions.
For example rather than returning o, which will have all the properties exposed, you can return a different object that has private access. There's a bit of redundancy in this snippet, but I wanted to keep it close to your example:
function person(name, age, job){
"use strict";
//optional: define private variables/functions here
var name = name;
var age = age;
var job = job;
//return the object that uses variable, that are only visible within the function
return {
sayName: function(){
alert(name);
},
sayJob: function(){
alert(job);
}
}
}
var newGuy = person("Guy", 21, "Seeker");
newGuy.sayName();
newGuy.sayJob();
alert("undefined: ", newGuy.name); // "Guy" <- Shouldn't this return an error or "undefined"?

For a durable object, Douglas Crockford recommends avoiding "this" and "new" altogether. This is how you would go about accomplishing what you want:
var person = function (vals) {
var that = {}; // create object to avoid constructing with "new" and using "this"
that.sayName = function () { // bind accessor functions
return vals.name; // use passed values to ensure privacy
};
return that;
};
var guy = person({name: "Guy"}); // avoided use of "new"
alert(guy.name); // undefined as should be
guy.sayName(); // "Guy"
You can find more info in his book: Javascript: The Good Parts on page 52. I hope this helps.

Related

Writing JS Prototypes, should all functions use the Prototype object?

I'm beginning to learn more about writing JS using the Prototype object, but I want to make sure I don't pick up any bad habits from other developers. My understanding of using Prototype is to create public methods for your instance. For example:
var module = new Module();
module.method();
But I see a lot of developers creating all their code inside the Prototype object, things that I would consider "private". Is this bad practice or considered okay? It just means I can then do:
module.privateFn();
Do they know this? Is that okay? Any help appreciated. I've been looking through the source code on GitHub to try establish the best way forward, here's a script that uses Prototypes for everything (for instance attachEvent which they clearly want privately kept):
https://github.com/WickyNilliams/headroom.js/blob/master/dist/headroom.js
Much appreciated, I want to make sure I develop using the correct implementations.
First of all you don't need to write modules using prototype. Think like if you writing something like a class you should use prototypes. And also it's important to where define your methods. Defining methods on prototype object and defining them in constructor function is totally different things!
Let's see a sample class definition with using methods defined in constructor:
var Dog = (function () {
var Dog = function (age, name) {
var that = this;
this.age = age;
this.name = name;
this.sayHi = function () {
console.log('Warf! Im ' + that.name); // meaning of "this" changed!!!
};
this.anotherMethod = function () {};
};
return Dog;
}());
var puppy = new Dog(1, 'puppy'); // sayHi and anotherMethod created
var sirius = new Dog(1, 'sirius'); // sayHi and anotherMethod recreated
sirius.sayHi = function () { console.log('Yohalolop!'); };
puppy.sayHi(); // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Yohalolop!'
So there is some problems with the above example, firstly methods are defined like any other instance variables. Actually yeah you define them as instance variable and this means this functions are recreated for every instance object you create. I guess you have mentioned you can't use this keyword in your method definitions. This is error prone and there is a chance to forget that and use this keyword by mistaken. There are some times you can use methods as instance variables of course like variable callbacks.
Let's see a sample class definition with prototype object:
var Dog = (function () {
var Dog = function (age, name) {
this.age = age;
this.name = name;
};
// sayHi method defined only once in prototype
Dog.prototype.sayHi = function () {
console.log('Warf! Im ' + this.name; // we can use this keyword
};
// anotherMethod defined only once in protoype
Dog.prototype.anotherMethod() {
};
return Dog;
}());
var puppy = new Dog(1, 'puppy');
var sirius = new Dog(1, 'sirius'); // sirius and puppy sharing same prototype object
puppy.sayHi(); // -> 'Warf! Im puppy'
sirius.sayHi(); // -> 'Warf! Im sirius'
// remember puppy and sirius sharing same prototype object
Dog.prototype.sayHi = function () {
console.log('Yohalolop');
};
puppy.sayHi(); // -> 'Yohalolop'
sirius.sayHi(); // -> 'Yohalolop'
As an answer to your question about private functions, it is more complicated. Yes you can use private functions even you define your methods on prototype, but there are some concerns about testing. Usage of them is up to you. I prefer to don't use. Let me show some examples.
var Calculator = (function () {
var Calculator = function () {
this.importantNumber = 2;
};
// There is unfortunately no native implementation
// for private methods but you can mimic them with
// unaccessible functions and binding.
var someExtremeComputations = function () {
return 40 + this.importantNumber; // this keyword points to instance because of binding
};
Calculator.prototype.getMeaningOfLife = function () {
var result = someExtremeComputations.call(this); // we bind function to instance
return result;
};
return Calculator;
}());
This is the one of the examples how you can define private methods in javascript. The problem with private functions, they can't be tested. There is no way to test someExtremeComputations method.
Some people (includes me) use prefixed underscore naming convention for private methods. So they are actually public methods but if someone calling them or overriding they were warned by prefixed underscore. After all we can test private methods since they are public in real.
var Calculator = (function () {
var Calculator = function () {
this.importantNumber = 2;
};
// private method's name prefixed by an underscore to warn
// other developers to be careful about that or not to use.
Calculator.prototype._someExtremeComputations = function () {
return 40 + this.importantNumber;
};
Calculator.prototype.getMeaningOfLife = function () {
var result = this.someExtremeComputations(); // no need to bind
return result;
};
return Calculator;
}());
Explaining this with a few words is impossible. A generally good pattern is to construct methods through prototypes when you want to optimize your code. A good guideline is to only put the most essential data in the memory, using prototypes is critical for this since the prototyped variables and methods isn't injected into the memory until you request them.
When it comes yo your example there are no prototypes.
Simple example
// new object
var Dog = function() {
var that = this;
// add a property
that.name = "Fido";
// add a method
that.getName = function() {
return that.name;
};
};
// ... all the above is stored in memory directly
// Requires to be constructed
var dogObj = new Dog();
console.log(dogObj.getName()); // Fido
delete Dog.name // false
typeof Dog.name // "string"
delete dogObj.name // true
typeof dogObj.name // "undefined"
typeof Dog.name // "string" (still there)
// Will be available in the dogObj (after you call it)
dog.prototype.first = "first";
// Will be available in the dogObj (after you call it)
dog.prototype.second = function() {
return "second";
}
// Will not be available in dogObj
dog.third = "third";

Is it possible to call an instance variable inside of a private function in javascript?

I have a function defined in javascript that acts as a class. Within it, I have several public methods defined, but there is one private method, and I need to access one of the public methods within it.
function myClass(){
this.myPublicMethod = function(a,b){
var i = a*b;
return i;
}
function myPrivateMethod(){
var n = this.myPublicMethod(2,3);
}
}
This doesn't work. Is there a way to access myPublicMethod within myPrivateMethod?
You simply have to specify the value of this when calling your private method using Function.prototype.call.
myPrivateMethod.call(this);
E.g.
function myClass(){
this.myPublicMethod = function(a,b){
var i = a*b;
return i;
}
function myPrivateMethod(){
var n = this.myPublicMethod(2,3);
}
//calling private method in the *scope* of *this*.
myPrivateMethod.call(this);
}
Please note that having true private members (that aren't functions) comes at the cost of not taking advantages of prototypes. For that reason, I prefer to rely on naming conventions or documentation to identify private members rather than enforcing true privacy. That holds only for non-singleton objects.
The following example demonstrates what is being said above.
//Constructors starts by an upper-case letter by convention
var MyClass = (function () {
function MyClass(x) {
this._x = x; //private by convention
}
/*We can enforce true privacy for methods since they can be shared
among all instances. However note that you could also use the same _convention
and put it on the prototype. Remember that private members can only be
tested through a public method and that it cannot be overriden.*/
function myPrivateMethod() {
this.myPublicMethod1();
}
MyClass.prototype = {
constructor: MyClass,
myPublicMethod1: function () {
//do something with this._x
},
myPublicMethod2: function () {
/*Call the private method by specifying the *this* value.
If we do not, *this* will be the *global object* when it will execute.*/
myPrivateMethod.call(this);
}
};
return MyClass;
})();
You can try this to defeat the local scoping:
function myClass(){
this.myPublicMethod = function(a,b){
var i = a*b;
return i;
}
// Capture the original context of `this` myClass
var self = this;
function myPrivateMethod(){
var n = self.myPublicMethod(2,3);
}
}
We use self to maintain a reference to the original this even as the context is changing (since we want to call the public method int the private method).
One way to do this is defining every method as private first, and making the ones you want public in the end (myPrivateMethod will reference the original myPublicMethod even if myClass.myPublicMethod is overridden):
function myClass(){
var myPublicMethod = function(a,b){
var i = a*b;
return i;
}
var myPrivateMethod = function (){
var n = myPublicMethod(2,3);
}
this.myPublicMethod = myPublicMethod;
}
You could write
var myPublicMethod = this.myPublicMethod = function()...
So there was a private and a public instance created.
Just seems cleaner to me.
You could potentially pass the public function to the private function as a parameter and then call it.
this.myPublicMethod = function(a,b){
alert(a * b);
}
function myPrivateMethod(publicMethod){
var n = publicMethod(2,3);
}
myPrivateMethod(this.myPublicMethod);
Here is a working fiddle.. http://jsfiddle.net/rxtB2/3/
An alternative to invoking call could be to attach the method directly to the myClass Function object.
function myClass(){
myClass.myPublicMethod = function(a,b){
var i = a*b;
return i;
}
this.myPublicMethod = myClass.myPublicMethod;
function myPrivateMethod(){
var n = myClass.myPublicMethod(2,3);
return n;
}
console.log("Calling myPrivateMethod()");
console.log(myPrivateMethod());
}
If you only want "private" methods then your pattern for defining it is wrong. I think methods that can access "private" methods are called privileged methods but can be wrong.
The pattern for creating them is the following (added instance variables and inheritance in the example):
// added to show inheritance
var Parent = function(){
//instance members
this.parentInstanceVar=["parent"];
};
var Class = function() {
//1st step to "inherrit" from Parent
// take ownership of Parent instance members
Parent.call(this);
//to pass all arguments to Parent constructor:
//Parent.apply(this,arguments);
//to pass specific agruemtns to Parent
//Parent.call(this,arg1,arg5);
this.someIntanceVar=["Class instance"];
};
Class.prototype=(function(parent){
var ret=(parent&&parent.prototype)?
Object.create(parent.prototype):
Object.create({});
//repair the constructor
ret.constructor=Class;
var myPrivateMethod = function() {
return this.someIntanceVar;
};
//privileged method calling "private method"
ret.myPriviligedMethod=function(){
return myPrivateMethod.call(this);
};
return ret;
}(Parent));//2nd step to "inherit" from Parent
//non privileged method
Class.prototype.nonPrivileged=function(){
//can't accesss myPrivateMethod here
};
//some tests creating 2 instances
var c1=new Class();
var c2=new Class();
c1.parentInstanceVar.push("added in c1");
c1.someIntanceVar.push("added in c1");
console.log(c2.parentInstanceVar);//=["parent"]
console.log(c2.someIntanceVar);//=["class instance"]
console.log(c1.myPriviligedMethod());//=["Class instance", "added in c1"]
console.log(c2.myPriviligedMethod());//=["Class instance"]
//reason why we repaired the constructor:
console.log((new c1.constructor()) instanceof Class);//=true
This pattern only handles instance shared private members. If you need instance specific private members you can't use prototype for any privileged methods (methods that need access to "private" instance specific members). You can use use a function that returns an object containing closures but I would really not use this pattern as it ignores prototype and the benefits that come with it, makes testing harder and is a huge pain to clone.
var createClass=function(privateInstanceVal){
var privateMethod=function(val){
privateInstanceVal.push(val);
return privateInstanceVal;
};
return{
publicInstanceVar:[],
publicMethod:function(val){return privateMethod(val);}
}
};
c1=createClass([]);
var b = c1.publicMethod(33);
console.log("b is:",b);
b.push("because I returned the private I made it public");
console.log(c1.publicMethod(0));//=[33, "because ... public", 0]
The sample shows a mistake sometimes made by returning "private" you made it public. Instead you can return a copy: return privateInstanceVal.concat([]);

In javascript, Is there a perfect way to define class

I am looking for a perfect way to define class. "perfect" here means:`
create instances will not create copies of methods.
public function could easily(not to much hassle) access private variable
For example, way 1:
function Foo1() {
var private1;
this.publicMethod1 = function() {//create instance will create copy of this function}
}
will not meet rule No.1 above.
Another example, way 2:
function Foo2() {
var private2;
}
Foo2.prototype.Method2 = function() {//cannot access private2}
will not meet rule No.2 above.
So is it possible to meet both rules? Thanks.
In JavaScript it's more about conventions. Private properties or methods are defined with a underscore first like _private. With a few helpers you can make classes easily. I find this setup easy enough, all you need is a helper inherits to extend classes, and instead of using multiple arguments you pass in an object props and simply call "super" on the inherited classes with arguments. For example, using a module pattern:
Function.prototype.inherits = function(parent) {
this.prototype = Object.create(parent.prototype);
};
var Person = (function PersonClass() {
function Person(props) {
this.name = props.name || 'unnamed';
this.age = props.age || 0;
}
Person.prototype = {
say: function() {
return 'My name is '+ this.name +'. I am '+ this.age +' years old.';
}
};
return Person;
}());
var Student = (function StudentClass(_super) {
Student.inherits(_super);
function Student(props) {
_super.apply(this, arguments);
this.grade = props.grade || 'untested';
}
Student.prototype.say = function() {
return 'My grade is '+ this.grade +'.';
};
return Student;
}(Person));
var john = new Student({
name: 'John',
age: 25,
grade: 'A+'
});
console.log(JSON.stringify(john)); //=> {"name":"John","age":25,"grade":"A+"}
console.log(john.say()); //=> "My grade is A+"
About the private variable "issue" just stick to convention for instance properties and use closures when needed for everything else private.
function Foo3() {
this.private = {};
}
Foo3.prototype.set_x = function (x) {
this.private.x = x;
};
To make a long story short: no, it is not. You cannot extend the prototype with methods that could access private variables. At least if these private variables are made private via a closure.
Though, it is a convention in javascript that you mark your private fields with an underscore, for example _myPrivateField. These would be still public, but i have seen this solution being used in many libraries and i also prefer that style to meet your first rule.
A basic example is below:
Foo = function(id)
{
// private instances.
var _id;
var _self = this;
// constructor
_id = id;
// private method
function _get()
{
return _id;
};
// public function
_self.set = function(id)
{
_id = id;
};
_self.get = function()
{
return _get();
};
};
var bar = Foo(100);
console.log( bar.get() );
bar.set(1000);
console.log( bar.get() );
I would recommend you use prototype.

how do i namespace pseudo-classical javascript

I have some simple OO code I've written that I'm playing with:
//define a constructor function
function person(name, sex) {
this.name = name;
this.sex = sex;
}
//now define some instance methods
person.prototype.returnName = function() {
alert(this.name);
}
person.prototype.returnSex = function() {
return this.sex;
}
person.prototype.talk = function(sentence) {
return this.name + ' says ' + sentence;
}
//another constructor
function worker(name, sex, job, skills) {
this.name = name;
this.sex = sex;
this.job = job;
this.skills = skills;
}
//now for some inheritance - inherit only the reusable methods in the person prototype
//Use a temporary constructor to stop any child overwriting the parent prototype
var f = function() {};
f.prototype = person.prototype;
worker.prototype = new f();
worker.prototype.constructor = worker;
var person = new person('james', 'male');
person.returnName();
var hrTeamMember = new worker('kate', 'female', 'human resources', 'talking');
hrTeamMember.returnName();
alert(hrTeamMember.talk('I like to take a lot'));
Now this is all well and good. But I'm confused. I want to include namespacing as part of my code writing practice. How can I namespace the above code. As it is now I have 2 functions defined in the global namespace.
The only way I can think to do this is to switch to object literal syntax. But then how do I implement the pseudo-classical style above with object literals.
You could for example do following:
var YourObject;
if (!YourObject) {
YourObject = {};
YourObject.Person = function(name, sex) {
// ...
}
YourObject.Person.prototype.returnName = function() {
// ...
}
// ...
}
You don't have to use object literals, at least, not exclusively.
Decide on the single global symbol you'd like to use.
Do all your declaration work in an anonymous function, and explicitly attach "public" methods as desired to your global object:
(function(global) {
// all that stuff
global.elduderino = {};
global.elduderino.person = person;
global.elduderino.worker = worker;
})(this);
I may not be completely understanding the nuances of your issue here, but the point I'm trying to make is that Javascript makes it possible for you to start with your symbols being "hidden" as locals in a function, but they can be selectively "exported" in various ways.

Encapsulation in javascript

I need to create simple reusable javascript object publishing several methods and parameterized constructor. After reading through several "OOP in JavaScript" guides I'm sitting here with an empty head. How on the Earth can I do this?
Here my last non-working code:
SomeClass = function(id) {
this._id = id;
}
(function() {
function intFun() {
return this._id;
}
SomeClass.prototype.extFun = function() {
return incFun();
}
})();
This is my usual approach:
MyClass = function(x, y, z) {
// This is the constructor. When you use it with "new MyClass(),"
// then "this" refers to the new object being constructed. So you can
// assign member variables to it.
this.x = x;
...
};
MyClass.prototype = {
doSomething: function() {
// Here we can use the member variable that
// we created in the constructor.
return this.x;
},
somethingElse: function(a) {
}
};
var myObj = new MyClass(1,2,3);
alert(myObj.doSomething()); // this will return the object's "x" member
alert(myObj.x); // this will do the same, by accessing the member directly
Normally the "this" keyword, when used in one of the object's methods, will refer to the object itself. When you use it in the constructor, it will refer to the new object that's being created. So in the above example, both alert statements will display "1".
An exception to this rule is when you pass one of your member functions somewhere else, and then call it. For example,
myDiv.onclick = myObj.doSomething;
In this case, JavaScript ignores the fact that "doSomething" belongs to "myObj". As a result, the "this" inside doSomething will point to another object, so the method won't work as expected. To get around this, you need to specify the object to which "this" should refer. You can do so with JavaScript's "call" function:
myDiv.onclick = function() {
myObj.doSomething.call(myObj);
}
It's weird, but you'll get used to it eventually. The bottom line is that, when passing around methods, you also need to pass around the object that they should be called on.
I usually don't worry too much about hiding the internals, although I do prefix them with underscores to mark them as not intended to be used outside the "class". Normally what I will do is:
var MyClass = function() {};
MyClass.prototype = {
_someVar : null,
_otherVar : null,
initialize: function( optionHash ) {
_someVar = optionsHash["varValue"];
_otherVar = optionsHash["otherValue"];
},
method: function( arg ) {
return _someVar + arg;
},
};
And use it as so...
var myClass = new MyClass( { varValue: -1, otherValue: 10 } );
var foo = myClass.method(6);
All vars are private:
SomeClass = function (id) {
var THIS = this; // unambiguous reference
THIS._id = id;
var intFun = function () { // private
return THIS._id;
}
this.extFun = function () { // public
return intFun();
}
}
Use THIS within private methods since this won't equal what you might expect.
From http://learn.jquery.com/code-organization/concepts/#the-module-pattern:
// The module pattern
var feature = (function() {
// private variables and functions
var privateThing = "secret";
var publicThing = "not secret";
var changePrivateThing = function() {
privateThing = "super secret";
};
var sayPrivateThing = function() {
console.log( privateThing );
changePrivateThing();
};
// public API
return {
publicThing: publicThing,
sayPrivateThing: sayPrivateThing
};
})();
feature.publicThing; // "not secret"
// logs "secret" and changes the value of privateThing
feature.sayPrivateThing();
So using returning an object that aliases its "methods" could be another way to do it.
I've read from http://www.amazon.com/Programming-Oracle-Press-Poornachandra-Sarang-ebook/dp/B0079GI6CW that it is always good practice to use getters and setters rather that accessing the variable directly from outside the object, so that would eliminate the need of returning variables by reference.
BTW you could just use this.variable to reference/declare a public variable and var variable to declare a private variable.
I know this is a late answer, but I hope it helps anyone who reads it in the future.

Categories

Resources