Javascript private variables and parameters have same name - javascript

function() {
var name;
this.set = function( name ) {
this.name = name; <-- this
}
}
How would I write the line so that I can assign the parameter to the private variable? Unlike Java, "this" also points to a function, so I can't figure it out.

You'll just have to use a different name for the argument so it won't shadow the private variable name outside the function set, that's all.
var SomeClass = function() {
var name;
this.set = function( otherName ) { // argument should have a diffirent name so it won't shadow the other variable "name"
name = otherName;
}
this.get = function() {
return name;
}
};
var ins = new SomeClass();
ins.set("Jim Carrey"); // OK
console.log(ins.get()); // OK
console.log(ins.name); // undefined as expected

Inside the function set, inner name variable will get more preference than the outer name variable. In order to assign some value to the outer variable, you will have to have a different name inside or outside.
However, You can do something like,
function() {
this.name = '';
this.set = function( name ) {
this.name = name; <-- this
}
}
This is not assigning the new value to the private variable, this is assigning the value to the object's property.

2020 edit:
I happen to come back to this question and realized that I was mistaken.
Better code example.
type = function() {
var name = "default";
var self = this;
this.set = function(name) {
console.log("this: " + this);
console.log("self: " + self);
console.log("name: " + name);
name = name; // <-- name shadowed
}
this.get = function() {
return name;
}
}
test = new type();
console.log("test.name: " + test.name);
console.log("test.get: " + test.get());
test.set("new")
console.log("test.name: " + test.name);
console.log("test.get: " + test.get());
I wanted to avoid name shadowing which can be done in Java by doing
this.name = name;
However, in Javascript, "name" is declared as a public property and initialized so that defeats the purpose of this thought-exercise.
"self" technique won't work either (this is where I mistakenly thought it would work)
The true answer is Aadit M Shah's comment in the first answer.
With the recent EcmaScript (or not so recent), Javascript lets you assign getter and setter to a property, so this technique is probably not needed.

Related

Get the public properties of a class without creating an instance of it?

