When using the module pattern in javascript how should constructors be defined, if at all. I would like my constructor to fit into a standard module pattern and not be global.
Why doesn't something like this work, is it complete and total nonsense?
var HOUSE = function() {
return {
Person: function() {
var self = this;
self.name = "john";
function name() {
return self.name;
}
}
};
}();
var me = new HOUSE.Person();
alert(me.name());
Your code is almost fine. However the function name() was not public but the variable was so you were trying to execute the variable causing an error. Add the function getName onto the object and call that instead:
var HOUSE = function() {
return {
Person: function() {
var self = this;
self.name = "john";
self.getName = function() {
return self.name;
}
}
};
}();
var me = new HOUSE.Person();
alert(me.getName());
http://jsfiddle.net/8nSbP/
Using var and function foo() {} (the latter as a declaration, which means "just" function foo() {} without assigning it), create local symbols. So, the function is not available outside the constructor.
Whatever you want to expose (make public), you should assign to this (or self since you defined self = this):
self.getName = function() {
return self.name;
};
Note that you already used name, so I gave function another name. If you wanted to make the name string local, and expose the function, then they can have the same name since there is no conflict. E.g.:
var name = "john";
self.name = function() {
return name;
};
You need to bring the method out, and attach it to the Person prototype. But when you do, you'll have a name property, and a name method, which won't work, so consider renaming the latter
HOUSE.Person.prototype.getName = function(){
return this.name;
}
OR, you could just attach it to this, and make getName a privileged method:
Person: function() {
this.name = "john";
this.getName = function() {
return this.name;
}
}
Related
I'm wondering how to access a public property from private and public functions in a JavaScript module?
For example, if this is my module:
var PersonModule = (function(){
var sayHello = function(){
alert("Hello " + name);
}
var privateChangeNameToBob = function(){
this.name = "Bob";
}
var changeName = function(){
privateChangeNameToBob();
}
return {
name: "",
sayHello: sayHello,
changeName: changeName
}
})();
Neither sayHello or the changeName functions work correctly because I don't know how to access the public name property. Is there a way to do this? I've worked around it by using private variables with getters and setters, but I'm wondering if I can do it without them.
You need a reference to the result object:
var PersonModule = (function(){
function sayHello() {
alert("Hello " + person.name);
}
function privateChangeNameToBob() {
person.name = "Bob";
}
function changeName() {
privateChangeNameToBob();
}
const person = {
name: "",
sayHello,
changeName
};
return person;
})();
Of course, given your singleton IIFE module, you could just as well refer to PersonModule.name directly.
In the way you're doing it the name variable that you're using as public it's not the same as the one in your sayHello method. You have to understand that this is a MODULE not a class that needs to be instantiated. The IIFE already instantiates it for you. To do what you want you can use the below model. Use self. in the public methods/vars and nothing in the private. Then it will all work.
var PersonModule = (function(){
var self = {};
var privateChangeNameToBob = function(){
self.name = "Bob";
};
self.sayHello = function(){
console.log("Hello " + self.name);
};
self.changeName = function(){
privateChangeNameToBob();
};
self.name = "";
return self;
})();
PersonModule.name = 'Test';
PersonModule.changeName();
PersonModule.sayHello();
You need to declare the property inside your closure. Check this example out to understand it better:
var ClassName = function(constructorParam) {
var privateProperty = 'Im a private property';
this.publicProperty = 'Im a public property';
function privateMethod() {
console.log('Private method');
}
this.publicMethod = function() {
console.log('Public method');
// We can call private properties
console.log(privateProperty);
// Either private methods
privateMethod();
}
}
var instance = new ClassName('Here goes something to constructor');
instance.publicMethod();
Your this.name in privateChangeNameToBob is setting name as a property of that function, not of the module. You can, instead, use it like so:
var PersonModule = (function(){
var name = '';
//...
var privateChangeNameToBob = function(){
name = "Bob";
}
return {
name: name,
sayHello: sayHello,
changeName: changeName
};
})();
See fiddle here: https://jsfiddle.net/yv8uqh5y/
One last note is a design pattern you may find useful. You can declare a variable named base or similar within your module scope, like so:
var PersonModule = (function(){
var base = {};
base.name = '';
base.sayHello = function() {/* ... */};
//...
return {
name: base.name,
sayHello: base.sayHello,
changeName: base.changeName
};
})();
See fiddle here: https://jsfiddle.net/k63u9bfo/
This way you can reference the base of your module without having to worry what this maps to (eg. if you're trying to access the module internally using this within an anonymous function declared within a module method.
Trying to understand JS better, have a couple of clarifications. Lets suppose we have the following method
var customer = function(){
var name = "Contoso";
return {
getName : function(){
return this.name;
},
setName : function(newName){
this.name = newName;
}
}
}();
why is name not visible outside ?, when we log (customer.name) its undefined, however if we remove the self initializing parenthesis on function and change the variable declaration to (this.name) & again when we log the same we are able to see the value. what am i missing in here.
You need to take in consideration that JavaScript doesn't really have native classes. With this said, the way you can create constructors in order to "mimic" a class and be able to use this you need to create something like so:
function fnc (string) {
this.string = string;
}
fnc.prototype.getString = function() {
return this.string;
}
var x = new fnc('bar');
console.log(x.getString()); //bar
This is called the Constructor Pattern.
What you're trying to do is use something called the Module Pattern which works something like so:
var fn = (function() {
var string = 'foo';
return {
getString() {
return string;
}
}
})();
console.log(fn.getString()); //foo
Here is a working example: https://repl.it/FCn7
Also, a good read: https://addyosmani.com/resources/essentialjsdesignpatterns/book/
Edit
Example using getString and setString with the Module Pattern
var fn = (function() {
var string = 'foo';
return {
getString() {
return string;
},
setString(str){
string = str;
}
}
})();
fn.setString('xyz');
console.log(fn.getString()); // xyz
var is creating variable inside function scope which is not available outside as function property. If you want to access properties like customer.name you need to initialize it as this.name as you noticed.
var in this example is like creating private variable which can be modified by functions, but not directly.
SO this will work:
var customer = function(){
var name = "Contoso";
return {
getName : function(){
return name;
},
setName : function(newName){
name = newName;
}
}
}();
I have the inheritance chain Vehicle -> Motorized -> Car implemented:
function Vehicle()
{
var m_name;
this.setName = function(pName) {
m_name = pName;
};
this.getName = function() {
return m_name;
};
}
function Motorized()
{
var m_started = false;
this.start = function() {
m_started = true;
console.log(getName() + " started");
};
}
function Car()
{ }
//set up the inheritance chain
Motorized.prototype = new Vehicle();
Car.prototype = new Motorized();
// use
var lCar = new Car;
lCar.setName("Focus");
console.log(lCar.getName()); // Focus
lCar.start(); // ReferenceError: getName is not defined
When I invoke lCar.start() (defined in function Motorized), I get an ReferenceError: getName is not defined. How can I use the inherted method getName() in my subclass Motorized?
Because Javascript doesn't know where to look for your getName() method. You can clarify the syntax declaring a self variable that always points to the right object, like this:
function Vehicle()
{
var self = this; // Vehicle
var m_name;
this.setName = function(pName) {
self.m_name = pName;
};
this.getName = function() {
return self.m_name;
};
}
function Motorized()
{
var self = this; // Motorized
var m_started = false;
this.start = function() {
/*
`self` is Motorized, with proto Vehicle, so
has a getName() method.
`this` instead is the object where you call
start() from, i.e. Car, in the example down below.
*/
self.m_started = true;
console.log(self.getName() + " started");
};
}
function Car()
{ }
//set up the inheritance chain
Motorized.prototype = new Vehicle();
Car.prototype = new Motorized();
// use
var lCar = new Car;
lCar.setName("Focus");
console.log(lCar.getName()); // Focus
lCar.start(); // Focus started
Note that in this case, using the keyword this instead of self throughout the code would have worked as well, but you definitely cannot omit it before getName(). Also, if you are planning to add more code later on, such as event handlers in jQuery, having a clear reference to the class you're coding in can be useful, as this can become easily ambiguous, at least from the human point of view.
Anyway, whether using self is a bad coding pattern or not is the topic of this question; the point in your example is that you need to call self.getName() or this.getName().
I am having trouble combining private/public methods along with inheritance in Javascript. I think it is just a misunderstanding on my part and hopefully an easy resolution.
Here is what I have:
RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Orange = function() {
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
// Public
return {
getName : function() {
return "Orange";
}
}
}
RB.Orange.prototype = new RB.Fruit();
var o = new RB.Orange();
console.log(o.getType());
When I run this code I receive the error "Uncaught TypeError: Object # has no method 'getType'". I know that it has to do with using the "return" within the class functions (since moving the getName method out of the "return" block allows it to work), but I'd like to continue to be able to declare private/public methods within classes.
How do I modify this to allow RB.Orange to access the RB.Fruit.getType function?
Thanks!
In JavaScript, a constructor call implicitly returns the newly-constructed instance, but the constructor can override that default behavior by explicitly returning a different object. For example, if you define a "constructor" Foo like this:
function Foo() {
return new Date();
}
then the statement foo = new Foo() will set foo to a new Date, not a new Foo.
If I understand correctly what you want, you just need to change this:
return {
getName : function() {
return "Orange";
}
}
(whereby your "constructor" returns a completely fresh object, with only a getName method, and no relation to the object under construction) to this:
this.getName = function() {
return "Orange";
};
(whereby it adds a getName method to the object under construction, and still allows that object to be returned).
The main problem
When you return a non-primitive value from a constructor function, that non-primitive value is returned rather than the default returned instance you would expect when invoking it with the new keyword.
E.g.
function A() { return {}; }
new A() instanceof A; //false
Therefore you could simply change your code to something like:
RB.Orange = function() {
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
this.getName = function () {
return 'Orange';
};
//priviledged function which uses a private member
this.someOtherFunction = function () {
makeOrangeJuice();
};
};
Some inefficiencies in your code
Why not using the prototype?
Functions that aren't priviledged should not be declared within the constructor function. In other words, functions that do not access private variables should not be created in the constructor function because they do not have to and it's extremely inefficient to do so. Why? Because a new function is being created everytime the constructor is called.
Instead you should make use of the Constructor.prototype to share your public functions between all instances.
E.g.
function Person(name) {
this.name = name;
}
Person.prototype.sayName = function () {
console.log('My name is ' + this.name);
};
new Person('Foo Bar').sayName();
Use Object.create rather than new for inheritance when possible.
Most inheritance patterns using the new keyword were done this way because the language was lacking another way of setting up the prototype chain of an object, but now that we have Object.create, your should use it. Using the new keyword for inheritance the way you did has some undesired side-effects like running the constructor function. There are ways to avoid these side effects by using an intermediate empty function but why not simply use Object.create?
E.g. (based on the above example)
function BadPerson(name) {
//call parent constructor
Person.call(this, name + ' the bad');
}
BadPerson.prototype = Object.create(Person.prototype);
BadPerson.prototype.constructor = BadPerson; //fix constructor
Private functions can also be shared!
Note that private functions that do not access private variables can also be shared. You can make use of the module pattern to create a scope for them.
E.g.
var Person = (function () {
//private function used in a functionnal style
function _validateName(name) {
console.log('Validating the name in functionnal style');
}
//private function used in an OO style
function _validateNameOO() {
console.log('Validating the name in a OO style');
}
function Person(name) {
this.name = name;
}
Person.prototype.validateNameBothWays = function () {
_validateName(this.name);
_validateNameOO.call(this);
};
return Person;
})();
new Person().validateNameBothWays();
The following shows how you could implement shared private members and where to put the priviliged methods (methods that can access the shared privates);
I never found much use for this pattern and usually indicate a private being private with the name _aPrivate as Phillip already explained in his answer.
For an introduction on constructor functions, prototype, inheritance and the value of this click here.
RB = {};
RB.Fruit = function() {
}
// Public
RB.Fruit.prototype.getType = function() {
return "FRUIT";
};
RB.Orange = function() {
//inherit instance specific values of Fruit (there are none but there might be)
RB.Fruit.apply(this,arguments);
};
//inherit shared members from the prototype of Fruit
RB.Orange.prototype = Object.create(RB.Fruit.prototype);
//repair constructor to be Orange instead of Fruit
RB.Orange.prototype.constructor = RB.Orange;
//shared privates and privileged methods (methods that can access the privates)
// go in the following IIFE function body.
(function(){
//private version of makeOrangeJuice
var makeOrangeJuice = function () {
//the value of 'this' here isn't the Orange instance
//if you need it then pass it with the public version of
//makeOrangeJuice or use makeOrangeJuice.call(this) in the
//public version
console.log("Orange has been squeezed.");
};
//public version of makeOrangeJuice
RB.Orange.prototype.makeOrangeJuice=function(){
//call private makeOrangeJuice function
makeOrangeJuice();
}
}());
//non privileged member, in getName the private version of makeOrangeJuice
//doesn't exist you can call the public version with this.makeOrangeJuice
RB.Orange.prototype.getName = function() {
return "Orange";
};
var o = new RB.Orange();
console.log(o.getType());
o.makeOrangeJuice();
You need to assign the functions to the prototype of your objects, if you want them to be inherited.
RB = {};
RB.Fruit = function() {};
RB.Fruit.prototype.getType = function() {
return 'Fruit';
};
RB.Orange = function() {};
RB.Orange.prototype = new RB.Fruit();
RB.Orange.prototype.getName = function() {
return 'Orange';
};
If you really need to use privates, and can't just label things as private using conventions like the _name, then you'll need to move the functions that will use the privates into the constructor with the private members.
If they're not instance specific, you can (and should) wrap this whole thing with an immediate function.
(function() {
// All previous code here
window.RB = RB;
}());
Here is one way that you could do it:
var RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Orange = function() {
// Private variable
var fruit = new RB.Fruit();
// Private function
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
// Public object with accessor
return {
getName : function() {
return "Orange";
},
getType: fruit.getType
}
}
var o = new RB.Orange();
console.log(o.getType());
try this code.
RB = {};
RB.Fruit = function() {
// Public
this.getType = function() {
return "FRUIT";
}
}
RB.Fruit.prototype.getType = function() {
return "FRUIT";
};
RB.Orange = function() {
RB.Fruit.call(this);
// Private
function makeOrangeJuice() {
console.log("Orange has been squeezed.");
}
this.getName = function() {
return "Orange";
};
this.getJuice = function(){
makeOrangeJuice();
};
};
var o = new RB.Orange();
//calling the super-call's function
console.log(o.getType());
//public function
o.getJuice();
//trying to access private function
o.makeOrangeJuice();
For more detail on the code ojbect oriented javscript plz check below link
http://mckoss.com/jscript/object.htm
Ok, I'm creating a chaining method with javascript and I'm trying to archive that the main obj or class have access to 4 property that are functions and the properties must have access to some functions that the main obj cannot.
Here a example:
var Main = function(){
return {
property1:function(){
return this;
},
property2:function(){
return this;
},
etc:function(){
return this;
}...
}
}
To execute as you know its like this:
Main().property1().property2().etc();
Main have access to its properties but Main must not have access to this properties that are properties of Main's properties. In simplier way: just the properties of Main must have access, not Main.
Here an example:
Main().property().innerProperty1().innerProperty2().etc()//cool, property1 can access to innerProperty 1 and 2 and etc()
but if i want to do this:
Main().innerProperty() // ERROR, Main does not have acccess to innerProperty()
Could that be possible in javascrip? Remember that must be chainable.
I'm still not very sure what you are asking, but this is what i came up with. I made two JS classes to demonstrate what you are saying.
function Owner(name) {
this.Name = name;
this.ChangeName = function (newName) {
this.Name = newName;
return this;
};
}
function Car(make, model, owner) {
this.Make = make;
this.Model = model;
this.Owner = owner;
this.UpdateMake = function (newMake) {
this.Make = newMake;
return this;
};
this.UpdateModel = function (newModel) {
this.Model = newModel;
return this;
};
this.UpdateOwner = function (newOwner) {
this.Owner = newOwner;
return this;
};
}
Here's the fiddle: http://jsfiddle.net/whytheday/zz45L/18/
Car would not have access to Owner's name unless it went through Owner first.