i need to create a javascript function with a private variable that has setter and getter methods. i tried:
function createSecretHolder(secret) {
this._secret = secret;
var getSecret = function(){
return this._secret;
}
var setSecret = function(secret){
this._secret = secret;
}
}
and a version with:
this.getSecret = function()...
and
this.seSecret = function()...
it is not passing the test suite on code wars. something like
var obj = createSecretHolder(secret);
obj.getSecret();
obj.setSecret(newSecret);
and others which are hidden. I get an error TypeError: Cannot read property 'getSecret' of undefined and another cannot call method setSecret
createSecretHolder() doesn't return a value so createSecretHolder(secret) returns undefined.
So var obj = createSecretHolder(secret); sets obj to undefined. Hence the error "Cannot read property 'getSecret' of undefined" when you try to access obj.getSecret().
Even if it returned an object, you have declared getSecret using var inside a function. Variables described that way are scoped to the function. So when you try to access it outside the function, as you do in obj.getSecret(), that won't work.
You also seem to misunderstand how this works. It will not create a private variable.
There are a number of ways to do this. Here's one:
function createSecretHolder(mySecret) {
var secret = mySecret;
return {
getSecret: function(){
return secret;
},
setSecret: function (mySecret){
secret = mySecret;
}
};
}
When you use a Constructor to create an object you need to use the new keyword.
Inside your constructor you set a property with this._secret = secret. This is accessible from outside. It should be var _secret = secret.
Also you create local functions inside your object to get/set _secret. They should be methods of the object. See below.
// object constructor
function createSecretHolder(secret) {
// local variable. it isn't accessible from outside
var _secret = secret;
// method to get the secret
this.getSecret = function() {
return _secret;
}
// method to set the secret
this.setSecret = function(secret){
_secret = secret;
}
}
// create new "createSecretHolder" object
var secret = new createSecretHolder("secret 1");
secret.getSecret(); // returns "secret 1"
secret.setSecret("secret 2");
secret.getSecret(); // returns "secret 2"
Look into prototypejs OO programming.
If you can't use prototypejs because of jQuery conflicts, there is a version of it only with OO support here: https://github.com/Prescia/Prototypejslt
Your could would look like:
createSecretHolder= Class.create();
createSecretHolder.prototype = {
_secret: 0,
othervariable: true,
initialize: function(inSecret) { // this is the constructor on prototypejs
this._secret = inSecret;
}
}
// Create instance:
var myInstance = new createSecretHolder(5);
// so this should alert "5":
alert(myInstance._secret);
I can't live without prototypejs Object Orientation, so I often use this light version that won't conflict with other stuff
Related
Can I define functions on proto? Part of the objective is to have getter and setters but not creating any noise when I console.log the object. I've noticed anything defined on prototype is not included in the console.log.
function ValueObject() {
var authentication; //private variable
__proto__.getAuthentication = function() {return authentication};
__proto__.setAuthentication = function(val) {authentication = val};
this.val = val;
}
Desired behavior.
var vo1 = new ValueObject(1);
console.log(vo1); // ValueObject { val: 1 } (desired behavior)
My objective is to show value only in console.log while hiding all those getters and setters from user of the library because they are of internal nature and use.
The problem is getter and setters are not accessible when i instantiate the object.
function ValueObject(val) {
private_val = val; //private
ValueObject.prototype.get =()=> {
this.authentication = private_val;
return this.authentication; // public now
}
}
var auth = new ValueObject('test');
alert('private: '+auth.private_val); // can't receive, it's private hence undefined
alert('private: '+auth.authentication); // neither
alert('public: '+auth.get()); // here you can
IMHO, that's the basic principal. should be working - and ()=> is short for function().
EDIT: and here for a set/get construct example... this should work too:
function ValueObject() {
var private_val; //private
ValueObject.prototype.set =(val)=> {
private_val = val; // private variable gets a value
}
ValueObject.prototype.get =()=> {
this.authentication = private_val; // public variable gets the private value
return this.authentication; // public now
}
}
var auth = new ValueObject;
auth.set('test');
alert('private: '+auth.private_val); // can't receive, it's private hence undefined
alert('private: '+auth.authentication); // neither
alert('public: '+auth.get()); // here you can
check demo
The private variable needs to be publicly exposed in order to access it from the prototype chain. If you need the variable to be private, you will have to deal with seeing the public functions in the console.
How do I add properties to a constructor function in JavaScript? For example. If I have the following function.
function Hotel(name)
{
this.name = name;
};
var hotel1 = new Hotel('Park');
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this". Of course it would not be private since objects created will be able to use it correct?
Can I do something like this. Do I use the this keyword or do I use the var keyword
which one is it? I have example 2 on the function constructor on the bottom
1. var numRooms = 40;
2. this.numRooms = 40;
3. numRooms : 40,
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
};
I know that if I want a function within the object constructor I need to use the this word. Will that work as well for normal variables as I have asked above.
function Hotel(name)
{
this.name = name;
this.numRooms = 40;
this.addNumRoomsPlusFive = function()
{
return this.numRooms + 5;
}
};
You can simple add a private variable to your constructor:
function Hotel(name) {
var private = 'private';
this.name = name;
};
But if you will use your Hotel function without a new operator, all properties and functions which was attached to this will become global.
function Hotel(name) {
var private = 'private';
this.name = name;
};
var hotel = Hotel('test');
console.log(name); // test
It is good idea to return an object in constructor function:
function Hotel(name) {
var
private_var = 'private',
private_func = function() {
// your code
};
retur {
name: 'name',
public_func: private_func
}
};
var hotel = Hotel('test');
console.log(name); // undefined
So if you will use Hotel constructor without new operator no global variable will be created. This is possible only if the return value is an object. Otherwise, if you try to return anything that is not an object, the constructor will proceed with its usual behaviour and return this.
can I add a "local" variable that can be used locally within the class as if it were private with the same notation using the keyword "this".
Yes we can:
// API implementation in the library
function Hotel(name) {
// only our library code knows about the actual value
const numRooms = 'privateNoRoomsVar';
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// also, users don't have access to 'numRooms' variable so they can't use hotel[numRooms].
If a user looks at the source code and finds out the value privateNoRoomsVar, then they can misuse the API.
For that we need to use symobls:
// API implementation in the library
function Hotel(name) {
// no one can duplicate a symbol so the variable is really private
const numRooms = Symbol();
this.name = name;
this[numRooms] = 40;
this.addNumRoomsPlusFive = function() {
return this[numRooms] + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
// there is no way users will get access to the symbol object so the variable remains private.
Private class features, #privateField, are supported by all the browsers so we don’t have to worry about this anymore.
// API implementation in the library
class Hotel {
// private field
#numRooms = 40;
constructor(name) {
this.name = name;
}
addNumRoomsPlusFive() {
return this.#numRooms + 5;
}
};
// from the library user's perspective
const hotel = new Hotel('Transylvania');
console.log('rooms+5 =', hotel.addNumRoomsPlusFive());
console.log('hotel.numRooms =', hotel.numRooms); // undefined
//console.log('hotel.numRooms =', hotel.#numRooms); // throws error
Javascript historically creates objects from prototypes of other objects. It was a result of EMCA2015, that you have a distinct syntax of a class that specifies an object. As an aside, if you mouse over the table in that link it gives dates of when the feature was implemented.
A javascript object created by the new operator is more or less a combination of an associative array ( what you make with let avar={}; ) that can access the function level scopes it is defined in. The keys of the array are its properties. According to its creator, Javascript was created to be an easy to use program language without a hierarchy of types. One of the ways it accomplished this is by more or less considering its mapping type to be equivalent to the prototypical Object which object oriented programming languages describe.
Adding properties in 2022
function AProtoype(arg1, arg2, arg3){
//this defines a property
this.pa=arg1;
/* unicorns in this section */
let x = 1;
/*
a getter which has the same syntax as a property
but returns x from the scope which it references and
not the object.
*/
get getx() => x;
}
let object = new AProtoype(2,3,4);
Is equivalent to the following code for the purposes of data access but not inheritance and typing. The new operator also sets variables on an object that are used for these purposes.
function NewObject(arg1, arg2, arg3){
let prototype = {};
/*dragons in this section, as you are not using the this keyword to accomplish things*/
prototype.pa = arg1;
Object.defineProperty(prototype, "getx", {get:()=>x});
return prototype;
}
//If you do this instead of using the new operator it is an anti-pattern.
//And like all anti-patterns: "But it works!"
let object = NewObject(2,3,4);
The relevant property defining methods where in some sense supported as early as 2010, 2011. I do not have a contemporary source to that time to confirm if you could pull off what I'm doing though, and you'd only want to if all else failed and it needed to run on Internet Explorer 9. In the event all else is failing, you may want to read the documentation for Object.create, which is also of interest because more or less provides an api to make new objects.
Now, for a fun time and horror, you can also define a function that returns this, and get an object back with an equivalent binding of that function. The horror comes when it is an object in global scope, and you rename a property of that object; as Javascript will resolve the name collision by happily writing on whatever it finds if it can. You can then use this to re-implement the prototype pattern that javascripts new operator is built off of conceptually, for the sake of science.
When you use a "constructor function" in Javascript, any properties defined on the instance using the this keyword become public. This is unavoidable, because Javascript objects have no concept of private properties - if it exists, it can be accessed directly as object.property.
For example, if you tried to do as in the following snippet, mimicking a typical getter/setter pattern with a private variable in Java or C# (note that even if this worked, this is not idiomatic Javascript):
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
then while you can indeed use the getter and setter to do as you expect, you can also just access and set the private variable directly! Demonstration:
function MyObject(privateVar) {
this.privateVar = privateVar;
}
MyObject.prototype.getVar = function() {
return this.privateVar;
};
MyObject.prototype.setVar = function(newVal) {
this.privateVar = newVal;
};
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - not intended to work
console.log(obj.privateVar); // 2
obj.privateVar = 3;
console.log(obj.getVar()); // 3 (using public API to get it to show that the direct update to the private variable also affects the intended public methods)
There is though a way to mimic the effect of private variables. They're not actually object properties - because, as I have just demonstrated, such are intrinsically public - but the same can be mimicked by:
not using a "constructor function" at all, but a regular function that happens to return an object. This is all a constructor function really does, anyway - the difference in JS is only syntactic, that you do not need to use the new keyword when you call the function. (Although you still can, if you really prefer - any function that returns an object can be called with new and behave in the same way as without it, although performance will likely suffer a little as the function would then construct a brand new object and throw it away. See MDN for a justification of these statements, particularly step 4.)
inside this function, using a regular variable as the private variable. This variable will be completely inaccessible from outside by the simple rules of scope, but you can still have the returned object retain access to it by the "magic" of closures.
Here is the above getter/setter example translated to this procedure, as well as demonstrations of it working. (I hasten to add again though, that this wouldn't be considered idiomatic code in Javascript.)
function makeObjectWithPrivateVar(privateVar) {
function getPrivateVar() {
return privateVar;
}
function setPrivateVar(newVal) {
privateVar = newVal;
}
return { getPrivateVar, setPrivateVar };
}
var obj = makeObjectWithPrivateVar(1);
// getter
console.log(obj.getPrivateVar()); // 1
// setter
obj.setPrivateVar(2);
// getter again to observe the change
console.log(obj.getPrivateVar()); // 2
// but how could we access the private var directly??
// answer, we can't
console.log(obj.privateVar); // undefined
console.log(privateVar); // ReferenceError, privateVar is not in scope!
Note finally though that it's rare in modern Javascript to use the function-based constructors in this style, since the class keyword makes it easier to mimic traditional class-based languages like Java if you really want to. And in particular, more recent browsers support private properties directly (you just have to prefix the property name with a #), so the initial code snippet translated into a class and using this feature, will work fine:
class MyObject {
#privateVar
constructor(privateVar) {
this.#privateVar = privateVar;
}
getVar() {
return this.#privateVar;
}
setVar(newVal) {
this.#privateVar = newVal;
}
}
var obj = new MyObject(1);
// using public getter/setter
console.log(obj.getVar()); // 1
obj.setVar(2);
console.log(obj.getVar()); // 2
// using private variable directly - now doesn't work
console.log(obj.privateVar); // undefined, it doesn't exist
// console.log(obj.#privateVar); // error as it's explicitly private, uncomment to see error message
Usually it's performed using closures:
var Hotel = (function() {
var numrooms=40; // some kind of private static variable
return function(name) { // constructor
this.numrooms = numrooms;
this.name = name;
};
}());
var instance = new Hotel("myname");
When creating an object to use JS in an OO manner, is there any difference within a JS engine between (with the exception of being able to define a constructor:
var Uploader = Uploader || {};
and
var Uploader = function() {
}
and
function Uploader() {
}
Especially when later, you wish to do something along the lines of
Uploader.DOM = {
Create: function(file) {
}
};
Is it all down to personal preference? Or is there a real difference?
Objects:
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
}
}
In MyObj.find function this keyword will point to MyObj (which somewhat resembles how this works in languages those have classes). You can use this functionality to do mix-ins:
var MyObj2 = {
myArr: [4,2,6]
}
MyObj2.find = MyObj.find;
In MyObj2.find function this keyword will point to MyObj2.
Also objects support getters and setters (works on IE9+ and all good browsers):
var MyObj = {
myArr: [1,2,3],
find: function(/*some arguments*/) {
//some logic that finds something in this.myArr
},
get maxValue() {
return Math.max.apply(null, this.myArr);// maxValue is calculated on the fly
},
a_: null,
get a () {
return this.a_;
},
set a (val) {
//fire a change event, do input validation
this.a_ = val;
}
}
Now max value in the array can be accessed like this: MyObj.maxValue. I also added a property a_. It can't be named the same as its getter and setter so appended an underscore. Appending or prepending underscores is a naming convention for private variables which should not be accessed directly.
var qwe = MyObj.a // get a_
MyObj.a = 'something'; //set a_
Functions:
var u = new Uploader(); // will throw an exception
var Uploader = function() { }
Uploader is defined in runtime here. It does not exist yet when I try to instantiate it.
var u = new Uploader(); //will work
function Uploader() {}
Uploader is defined in compilation time here so it will work.
Functions can be used with revealing pattern to conceal some members. Functions don't support getters and setters but you can put objects inside functions.
function myFunc() {
function privateFunc() {};
function publicFunc() {};
var obj = {
//members, getters, setters
};
return {
publicFunc: publicFunc,
obj: obj
}
}
You can call muFunc.publicFunc() outside of myFunc because it is returned. But you can not use privateFunc outside because it is not returned.
Revealing pattern functions are not meant to be instantiated usually. This is because when you instantiate it everything inside will be copied to a new instance. So it will use up more memory than if you would add functions using prototype.
myFunc.prototype.someFunc = function() {};
Like this all instances of myFunc will share the same instance of someFunc.
Conclusion: with functions you can simulate a private access modifier but in objects the this keyword acts somewhat similar of what you'd expect in a language that have classes. But you always can use call, apply and bind to change the context (i.e. what 'this' keyword will be) of the function.
I'm using JavaScript objects like this:
var obj = new Foob;
should I pretend like there is a private way and do:
obj.get('foo');
or should I just try to access directly as :
obj.foo
You can actually have variables which can only be accessed through setters and getters in Javascript:
function Foob(){
var foo = 5;
this.getFoo = function(){
return foo;
}
this.setFoo = function(newFoo){
foo = newFoo;
return this;
}
}
var obj = new Foob;
obj.getFoo(); // 5
obj.foo; // undefined
Or if you want a generic getter/setter:
function Foob(){
// You can set default values in the data object
var data = {};
this.get = function(key){
return data[key];
}
this.set = function(key, value){
data[key] = value;
return this;
}
}
One least known feature of Javascript is that it supports getters and setters natively.
When defining a property, you can either define it simply by :
someObj.prop = 12;
OR you can define getters and setters , using Object.defineProperty and the reserved words get and set :
Object.defineProperty ( someObj, "prop" ,
{ get : function () { return ??; } ,
set : function (val) { /* store val */ } } ;
A way of using such getters/setters inside a 'class' to get a private variable would be :
var MyClass = function() {
var _private = 5;
Object.defineProperty(this, "public", {
get : function() { return _private; },
set : function(val) { _private=val; }
});
return this;
};
var anInstance = new MyClass();
anInstance.public = 12 ;
console.log(anInstance.public) ; // writes 12
console.log(anInstance._private) ; // writes undefined.
so you have a truly private variable, armed with a getter and a setter.
Obviously, there is not much interest to use getters/setters code , unless you want to make bound-checking/type-checking or have a another specific reason.
I used to like the idea of getters and setters when I started using object-oriented JavaScript heavily, but that is because I was coming from a Java background.
ES5 supports getters and setters through a special syntax
See John Resig's explanation:
http://ejohn.org/blog/javascript-getters-and-setters/
My take is to think about why getters/setters are useful. It's so one has a way to encapsulate a variable's access so that it can be intercepted / controlled. If calling code directly mutates another object's instances variables, then you can't change it transparently. Needing to catch all of these mutations requires changing variable scope, adding a getter and setter and altering all calling code.
However, this syntax is transparent to calling code. Therefore, you can simply allow a property to be directly controlled and then if you need to intercept it, to say add a console.log for debugging, you can ADD a getter and setter and it will just work.
function Foob() {
}
Foob.prototype = {
get foo() {
return this._foo;
},
set foo(foo) {
this._foo = foo;
}
};
var o = new Foob();
console.log(o.foo);
The downside to the getter/setter syntax is that it doesn't actually make your variable private, it only "hides" it so that you can use some secret internal name, unless you define it within the constructor as Vincent indicated.
To get truly private:
function Foob() {
var foo;
this.__defineGetter__('foo', function () {
return foo;
});
this.__defineSetter__('foo', function (_foo) {
foo = _foo;
});
}
var o = new Foob();
console.log(o.foo);
If I create a constructor function BlahWidget and give it 2 public methods: publicHello and secondHello. I assign publicHello directly inside the widget using 'this' but use the prototype object to assign the secondHello method, what difference does that really make to the behaviour of the 2 methods on the widget?
var BlahWidget = function(){
this.publicHello = function(){
alert("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
alert("Second Hello");
}
My understanding was that using .prototype allows it to be called by inherited objects. But turns out that this is not the case. Both methods can be called by the inherited function objects, as shown below:
var MiniBlah = function(){
this.callSupers = function(){
this.publicHello();
this.secondHello();
}
}
MiniBlah.prototype = new BlahWidget();
MiniBlah.prototype.constructor = MiniBlah;
var x = new MiniBlah();
x.callSupers();//calls both publicHello and secondHello
The difference is that functions declared on the prototype object are shared across instances of objects created by a constructor function whereas functions declared inside of the body of a constructor function are not, they belong to the object constructed from the function.
What this means in practice is that you could create a load of objects from a constructor function with a function on the prototype doing X, then change that function on the prototype to do Y and all object instances will get the new functionality of the function.
An example
var BlahWidget = function(){
this.publicHello = function(){
console.log("Hello");
}
};
BlahWidget.prototype.secondHello = function(){
console.log("Second Hello");
}
var blah1 = new BlahWidget();
var blah2 = new BlahWidget();
blah2.publicHello = function() {
console.log("Goodbye");
}
blah1.secondHello(); // logs SecondHello
blah2.secondHello(); // logs SecondHello
BlahWidget.prototype.secondHello = function(){
console.log("Second Goodbye");
}
blah1.secondHello(); // logs Second Goodbye
blah2.secondHello(); // logs Second Goodbye
blah1.publicHello(); // logs Hello
blah2.publicHello(); // logs Goodbye
Every single instance of "BlahWidget" will have its own distinct copy of the "publicHello" function.
Also, though this is just academic, I'm not sure I'd say that "prototype" is a keyword; it's more like a "special property name".
In JavaScript Functions are so powerful to build OOPs and modular concepts. Following concepts are implemented using Function only in JavaScript:
Method
Class
Constructor
Module
Below code shows the code which create class MyClass and it has private members:
function MyClass(a) {
var count = 3; // private member
// this check function is private function
function check() {
if (count > 0) {
count--;
return true;
}
else {
return false;
}
}
this._a = a;
this.get = function () {
if (check()) { // use of private function
return this._a;
}
else {
return "Thullu"; // after invoking get method 3 times in the object this else will be executed
}
}
}
In the above code variable, count is private as any object created from MyClass will not have this variable similarly function check() is private function as this function is not part of this in the MyClass. When we create an object of MyClass using new keyword this is returned. This concept is possible in JavaScript because of lexical scoping (functional scoping).
When we create object of this class MyClass, and call the get method more than 3 times:
I would like to write few points regarding new keyword.
When a function is called with the new operator, a new object is created with prototype members and assigned to this.
Above statement is true only if there is no explicit return value in the function. If explicit return is present in Class (function), then same return will be assigned to the object.
I would like to give here one more example with very basic functionality like in all OOP languages we have. We declare private field and then use public properties to expose the private field, in more formal and OOPs way we create Get and Set method to update private field or retrieve private member of class.
Same get and set functionality for private variables in JavaScript we can achieve as shown in below example:
// private class with get and set methods
function MyClass() {
var _privateField = 0; // It is private field as it is not part of "this"
this.GetPrivateField = function () {
return _privateField;
};
this.SetPrivateField = function (value) {
_privateField = value;
};
}