I am using the module reveal prototype pattern (https://weblogs.asp.net/dwahlin/techniques-strategies-and-patterns-for-structuring-javascript-code-revealing-prototype-pattern), and am having trouble accessing my this variable in my prototype functions. I have this code:
myapp.ConfirmationWindow = function (temptype) {
this._type = temptype;
};
myapp.ConfirmationWindow.prototype = function () {
this._showConfirmationWindow = function (message) {
var a = this._type; //valid
return _showWindow("hello");
}
this._showWindow = function (message) {
var a= this._type; //invalid
}
return {
showConfirmationWindow: _showConfirmationWindow
};
}();
I am able to access this._type in _showConfirmationWindow(), but am not able to access this._type in _showWindow. The different is that the prototype is setting _showConfirmationWindow() as public and _showWindow as private, but why doesn't _showWindow get access to this._type. Why is this the case.
One solution I found is to pass this as an extra parameter in _showWindow
_showWindow don't have a this reference to your instance because it's not part of ConfirmationWindow prototype because by returning only showConfirmationWindow, it never gets assigned to the prototype. You could use call to invoke your private functions like:
_showWindow.call(this, "hello")
Or adding a second argument to _showWindow like and pass the this reference when you invoke it:
_showWindow(message, self)
But i would prefer the first one.
Related
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");
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
I'm writing a JavaScript library in which I want some methods and properties public and other private. The following seems a great way of doing this whilst wrapping everything up into a single object.
(function (window) {
var Thing = function() {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
}
}();
window.Thing = Thing;
})(window);
Thing.method();
Which is great. (Mostly grabbed from here).
However, I'd still like to be able to use the constructor of Thing to pass in some arguments.
Is there anyway I can provide a constructor in the return statement, or use prototype to override the constructor? So I can call:
Thing(stuff);
Right now, if I try that it causes:
Uncaught TypeError: Property 'Thing' of object [object DOMWindow] is not a function
Which makes sense as it's not returning itself, but ideally it'd be possible to call a constructor.
OR, is this just baaaad and I should steer clear of some or all of this?
To accomplish what you are asking, do something like this:
(function (window) {
var thingMaker= function(stuff) {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
alertStuff:function() {
alert(stuff);
}
}
};
window.thingMaker= thingMaker;
})(window);
var myThing = window.thingMaker(stuff);
myThing.alertStuff()
More information can be found by searching the googlenets for Douglas Crockford. Some great and very informative videos by him are available on yui theater. But I would have to ask, why create another framework when there are already so many great ones out there (jquery,prototype,yui,dojo to name a few)
Thing is already created, so you are always going to be too late to call a 'constructor'.
You could pass variables in like this:
(function (window, var1, var2) {
var Thing = function() {
// private var
var variable = "value";
return {
// public method
method:function() {
alert(variable);
}
}
}();
window.Thing = Thing;
})(window, var1, var2);
Thing is an Object with one method called method:
{
// public method
method:function() {
alert(variable);
}
}
Thing.method(); // alerts "value"
You could return instead:
function () {
alert(arguments)
}
Then
Thing(6,5,4); // alerts 6,5,4
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;
};
}
What are the technical reasons for using .prototype instead of declaring functions and members inside the object itself. It is easiest to explain with code examples.
What are the advantages of using:
RobsObject = function(data){
this.instanceID = data.instanceID;
this._formButton = document.getElementById('formSubmit_' + this.instanceID);
if(this._formButton)
{
//set a click listener that
//points to this._onSubmit, this._onSuccess, and this.onFailure
}
};
RobsObject.prototype = {
_onSubmit: function(type, args)
{
//make an ajax call
},
_onSuccess: function(type, args)
{
//display data on the page
},
_onFailure: function(type, args)
{
//show an alert of some kind
},
};
As oppose to declaring your functions inside of the Object like:
RobsObject = function(data){
this.instanceID = data.instanceID;
this._formButton = document.getElementById('formSubmit_' + this.instanceID);
if(this._formButton)
{
//set a click listener that
//points to this._onSubmit, this._onSuccess, and this.onFailure
}
this._onSubmit = function(type, args)
{
//make an ajax call
}
this._onSuccess = function(type, args)
{
//display data on the page
}
this._onFailure = function(type, args)
{
//show an alert of some kind
}
};
Thanks.
Edit: As many of you have pointed out my functions in the second code snippet should have 'this' in front of them in order to be public. So I added it. Just a mistake on my part.
Everything declared in a constructor function's prototype is shared by all instances of that constructor function. If you define functions in the constructor function, then each instance gets its own copy of the function, which wastes memory (and could potentially cause problems if you compare properties between two instances later).
Also, in your example the functions declared in the constructor function are private to the scope of the function. They cannot be called as member methods on instances. For that you would need to assign them to properties of the object:
MyObject = functon() {
// ...
this.myMethod = function() {
// ...
};
}
Douglas Crockford has a good write-up of prototypical inheritance that is definitely worth checking out: Prototypical Inheritance in JavaScript.
UPDATE: Brief Prototype Summary
When you create a new object using a constructor function, the value of the function's prototype property is assigned as the new object's prototype object. (Yes, the names are confusing!) This is a lot like assigning a superclass in a class-based language (but not quite! Read Crockford's page!)
// MyObject constructor function:
MyObject = function() {
this.a = 1;
}
// Define an object to use as a prototype.
var thePrototype = { b: 2 };
// Assign thePrototype as the prototype object for new instances of MyObject.
MyObject.prototype = thePrototype;
// Create an instance of MyObject.
var x = new MyObject();
// Everything in thePrototype is available to x.
console.log(x.b);
// x's prototype is a reference to thePrototype, so updating it affects x.
thePrototype.c = 3;
console.log(x.c);
// Setting properties on x always sets them *on x*, even if the property is
// defined on the prototype:
x.b = 0;
y = new MyObject();
console.log(x.b);
console.log(y.b);
The answer is memory. If you put the members inside of the object itself, then EVERY instance of that object will contain (in memory) all members. If you use prototype, on the other hand, it only exists once, and all instances will access those members as if they were their own.
In the first case, an object constructed with new RobsObject() has the functions _onSubmit(), _onSuccess() as it's properties. They are so-called the public functions of the object.
In the second case, those functions are not properties of new RobsObject(). However, they would be visible to any of the 'public' functions (there aren't any, in your case). In effect, they are the private functions.
However, if you wrote your second snippet this way...
RobsObject = function(data){
this.instanceID = data.instanceID;
this._formButton = document.getElementById('formSubmit_' + this.instanceID);
if(this._formButton)
{
//set a click listener that
//points to this._onSubmit, this._onSuccess, and this.onFailure
}
this._onSubmit = function(type, args)
{
//make an ajax call
}
this._onSuccess = function(type, args)
{
//display data on the page
}
this._onFailure = function(type, args)
{
//show an alert of some kind
}
};
the result is the same.
An important difference between these two conventions is that in the first method, you can't define private functions that can be shared between many public functions like you do in the second method. The Object literal used to define the prototype does not form closures like a function body.
For example,
function MyConstructor() {
var myPrivate = function() {
}
this.myPublic1 = function() {
myPrivate();
}
this.myPublic2 = function() {
myPrivate();
}
}
myPrivate() is a function that is visible to both public functions.