Encapsulation / Data Hiding in Javascript? - javascript

I would like to understand the concept of Encapsulation in JavaScript, and how to make my properties and methods public or private.
I'm playing around with this example:
var person = function(newName, newAge) {
// Private variables / properties
var name = newName;
var age = newAge;
// Public methods
this.getName = function() {
return name;
}
// Private methods
var getAge = function() {
return age;
}
// Public method, has acces to private methods
this.giveAge = function() {
return getAge();
}
}
var jack = new person("Jack", 30);
console.log(jack.name); // undefined
console.log(jack.getName); // Jack
console.log(jack.getAge()); // TypeError: jack.getAge is not a function
console.log(jack.getAge); // undefined
console.log(jack.giveAge()); // 30
So, variables var name and var age are private. To access them I use public methods by using .this reference. So anything that is var inside my function is private, and anything that's .this inside my object is visible outside.
I guess that's cause person is visible, so it exposes all of its properties.
Am I on the right track? Is this the right way to hide or expose your properties / methods?
And one more question, why does console.log(jack.getAge()); throws an error? And when referencing functions I "stored" in variables, should I put () at the end of that function, it works both ways, so I don't know what do use?
Thanks!

I guess that's cause person is visible, so it exposes all of its properties.
Correct.
Am I on the right track? Is this the right way to hide or expose your properties / methods?
If you want to do it, then yes, this is a fairly standard way to do it. There's at least one other way as of ES2015, but with (probably) more overhead.
And one more question, why does console.log(jack.getAge()); throws an error?
Because the jack object doesn't have a getAge property, so jack.getAge yields undefined, which isn't a function. There's a getAge variable inside the context that the giveAge closure has access to (along with age and name), but jack doesn't have a getAge property.
And when referencing functions I "stored" in variables, should I put () at the end of that function, it works both ways, so I don't know what do use?
No, it doesn't work both ways. jack.getName gets a reference to the function. jack.getName() calls the function and gets its return value.
I should note that there's no point to the getAge function. It's only accessible to closures defined within the person function, just like age and name are. So anything that would use getAge would just use age instead and avoid the function call.
Just for completeness, I'll note that many people don't worry about truly private properties in JavaScript, opting instead for "private by convention" — e.g., they use a naming convention (such names starting with _) to mean "don't touch these, they're private." That doesn't do anything to prevent people using them, of course, it just indicates that they shouldn't. Folks advocating this usually point out that in many languages with "true" private properties/fields (Java, C#), those properties/fields are accessible with only a small amount of effort via reflection. And so, the argument goes, just using a naming convention is "as private."
I'm not agreeing (nor particularly disagreeing) with that, it does require rather more work in Java or C# to access private properties than public ones. I'm just noting that the "private by convention" approach is quite common, and frequently "good enough."

I guess that's cause person is visible, so it exposes all of its properties.
not exactly. First of all, person is a regular function. it can perfectrly be called without the new-keyword, but the results will blow up your whole application.
To understand why, you should first understand what the new-keyword does behind the scenes. This would be an js-implementation:
function fakeNew(constructor, ...args){
if(typeof constructor !== "function"){
throw new TypeError(constructor + " is not a constructor");
}
//create a new Instance of the constructors prototype-property
var instance = Object.create(constructor.prototype);
//invoke the constructor with the scope set to the instance and the provided arguments
var result = constructor.apply(instance, args);
//check wether the returned value is an Object (and functions are considered as Objects)
if(result === Object(result)){
//then return the result-value in favor to the instance
return result;
}
//otherwise return the instance
return instance;
}
On the other hand, any function can also be a constructor; no special needs, it's all up to you.
So back to jack
var jack = person("Jack", 30); //would result in the following desaster:
console.log(jack); //undefined, since person doesn't return anthing
console.log(jack.getName());
//will throw, since jack is still undefined, and therefore doesn't have any properties
//BUT:
console.log(window.getName()) //will return "Jack" now
console.log(window.getAge); //undefined, but this is fine
//global scope has not been polluted with this one, cause getAge was a local variable inside the function-call
console.log(window.giveAge()) //can still call the enclosed (private) function getAge()
then
var jill = person("Jill", 28);
//will overwrite the global functions and expose new values now
console.log(window.getName(), window.giveAge()) //"Jill", 28
//and Jack is kind of gone, well the variable is left but the variable contained undefined, so...
next thing is scoping. let's assume you made this correct
//first let's add a function that executes on the scope
//inside the constructor
this.getNameAndAge = function(){
return this.getName() + ": " + getAge();
}
.
var andy = new person("Andy", 45);
var joe = new person("Joe", 32);
//let's make Andy a little younger
andy.getNameAndAge = joe.getNameAndAge;
console.log(andy.getNameAndAge(), andy.getName() + ": " + andy.giveAge());
//will result in "Andy: 32", "Andy": 45
waaaaat?
well you've overridden the public method getNameAndAge.
the name is accessed by invoking the (also public) method getName() on the current Object.
but giveAge() still the enclosed variable from the scope where this specific "instance of the getNameAndAge-function" was declared, and therefore it's from Joe's function call.
To understand the impacts of this, let's make the scoping even more weird
funciton Animal(species, _name){
//species is likewise a local variable and can be enclosed, modified, or whatever
//we don't need to write it to some different variable
//but we want to expose the name of this animal, since it should be possible to change it later
//without the need to create a getter and a setter just to change the property of _name
this.name = _name;
this.whoAreYou = function(){
//so we concat the enclosed value from species with the name-argument on this object
//in the hope that everything will be alright.
return species + " " + this.name;
}
}
var jack = new Animal("dog", "Jack");
var jill = new Animal("cat", "Jill");
var joe = new Animal("fish", "Joe");
console.log(jack.whoAreYou()); //"dog Jack"
console.log(jill.whoAreYou()); //"cat Jill"
console.log(joe.whoAreYou()); //"fish Joe"
//as far so good; till now ...
//since these properties are still writable someone will start and move them around
//maybe like a callback
function someFunction(someArg, callback){
console.log(someArg, callback());
}
someFunction("Who are you?", jack.whoAreYou);
//or sth. like this:
//you may not believe that someone would ever do that, but it will happen!
jack.whoAreYou = jill.whoAreYou;
console.log(jack.whoAreYou());
//and now the poor dog has an Identity-crisis.
//the first one will result in:
"Who are you?", "dog undefined"
//the latter will log "cat Jack"
or even more fummy if sth. like this happens:
var fn = joe.whoAreYou;
console.log(fn.call(jack), fn.call(jill), fn.call(joe), fn.call(Animal));
//cause now they are all fishes, even the Animal-constuctor
I don't want to say that this is bad, or that you should avoid it but there is the way that it works, and that should be considered.
cause this way provides us with prototypal inheritance, and a great way to write mixins, without writing wrapper-methods all the time.
You can look at that as "i need to secure my private state", or "I work in whatever enviorment you provide to me"
And one more question, why does console.log(jack.getAge()); throws an error?
because jack.getAge is undefined and undefined is no function
var getAge = function() {
return age;
}
another comment to this line
in JS function- and variable-declarations are hoisted and therefore available from the beginning of the function. Expressions are not.
var person = function(){
//...
foo();
bar();
baz();
function foo(){ console.log("this will work"); }
var bar = function(){ console.log("this will fail"); }
//because to this point, bar was delared and assigned with undefined,
//and we remember? undefined can't be invoked
return whatever;
function baz(){ console.log("event this would work"); }
//unless some preprocessor decided (falsely), that this function can be removed
//since it is after the return-statement, and is therefore unreachable
}

Related

How to access a variable using new Person(name, description)?

While looking at the Cookie Clicker source code I noticed a peculiar system of Game objects, he used new Game.Building("cursor"...). I then decided I would test this with my own code so I did the same thing with a basic user variable.
AI.User = function(username, password) {
try {
this.username = username;
this.password = password;
this.setUsername = function(username) { this.username = username; };
this.setPassword = function(password) { this.password = password; };
this.getUsername = function() { return this.name; };
this.getPassword = function() { return this.password; };
this.GetUserByUsername = function(username) { };
return true;
}
catch(err) {
console.log(err);
return false;
}
};
new AI.User("John Smith", "JSmith42");
The problem is I do not know how to access the variable created.
Object-Oriented Programming in JavaScript
When you use a function with the new operator (i.e. as a constructor), it essentially wraps the function in a little extra code to create a new object, which it sets to this, and then returns that object at the end. **So to save the results of the call, you just assign it to a variable, like var myUser = new AI.User("John Smith", "JSmith42");
Getting into the details, you could think of it sort of like this. The code I'm about to give isn't a perfect match for what actually goes on behind the scenes, but it covers the basics:
function constructObject(constructor) {
var newPrototype = constructor.prototype || Object.prototype,
newThis = Object.create(newPrototype),
constructorResult;
constructor.apply(
newThis,
Array.prototype.slice.call(arguments, 1)
);
if (constructorResult !== undefined) {
return constructorResult;
}
return newThis;
}
When you call "new Constructor(a, b, c)", it's essentially like calling "constructObject(constructor, a, b, c)" as I mention here.
"Object.create" in line 2 creates a brand-new object, whose prototype is equal to whatever we pass in. Note that newPrototype gets picked up from from either constructor.prototype or, if that doesn't exist, Object.prototype. This "newPrototype" object then becomes the prototype of the object that we pass around.
"constructor.apply" then calls the constructor, with our newThis object set to this for that call, and passes in whatever other arguments we might have but leaves the constructor out. We save the return value of the function, even though it's bad practice for constructors to return anything.
Here's a gotcha: if for some reason the constructor returned an object, then we return that instead of the object we made. Otherwise, we return our new object. This is one of the big points where my code isn't a perfect match for what really happens, because the engine has better ways to examine what was or wasn't returned.
It's not good practice to use new without saving the result in a variable. It works, but it looks really strange, and I suspect this is part of why you were confused when you saw it.
Object-Oriented Programming in Cookie Clicker
Cookie Clicker essentially implements its own simple "OO-like" system on top of JavaScript's. There are three kinds of objects: Game.Object, Game.Upgrade, and Game.Achievement. There's no inheritance, prototypal or otherwise, but because it works through a series of callback functions, there's still a kind of polymorphism.
The new operator works just like it does in standard JavaScript. The key is that all three of the basic constructors save a reference to this every time they're called, in one of three lists within the Game object. That's how Cookie Clicker keeps tabs on the objects it creates without saving them in variables: it actually does, just not "in the open". The end result is almost like a kind of table (among other things, as the Game object is huge).
It is probably not a good idea to imitate this style. It reads like no other JavaScript code out there, which is probably a large part of why it confused you so much. Orteil himself seems to be moving away from it: the source code to Idle Game Maker (his follow-up engine) bears a strong resemblance to Cookie Clicker's, but the object system is gone. This is black magic: it's an interesting study in the esoteric details of JavaScript, but not something you should actually practice.
Which, given the themes of Cookie Clicker, is entirely appropriate.
If you're asking why create a variable like that, it's because it's a constructor for that variable. Instead of creating a User object with no name or password and setting it later, you can just call the constructor and fill in the proper parameters with the values you pass in.
This is a simple way to use OO style in javascript.
You can refer to this post if you like to read more.
You need to capture the result of the new expression in a variable:
var user = new AI.User("John Smith", "JSmith42");
console.log(user.getUsername();); // outputs "John Smith"
Note that you can also use a function's .prototype property to create your getters and setters once, rather than having to re-create them every time someone creates a new object. Here's an example of that from an article I wrote:
function Person(first, last)
{
this.first = first;
this.last = last;
}
var john = new Person("John", "Doe");
var mary = new Person("Mary", "Deer");
Person.prototype.full = function() {return this.first + " " + this.last;};
alert(john.full()); // "John Doe"
There are a lot of things happening here.
We create a function, which will set properties on its this object when called.
We create two separate instances of that function by putting the new keyword before our function calls. This ensures that john and mary refer to completely separate objects, each with their own first and last properties.
We create a new function and assign it to the full property on our Person function's prototype property. The prototype property exists on all functions, and allows you to define fall-back properties that should exist on every object created from that function.
We call the full() function on john. JavaScript sees that the john object doesn't actually have a full function on it, so it looks for a Person.prototype.full() function and calls that instead. Within that call, however, this still refers to the john object.

Accessing variables in a constructor function using a prototype methode

Why can't i access the variable HTML in the constructor function using the prototype method .nextSlide?
function test(root){
var HTML = getAllHTML();
function getAllHTML(){
var boss, expoHTML;
var boss = document.querySelector(root);
expoHTML = {
slides: boss.querySelectorAll(".slide"),
prev: boss.querySelector(".control.prev"),
next: boss.querySelector(".control.next"),
current: boss.querySelector(".slide-current"),
total: boss.querySelector(".slide-total")
}
return expoHTML;
}
}
EXPOjs.prototype.nextSlide = function(){
alert(HTML.current)
}
var newTEST = new test(".ieps");
newTEST.nextSlide();
It's a "scope" problem; every variable in Javascript has a scope, which means: "who can see this variable"?
In your case, HTML is defined in the function test(). This means that it will be visible:
Within the function test()
Within any functions defined within test()
That's it. Outside test(), HTML will be empty.
Now, I can see that you are using test() as a constructor function. With this, you enter the wonderful world of object creation and Javacript. Take a deep breath :D
When you do this:
function Person( age ){
this.age = age;
}
And then you do:
var pavlo = new Person( 23 );
Basically "new" has the effect of:
Creating an empty object
Running your function so that this points to the newly created object
Assign the newly created object to pavlo
This trickery means that you can do
var pavlo = new Person( 23);
console.log( pavlo.age );
And then there are prototype functions.
If you define a function like this:
Person.prototype.setAge = function( newAge){
this.age = newAge();
}
Any function (or any variable for that matter) defined in Person's prototype object will also be accessible to any object created using that constructor. Plus, the this variable will be the object making that call.
So, if you have:
function Person( age ){
this.age = age;
}
Person.prototype.setAge = function( newAge){
//`this` at this point is the object "calling" <-- This will throw an error if left uncommented.
this.age = newAge();
}
var pavlo = new Person( 23 );
console.log( pavlo.age );
// pavlo is making the call. So, within `setAge()`, `this` will be `pavlo`
pavlo.setAge( 26 );
So, for your solution:
function test(root){
this.HTML = getAllHTML();
// etc.
}
And then your alert should be:
test.prototype.nextSlide = function(){
alert(this.HTML.current);
}
Note that in Javascript you should have constructor functions starting with a capital letter (see: Test rather than test).
If you don't want HTML to be accessible from the outside, convention says that you normally put an underscore in front of the variable's name (call it _HTML ).
There are other ways of doing it, if you absolutely have to keep that variable hidden away from the developers. However, it's not exactly straightforward and -- most developers would say -- definitely not worth the effort.
A couple of good reads (but, I must say that I read them when I was starting with JS, and they confused the hell out of me at the time :D )
http://javascript.crockford.com/private.html (you know crockford, right? :D )
http://phrogz.net/JS/classes/OOPinJS.html (read it only when you have really understood the previous article)
UPDATE: This is another fantastic article on this matter: https://blog.jcoglan.com/2012/01/19/the-cost-of-privacy
Enjoy!
You're trying to access the property inside Test, but test is not part of Expojs. Then you're trying to extend the prototype of Expojs which is a bad idea because it's never a good idea to create new members for code which you don't control.
If you want nextSlide to be part of Test then you have to use Test.prototype.nextSlide(), which would create a new prototype member for the test object called nextSlide(). Then the public instance members would be accessible, such as this.getallHTML = function(){//usual stuff};
You need to use this keyword for the variables you want to access on a basic level.
After that there is the issue of abstraction which you have to consider if you want to protect the code from being used wrongly by others.
I've just been doing lots of tutorials on object orientation in JavaScript and as you can see I've learnt loads on this so far (still learning so I may not have everything right here), but I recommend doing some more study.

Why can`t I redefine function's prototype from within itself

I am trying to implement a way to achieve inheritance in JavaScript. First I define the base class, as follows:
function Person(name){
name = name + "!"; //I want to reuse this code for initialization
this.getName = function(){
return name;
};
this.setName = function(_name){
name = _name;
};
};
Then I define the sub class. Happens that I need a way to call the base class constructor. Ideally I would call it from within VipPerson constructor, when I still have a reference for name param. But if I do it from that point it simply does not work and if I try to access getName from base class I get an error that VipPerson has no getName method.
function VipPerson(name, vipLevel){
this.getVipLevel = function(){
return vipLevel;
};
//the line below would not work!
//VipPerson.prototype = new Person(name);
};
VipPerson.prototype = new Person(); //but this would. not ideal IMO
The drawback for me to set the prototype from outside the VipPerson is that I lose any reference to the parameter were passed.
Is there an elegant way to solve this? I would like to have this clean interface:
var foo = new Person("Foo");
console.log(foo.getName());
var bar = new VipPerson("Bar", 100);
console.log(bar.getName()); //error
console.log(bar.getVipLevel());
function VipPerson(name, vipLevel){
Person.call(this, name);
this.getVipLevel = function(){
return vipLevel;
};
};
VipPerson.prototype = Object.create(Person.prototype);
See:
https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/create/
However, I would avoid create closures just to make "privates" variables, unless there are specific security issues. JavaScript is a dynamic language with OOP prototype based, shouldn't be used like a class-based language with privates members.
I suggest to you to reading articles like that one: https://developer.mozilla.org/en/Introduction_to_Object-Oriented_JavaScript
It sort-of works when you set the prototype from inside the constructor, but it doesn't do what you really want. Because the setting of the prototype object is made until you're already running the constructor, the first newly created object (this) in thefirst call to the "VipPerson" constructor will not be "wired up" properly.
However, if you call the constructor again, you'll note that the prototype is there and that ".getName()" works.
Note that unless you want all your "Person" objects to share the same name, it's not going to work either way. "Person" should be set up such that "setName()" updates this.name and not a variable in the closure. There'll only be one "Person" instance for all the "VipPerson" instances — that being the instantiated prototype object.
Have you tried this approach?
function VipPerson(name, vipLevel){
this.__proto__ = new Person(name);
this.getVipLevel = function(){
return vipLevel;
};
};

JS Private methods not redefined at each constructor call

How do you make a Javascript private method that is not redefined each time you call the constructor ?
As far as I know, in OOP-JS, private methods are methods defined in the "constructor method" of one's "class", called each time one instantiates a new "object". I was thinking maybe a function declaration (i.e. function name(), as opposed to function expression var name = function()) would do the trick, but how can I be sure that the following code only declares my function once ?
​function Tester() {
function test () {
console.log("executed");
}
}
var t1 = new Tester();
var t2 = new Tester();
How do you make a Javascript private method that is not redefined each time you call the constructor ?
You can't (well, see below for a bit of wiggle room). But unless you're going to have thousands of instances of Tester, don't worry about it too much; most engines probably reuse the underlying code across the multiple function objects that get created. (The code, mind; not the function object or the context it closes over, which must be unique and allocated each time. But they need not be large. Of course, quite a function functions are fairly small as well...)
...how can I be sure that the following code only declares my function once ?
You can be sure that it doesn't; it declares the function each time Tester is called. Witness:
​function Tester() {
this.test = test;
function test () {
console.log("executed");
}
}
var t1 = new Tester();
var t2 = new Tester();
console.log(t1.test === t2.test); // "false"
Note that you can have functions that are private to the implementation, but not assigned to any instance of the object. The module pattern is handy for doing that:
var Tester = (function() {
function Tester(name) {
this.name = name;
}
Tester.prototype.publicFunction = function() {
privateFunction.call(this);
};
function privateFunction() {
console.log("My name is " + this.name);
}
return Tester;
})();
var t = new Tester("Fred");
t.publicFunction(); // Outputs "My name is Fred" via the private function
There, privateFunction is completely private, accessible only to the code within the anonymous function. And there's only one copy of it, but you can call it as though you were calling a method of a Tester instance using privateFunction.call(this).
Alternately, of course, since using call is slightly slower than doing a normal call, you could just pass the instance as an argument:
var Tester = (function() {
function Tester(name) {
this.name = name;
}
Tester.prototype.publicFunction = function() {
privateFunction(this);
};
function privateFunction(t) {
console.log("My name is " + t.name);
}
return Tester;
})();
var t = new Tester("Fred");
t.publicFunction(); // Outputs "My name is Fred" via the private function
Of course, the extra cost of call is only a problem if and when it's a problem; unless you're calling something hundreds of thousands of times in a tight loop, it's unlikely to matter. So whether to use call and this or pass an argument would be primarily a style choice.
It took me a while (coming form an ActionScript 3 background), but I feel that I should share with you how I learned to stop worrying and love the lack of private methods ;)
Many popular JavaScript libraries, such as Backbone.js and js-Signals simply make use of a naming convention where a leading underscore denotes private members as opposed to using slightly esoteric syntax (although each to their own!). Just to give this some additional context, Python's documentation goes as far as saying that Python does not support private members at all and suggests using an underscore instead.
JavaScript is a very dynamic language; there's no strict type checking and some really exciting scoping; and there are some really cool libraries out there which take advantage of those facts, such as SinonJS which makes it effortless to achieve meaningful test coverage in your codebase; for example:
var instance = new Car("ford");
// Replace the car's engine with test stub.
// Alternative syntax: sinon.stub(instance, '_engine');
instance._engine = sinon.stub(instance._engine);
car.start();
// As the '_engine' object has been mocked it gains new attributes.
ok(instance._engine.checkOil.calledOnce, 'Oil level was checked');
Sorry this answer doesn't really answer your question (T.J's answer is pretty much textbook in that regard) - I just thought it would be worthwhile to offer another possible solution.

Which method of creating javascript objects is better?

I've seen objects defined in two different ways, which function similarly, but are, of course, fundamentally different. You can do it either like this:
var myobject = {property: 'hello',
act: function() {
this.property += ' world';
}};
and like this:
function myobject() {
this.property = 'hello';
this.act = function() {
this.property += 'world';
}
}
The second method could create objects like so
var newobj = new myobject();
but you could do something similar using the first notation by making the object the return value of a function. The new keyword has the advantage of being able to pass parameters that can be used to initialize the properties of the object, but you could just as easily add an init function to the first kind of object.
Just wondering if besides these two differences, if there was a fundamental difference that made one method definitely better than the other method.
The second is better because you can reuse it. In addition, the constructor property of the constructed object is different in each case.
That aside, the second method wastes space by allocating a new function to the act property each time you call the constructor. (Note that the first method also wastes space in the same way.) Use prototypes instead:
function MyConstructor () {
this.property = 'hello';
}
MyConstructor.prototype = {
act: function () {
this.property += 'world';
}
};
MyConstructor.prototype.constructor = MyConstructor;
var obj = new MyConstructor ();
var f = function () {};
function g () {}
if (typeof(f) === typeof(g)) {
alert(typeof(f) + "\n" + f + "\n" + g);
}
The types are identical and variable f has an anonymous function assigned to it. Since f is a named variable with a function as its value it is a function that is not anonymous. JavaScript is a lambda language of downward inheritance that allows accidental creation of global variables. With regard to complex instances of inheritance where closures are used across the variance namespace scopes you have to be sure where your variables are defined to prevent collisions, especially with consideration for reuse. The first convention forces strict awareness of variable declaration, because the function must be declared before it can be executed. The second convention supplies no such awareness, which is potentially problematic with regards to instantiation and invocation as closure in complex logic prior described. Fortunately, JSLint is smart enough to throw an error when a function is used before it is declared. Since the two conventions are identical in representation I would suggest only using the one that is not open to abuse from flawed and sloppy programming.
In summary if g and f are both named variables with a function as assignment then always do it the right way using the first convention where you declare your variable using the var keyword.
javascript:
canDo="b:c=function(){}";
canNot="function a:d(){}";
eval(canDo);
alert(["Can do ",canDo,
".\n\n\nConfirmed result is: \n\n b:c=",
eval("b:c")
].join(""));
alert(
confirm(
"Click OK to confirm this is not valid (can NOT do):\n\n" + canNot) ?
eval(canNot) : "Test will fail if attempted and 'a:d' will not exist."
);
displays, in FireFox:
Can do b:c=function(){}.
Confirmed result is:
b:c=function () {
}
and
Click OK to confirm this is not valid (can NOT do):
function a:d(){}
which gives a runtime error if OK is chosen.

Categories

Resources