JavaScript Function within Function - javascript

I was wondering if it is possible to do the following:
worker.name("John").salary(100)
Basically, this changes the worker's(John's) salary to 100.
Is there a way to define a function in a function?
Can you tell me the method and explain it?

This is often times called chaining. Essentially, each method returns the parent object:
var worker = {
name: function ( name ) {
this._name = name;
return this;
},
salary: function ( salary ) {
this._salary = salary;
return this;
}
};
worker.name("Jonathan").salary("$1");
alert( worker._name );
alert( worker._salary );
You'll note that each method returns the object. This is made very clear in the following screenshot. If we console output the results of calling the name method, we see that the entire worker object is returned:

Create a constructor function like:
var Worker = function(){
};
Worker.prototype.name = function (name){
this.name = name;
return this;
};
Worker.prototype.salary = function (salary){
this.salary = salary;
return this;
}
Now above constructor function can be used as:
var worker = new Worker();
worker.name("John Doe").salary(100);

This is possible:
var worker = {
nameVar: null,
salaryVar: null,
name: function(name) {
this.nameVar = name;
return this;
},
salary: function(salary) {
this.salaryVar = salary;
return this;
}
}
Each method modifies the object, and returns this, which is the object. Then you can call another method, like in your example, without writing the object name explicitly.
Alternatively, you can implement a .clone method, and instead of this, return the clone with a modified property. This would be somewhat similar to the way jQuery works.

Related

JavaScript Self Invoking function properties

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;
}
}
}();

How do I "get" a member variable in JavaScript?

function User() {
this.firstname = null;
get getFirst() {
return this.firstname;
}
}
JavaScript console gives me an error saying "Unexpected Identifier" on line 12
var Jake = new User();
Jake.firstname = "Jake";
document.write(Jake.getFirst);
That's just not the syntax you use to define a getter. You'd use it in an object literal, like this:
var foo = {
get bar() {
return 42;
}
};
foo.bar; // 42
...but that's not where your get is.
To define it where your get is, you'd use defineProperty:
function User() {
this.firstname = null;
Object.defineProperty(this, "first", {
get: function() {
return this.firstname;
}
});
}
Note I called it first, not getFirst, because it's an accessor function, which looks like a direct property access, and so is traditionally not given a name in a verb form:
var u = new User();
u.firstname = "Paul";
u.first; // "Paul"
If you wanted to create a function called getFirst, just get rid of the get keyword:
this.getFirst = function() {
return firstname;
};
// ...
var u = new User();
u.firstname = "Paul";
u.getFirst(); // "Paul"
I believe the issue is that you are using get with a function rather than the object literal as outlined in the documentation.
var User = {
firstName: 'Darren',
get getFirst() { return this.firstName; }
}
alert(User.getFirst);
https://jsfiddle.net/ecao51n0/
get is intended to be called within an object, not a function constructor. If you want to declare getFirst as a function on User, then here's one way you could do it:
function User() {
this.firstname = null;
this.getFirst = function() {
return this.firstname;
}
}
Then you would also need to call getFirst as a function:
var Jake = new User();
Jake.firstname = "Jake";
document.write(Jake.getFirst());

How do I call a public function from within a private function in the JavaScript Module Pattern

How do I call a public function from within a private function in the JavaScript Module Pattern?
For example, in the following code,
var myModule = (function() {
var private1 = function(){
// How to call public1() here?
// this.public1() won't work
}
return {
public1: function(){ /* do something */}
}
})();
This question has been asked twice before, with a different accepted answer for each.
Save a reference to the return object before returning it, and then use that reference to access the public method. See answer.
Save a reference to the public method in the closure, and use that to access the public method. See answer.
While these solutions work, they are unsatisfactory from an OOP point of view. To illustrate what I mean, let's take a concrete implementation of a snowman with each of these solutions and compare them with a simple object literal.
Snowman 1: Save reference to return object
var snowman1 = (function(){
var _sayHello = function(){
console.log("Hello, my name is " + public.name());
};
var public = {
name: function(){ return "Olaf"},
greet: function(){
_sayHello();
}
};
return public;
})()
Snowman 2: Save reference to public function
var snowman2 = (function(){
var _sayHello = function(){
console.log("Hello, my name is " + name());
};
var name = function(){ return "Olaf"};
var public = {
name: name,
greet: function(){
_sayHello();
}
};
return public;
})()
Snowman 3: object literal
var snowman3 = {
name: function(){ return "Olaf"},
greet: function(){
console.log("Hello, my name is " + this.name());
}
}
We can see that the three are identical in functionality and have the exact same public methods.
If we run a test of simple overriding, however
var snowman = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
// but snowman2 says "Hello, my name is Olaf"
we see that #2 fails.
If we run a test of prototype overriding,
var snowman = {};
snowman.__proto__ = // snowman1, snowman2, or snowman3
snowman.name = function(){ return "Frosty";}
snowman.greet(); // Expecting "Hello, my name is Frosty"
// but #1 and #2 both reply "Hello, my name is Olaf"
we see that both #1 and #2 fail.
This is a really ugly situation. Just because I've chosen to refactor my code in one way or another, the user of the returned object has to look carefully at how I've implemented everything to figure out if he/she can override my object's methods and expect it to work! While opinions differ here, my own opinion is that the correct override behavior is that of the simple object literal.
So, this is the real question:
Is there a way to call a public method from a private one so that the resulting object acts like an object literal with respect to override behavior?
You can use this to get the object your privileged method greet was called on.
Then, you can pass that value to your private method _sayHello, e.g. using call, apply, or as an argument:
var snowman4 = (function() {
var _sayHello = function() {
console.log("Hello, my name is " + this.name);
};
return {
name: "Olaf",
greet: function() {
_sayHello.call(this);
}
};
})();
Now you can do
var snowman = Object.create(snowman4);
snowman.greet(); // "Hello, my name is Olaf"
snowman.name = "Frosty";
snowman.greet(); // "Hello, my name is Frosty"
And also
snowman4.greet(); // "Hello, my name is Olaf"
snowman4.name = "Frosty";
snowman4.greet(); // "Hello, my name is Frosty"
With module pattern, you hide all the innates of an object in local variables/functions, and usually employ those in your public functions. Each time a new object is created with a module pattern, a new set of exposed functions - with their own scoped state - is created as well.
With prototype pattern, you have the same set of methods available for all objects of some type. What changes for these methods is this object - in other words, that's their state. But this is never hidden.
Needless to say, it's tough to mix those. One possible way is extracting the methods used by privates into a prototype of the module's resulting object with Object.create. For example:
var guardian = function() {
var proto = {
greet: function () {
console.log('I am ' + this.name());
},
name: function() {
return 'Groot';
}
};
var public = Object.create(proto);
public.argue = function() {
privateGreeting();
};
var privateGreeting = public.greet.bind(public);
return public;
};
var guardian1 = guardian();
guardian1.argue(); // I am Groot
var guardian2 = guardian();
guardian2.name = function() {
return 'Rocket';
};
guardian2.argue(); // I am Rocket
var guardian3 = guardian();
guardian3.__proto__.name = function() {
return 'Star-Lord';
};
guardian3.argue(); // I am Star-Lord

Constructors in the Module Pattern

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;
}
}

Is it possible to append functions to a JS class that have access to the class's private variables?

I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());

Categories

Resources