Let's imagine that we have a JavaScript class:
var Person = (function () {
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.saySomething = function (something) {
return this.name + " " + this.surname + " says: " + something;
};
return Person;
})();
I want to iterate its methods and properties. I have no problem with the methods.
var proto = Person.prototype,
methods = Object.keys(proto);
// iterate class methods ["saySomething"]
for (var i = 0; i < methods.length; i++) {
// do something...
}
My problem comes when I want to iterate its properties:
var proto = Person.prototype,
targetInstance = new Person(), // this is my problem!
properties = Object.getOwnPropertyNames(targetInstance),
// iterate class properties ["name", "surname"]
for (var i = 0; i < properties.length; i++) {
// do something...
}
The only way that I have found is to create an instance and use Object.getOwnPropertyNames. I want to use this code as part of a framework so I will not have control over the classes defined by other developers. I want to avoid the need of creating an instance because if the constructor had some sort of validation like:
function Person(name, surname) {
if(typeof name === "undefined" || typeof surname === "undefined"){
throw new Error()
}
this.name = name;
this.surname = surname;
}
I wouldn't be able to use the code above. Do you know if it is possible to get the public properties of a class without creating an instance of it?
The properties don't exist until an object constructs them.
If your class looked like:
var Person = (function () {
Person.prototype.name = null;
Person.prototype.surname = null;
function Person(name, surname) {
this.name = name;
this.surname = surname;
}
Person.prototype.saySomething = function (something) {
return this.name + " " + this.surname + " says: " + something;
};
return Person;
})();
you would see name and surname too, but of course you can't count on the objects looking like that.
Do you know if it is possible to get the public properties of a class without creating an instance of it?
If you are talking about runtime them no, not without ugly hacks like toString (which gives you a string representation of the function body).
However you can get these at compile time using the TypeScript language service and then do code generation to assist the runtime (https://github.com/Microsoft/TypeScript/wiki/Using-the-Language-Service-API).
Neither of these are trivial.

javascript constructor function not giving correct result

i am a newbie to js.
i am trying to use constructor function to create an object.
here is my code
function player(name,age,rank)
{
this.name=name;
this.age=age;
this.rank=rank;
this.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
Now i am adding a new property like this
player.matchReady=true;
now i create an object like this
var kaka=new player("kaka",22,3,false);
And when i write this
document.write('kaka is match ready-->' + kaka.matchReady);
it gives me this output
kaka is match ready-->undefined
Why is it giving me undefined??
haven't i added a new property correctly??Please tell me.
Thanks.
Instead of player.matchReady=true;
Do, player.prototype.matchReady = true;
This way all players will have match ready default on true;
also you might want to put your function into the prototype.
player.prototype.sayEverything=function()
{
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
You can regard prototype as the scaffolding on which you outline all properties and functions an object should have when it's instantiated. All these default values will be the same for all objects.
When you add functions within functions all these functions get duplicated in memory when you instantiate a new object.
When possible and when there is no need for scoping, try to add generic functions like your sayEverything()(please rename that to toString() to keep in line with convention) to the prototype.
That way all the player objects can use the same function. Which is more memory efficient.
You cannot add a property to a class. You can always add the property as its prototype.
like this:
function player(name, age, rank) {
this.name = name;
this.age = age;
this.rank = rank;
this.sayEverything = function () {
return "The name of the player is " + this.name + "the age is " + this.age + "the rank is " + this.rank;
}
}
player.prototype.matchReady = true;
var kaka = new player("kaka", 22, 3, false);
alert('kaka is match ready-->' + kaka.matchReady);
working example: jsfiddle
Blog on prototype
If you add it to the prototype, all player will have the field.
player.prototype.matchReady = true;
If you only want a specific player to have the field, add it to that player variable:
var kaka = new player("kaka",22,3,false);
kaka.matchReady = true;// kaka has to come first
In the below example you can see what is private ,public,static and privileged variable or method .When ever you write property on Method itself like static variable,that variable wont be available for the instances.
Also whenever you are writing constructor function you should follow the Naming convention to help you differentiate from other function
/ Constructor
function Player(name) {
// Private
var dob= "17/04/1986";
// Privileged
this.getDOB = function () {
return dob;
};
// Public
this.name = name;
}
// Public
Player.prototype.getName = function () {
return this.name;
};
// Static property
Player.town = "South Park";

Why these closure based private variables in JavaScript not working

I am experimenting imitating OOP like behavior in JS. I am trying to have (private) variables: id and name in function Person. To this function I am passing arguments which are used to initialize (private) variables. Then I am returning object having getter and setter for name and only a getter for id, thus effectively making id read-only.
So id can be set only through constructor whereas name can be set and get anytime.
This is the code:
var Person = function (_id,_nm) {
var id, name;
this.id = _id;
this.name = _nm;
return {
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
document.writeln("Id: "+id+"<br />Name: "+name);
}
}
}
var person = new Person(123, "Mahesh");
person.print();
However when new Person(123,"Mahesh") executes, I dont understand it is actually setting id and name or not, since while debugging I can see values set appropriately when hovered over them but Locals panel does not show them initialized:
Or either while in print() is is not referring to the desired id and name variables:
Whats wrong here?
Working fiddle
The reason is because you are using public members for the Person.prototype. You don't need to add this references to these two. So delete:
this.id = _id;
this.name = _nm;
and simply use:
var id = _id,
name = _nm;
Now everything will work fine. The whole idea is to use var, and not this, otherwise a closure will not be created. Now you will not be able to access name and id directly, instead you will have to use setName(), getName(), setId(), getId() etc.
The two members, id and name, will now become closures as you want them to be.
Update
If you used this.id, then it wouldn't have been private and you could just do var p = new Person(1, "Mahesha"); and access p.name or p.id directly. They are supposed to be private so this is not what you want.
With the closure pattern, p.name and p.id are undefined and can only be accessed through p.getName(); and p.getId();. Read on how closures work. The idea is that because you are using that var name, a closure will be created to remember it's value.
Your getName and setName are using that closure to access the name property. There is no this.name, there is a value remembered through a higher - order closure.
this.id and var id are not the same. this.id is a property of the object. var id belongs to the local scope.
Either use new or return a value. Not both.
The problem is that you're creating a new instance of Person using the new keyword, but your constructor function is returning another object instead.
When you return something from a constructor function it returns that value, and not the instance of the function.
You see when you execute new Person(123, "Mahesh") a new instance of Person is created. This is accessible within the constructor function as this.
If you don't return anything from your constructor then JavaScript automatically returns this. However you're explicitly returning another object.
No wonder var person doesn't have id and name properties (which you only defined on this).
In addition print doesn't display the id and name because although you declared them (var id, name) you didn't give them any values. Hence they are undefined.
This is how I would rewrite your Person constructor:
function Person(id, name) {
this.getId = function () {
return id;
};
this.getName = function () {
return name;
};
this.setName = function (new_name) {
name = new_name;
};
this.print = function () {
document.writeln("Id: " + id + "<br/>Name: " + name);
};
}
I didn't set the id and name properties on this because it makes no sense to include them.
You've mixed up using locally scoped ("private") variables for _id and _nm and "public" instance properties (this.id and this.nm).
In this case you need the former, but you created both and only initialised the latter.
Note that since id is read-only you don't really need a separate local variable at all, you can just use the lexically scoped first parameter to the constructor:
var Person = function (id, _nm) {
var name = _nm;
...
};
Let me try to explain using the following:
// Scope 1
var Person = function (_id,_nm) {
// Scope 2
var id, name;
this.id = _id;
this.name = _nm;
return {
// Scope 3
setName: function (nm) {
name = nm;
},
getName: function () {
return name;
},
getId: function () {
return id;
},
print: function () {
$("#output").append("<p>Id: "+id+"; Name: "+name + "<p/>");
}
}
}
The print method will return undefined because you are referring to the var id, name; that is never set in your code. You set the _id and _name to the property id and name but you fail to return the object that you just created. Instead, you return a dictionary, that references the name and id variable you created in Scope 2 that you never set, hence the undefined output in the print() call.
Here is what you should have done:
var NewPerson = function (_id,_nm) {
var self = this;
this.id = _id;
this.name = _nm;
this.print = function () {
$("#output").append("<p>New Person Id: "+this.id+"; Name: "+ this.name + "<p/>");
};
return this;
};
var nperson = new NewPerson(456, "Marcos");
nperson.print();
This will output:
New Person Id: 456; Name: Marcos
In essence, new is creating a new object represented by this, and you must return this to have a reference to the object created. In fact, if you do not use the new before creating an object, you end up referencing a global instance of this. Try the following:
var nperson = new NewPerson(456, "Marcos");
this.name = "Hello";
nperson.print();
var nperson1 = NewPerson(456, "Marcos");
this.name = "Hello";
nperson1.print();
You will see that the first output will be as expected:
New Person Id: 456; Name: Marcos
But the second will pick up the change made to this.name:
New Person Id: 456; Name: Hello
Here is the JSFiddle.

How do I set up a javascript Class with inheritance + private properties + getters / setters

I wish to use https://github.com/mozilla/BrowserQuest/blob/master/server/js/lib/class.js with private inheritable properties and also some getters and setters in there.
Basically I want the getter / setter to modify a private property and subclasses to inherit the setter, getter and the private property of course.
This is what I got so far:
var Person = Class.extend({
init: function( name )
{
var name = "~";
this.myName = name;
return {
set myName( value )
{
name = value + " +?";
},
get myName()
{
return name + "^^^^^^^^^";
}
}
}
});
var c = new Person( "cheese" );
console.log(c.myName);
c.myName = "zoom";
console.log(c.myName);
Trace:
undefined
zoom
Its weird, my editor (Webstorm) sees c.myName as the setter/getter but the compilers consider it an undefined public property :(
Any help would be appreciated. This is Nodejs but I think the issues is javascript.
I'm assuming Node.js or any other environment where the whole EcmaScript 5 is available.
The only way to have true private data in JavaScript these days is to keep a variable in the constructor, which is what you're doing. However, you're confusing the use of return in the init function. While the init function is pretty much the constructor, it is not being called exactly as such, so return does nothing. Even if it did something, what you want is to add a property to this, not return a new object. So basically you'd have to change that return to Object.defineProperty:
init: function (name) {
// notice that the private variable has a different name
// than the parameter
var privateName = '~';
Object.defineProperty(this, 'myName', {
set: function (value) {
privateName = value + " +?";
},
get: function () {
return privateName + "^^^^^^^^^";
}
});
this.myName = name;
}
This still has a limitation in inheritance. If you wanted to inherit from the Person class and modify the getters and setters you'd have to get the property descriptor, modify it and redefine the property. That's painful. And it doesn't support accessing the "super getter/setter". In order to avoid that what we usually do in JavaScript is to forget about having true privates and use privates by convention, starting the private property's name with _. Then you can simply define your getters and setters in the prototype like this:
var Person = Class.extend({
init: function(name) {
// the private name property
this._name = '~';
this.myName = name;
},
set myName(value) {
this._name = value + " +?";
},
get myName() {
return this._name + "^^^^^^^^^";
}
});
This will let you access the super getter/setter when using inheritance.
There is a cutting edge feature that would let you have both true privates and inherit getters and setters: WeakMap. WeakMap is basically an object with creates a relationship between two other objects that doesn't count for garbage collection. That last part is important for memory management and that first part is the one that lets you have true privates. You can try WeakMaps in Beta versions of Firefox and in Node.js with a --harmony_collections flag. Here's how it would work:
function privatize() {
var map = new WeakMap();
return function (obj) {
var data = map.get(obj);
if (!data) {
map.set(obj, data = {});
}
return data;
};
}
var Person = (function () {
var _private = privatize();
return Class.extend({
init: function(name) {
// the private name property
_private(this).name = '~';
this.myName = name;
},
set myName(value) {
_private(this).name = value + " +?";
},
get myName() {
return _private(this).name + "^^^^^^^^^";
}
});
}());

JS: OOP private functions / private fields [duplicate]

This question already has answers here:
A way to encapsulte ( add privacy ) to models in the MVC?
(2 answers)
JavaScript private methods
(34 answers)
Closed 8 years ago.
Systemname =
{
Question :
{
send: function()
{
console.log("send");
},
read: function()
{
console.log("read");
},
delete: function()
{
console.log("delete");
}
},
Answer :
{
send: function()
{
console.log("Answer sent");
}
},
Person :
{
foo: 'foo',
bar: 'bar',
add: function(name)
{
console.log('person "' + name + '" added');
},
remove: function(id)
{
console.log('person with id "' + id + '" removed');
}
}
}
i'm learning how oop works in js and i'm a bit confused now about private methods and fields. i'd like to have some private member in the person section such as 'personCount' or 'lastAddedPerson'. if i add them like this:
Person:
{
personCount: 0,
lastAddedPerson: '',
...
}
at the beginning of the person section, the fields are public and can be called with Systemane.Person.Field.... how can i set them private? and the same for a method.
thx for your help.
Here is one way.
function Person(n) {
var name = n;
this.getName = function() {
return name;
}
this.setName = function(newName) {
name = newName;
}
}
var person = new Person('roman');
You can't have private properties or methods when you create objects using literals. In fact, there are no private properties in JavaScript, but you can achieve that in practice by using a constructor function, and declaring the private properties and methods as variables:
function Person() {
var privteProperty = 1;
var privateMethod = function(){}
this.publicProperty = 2;
this.publicMethod = function(){}
}
Then you can create an instance with:
var john = new Person();
I like using a sort of factory pattern instead of new:
var Person = (function() {
return {
create: function(name) {
return (function(n) {
var name = n;
function getName() {
return name;
}
function setName(newName) {
name = newName;
}
return {
getName: getName,
setName: setName
};
}(name));
}
};
})();
Then:
var person = Person.create("Bob");
person.getName(); //returns Bob
person.setName("Jimbo");
person.getName(); //returns Jimo
Seems complex, but is pretty simple.
Person is essentially assigned the return value of an anonymous self-invoked function. This return value has a single property called create, which is a reference to another function, which more-or-less acts like a constructor. This function also returns the return value of another anonymous self-invoked function. However, this return value is the actual instance of the object that you want. Inside this anonymous self-invoked function, you can see that I have a variable called name. This variable is private to that anonymous self-invoked function and lexically bound to the scope in which it is defined. What this means is that the value of name is preserved inside that function. Basically it hangs around even after the function is done executing. The only way you can access or modify that variable is through the getName and setName functions.

Categories

Resources