JavaScript - Invoking Methods that Reference this - javascript

Not sure what I'm doing wrong here, I just want to be able to have functions of an object reference the object scope
myscipt.js
function MyFoo () {
this.name = 'myname';
}
function MyBar () {
this.myFoo = new MyFoo();
function setMyFoosName( name ) {
this.myFoo.name = name;
}
}
somepage.html
<scipt>
$('document').ready( function() {
$.myBar = new MyBar();
}
...
some action
...
$.myBar.setMyFoosName( 'new name' );
</script>
this throws an exception:
this.myFoo.name = name; this.myFoo is not defined

Lekensteyn and Ken got it half right each.
You have to put "this" in a variable, like Lekensteyn did, in order to be able to reference it inside of the nested function as well.
You have to make setMyFoosName accessible outside of the scope of MyBar, by assigning it to a property of "this", like Ken did.
This is how I would do it:
function MyFoo () {
this.name = 'myname';
}
function MyBar () {
var that = this;
this.myFoo = new MyFoo();
this.setMyFoosName = function( name ) {
that.myFoo.name = name;
}
}

Cant you do an instance static method with the JSON Data type?
var MyFoo = {
_instance : null,
Instance : function(){
if(this._instance == null)
{
this._instance = new this.Object();
}
return this._instance;
},
Object : function()
{
this.name = 'not robert';
}
}
function MyBar (){
this.setMyFoosName = function ( name ) {
MyFoo.Instance().name = name;
}
}
Bar = new MyBar()
Bar.setMyFoosName('Robert');
Gives it more of a global scope and so on, aslong as MyFoo is in the global scope.
Example here.

this referes to the scope of setMyFoosName. You should put this in a variable, and refer to that variable:
function MyFoo () {
this.name = 'myname';
}
function MyBar () {
var that = this;
this.myFoo = new MyFoo();
this.setMyFoosName = function( name ) {
that.myFoo.name = name;
}
}
Try to avoid exporting variables which should remain private:
function myFoo () {
this.name = 'myname';
}
function MyBar () {
/* myFoo is private */
var myFoo = new MyFoo();
this.setMyFoosName = function( name ) {
myFoo.name = name;
}
}
In this way, you cannot break your function with:
$.myBar = new MyBar();
$.myBar.myFoo = new EvilObject();
$.myBar.setMyFoosName();
Of course, this depends on your use, whether myFoo should be overridable or not.

Related

Accessing 'this' inside an independent function in a Constructor

I have a Dog Constructor as follows:
var Dog = function(name,type)
{
this.name = name;
this.type = type;
this.normalObjFunc = function()
{
this.name = "kl";
}
var retfunc = function()
{
return this.name;
}
return retfunc;
}
In the retfunc function() , I am trying to access this.name in the following way.
var dogObj = new Dog("hj","labrador");
alert(dogObj());
In the output , I get as "result" in the alert messageBox, I am not getting what does the o/p "result" ,means?
I have purposely not included retfunc to "this" object, does it mean I cant access this.name inside retfunc() because a SEparate "this" would be created?
I am also aware of the fact that assigning var self =this solves the problem.
I just want to know what is "result" which is the output and why not undefined ideally?
The issue is because the scope of this within the functions will be the window. You need to cache the object reference in a variable and call that, like this:
var Dog = function(name, type) {
var _this = this;
this.name = name;
this.type = type;
this.normalObjFunc = function() {
_this.name = "kl";
}
var retfunc = function() {
return _this.name;
}
return retfunc;
}
var dogObj = new Dog("hj", "labrador");
console.log(dogObj());
Alternatively you can prototype the functions to keep the scope of this, however you would need to change your logic as it means that the return value of Dog() could not be the function.
var Dog = function(name, type) {
this.name = name;
this.type = type;
}
Dog.prototype.normalObjFunc = function() {
this.name = "kl";
}
Dog.prototype.retfunc = function() {
return this.name;
}
var dogObj = new Dog("hj", "labrador");
console.log(dogObj.retfunc());

How to encapsulate data in javascript without function duplication in every object instance?

I create a class in JavaScript with public and private properties - data and methods to operate on this data. Some data is private and should not be accessible via "."(dot) operator from class instance. Is there way to avoid method duplication for every class instance?
function MyClass() {
let privateVar;
let publicVar;
function publicFun() {
// do something
}
function privateFun(){
// do something else
}
this.v = publicVar;
this.f = publicFun;
}
let obj1 = new MyClass();
let obj2 = new MyClass(); // publicFun and privateFun methods duplication
ClassName.prototype approach require completely public API for all class data. So this doesn't work for me.
Here is my example if I understood you correctly:
Methods are defined only once, within the wrapper function (thus they are not declared on every instance)
You can create instances of objects they will all refer to the same methods, and can have exposed data.
Here is a fiddle example:
function wrapper() {
//Methods defined only once
function method() {
alert("this is method");
}
function methodWithParams(param, callback) {
var paramsVar = param;
function realMethodHere() {
alert("We passed a param: " + paramsVar);
paramsVar = "Changed"
callback(paramsVar);
alert("Now we cahnged the param's value to: " + paramsVar + ", rerun the method to verify");
}
return realMethodHere;
}
//Class constructor
function classConstructor() {
//Private
var privateData = "Private"
function privateFunction() {
alert("this is some private function, inaccesible");
}
//This callback was addedto allow yo uto change private data.
function privateDataChangerCallback(param) {
privateData = param;
}
//Public
this.publicData = "Public"
this.callMethod = method;
this.paramMethod = methodWithParams(privateData, privateDataChangerCallback);
}
return classConstructor;
}
var classDefinition = wrapper();
var classInstance = new classDefinition();
classInstance.callMethod(); //method without param
classInstance.paramMethod(); //method with exposed Private data
//rerunning the method to see what the value is:
classInstance.paramMethod(); //method with exposed Private data
You can try using TypeScript it's a javascript library that support OOP so you can write your code like in c# or java and the compiler will generate the real javascript for you.
If I understand right, you can add a parameter to your class definition and based on this parameter, you can choose to include additional properties to your return object.
Sample
function myClass(option) {
var myFunc1 = function() {}
var myFunc2 = function() {}
var myFunc3 = function() {}
var myFunc4 = function() {}
var myFunc5 = function() {}
var finalProps = {
myFunc1: myFunc1,
myFunc2: myFunc2,
}
switch (option) {
case "all":
finalProps["myFunc5"] = myFunc5;
case "more":
finalProps["myFunc3"] = myFunc3;
finalProps["myFunc4"] = myFunc4;
break;
}
return finalProps;
}
(function() {
var f1 = new myClass();
var f2 = new myClass("more");
var f3 = new myClass("all");
console.log(f1, f2, f3)
})()
You can create a stand-alone function in the constructor function:
var HelloWorld = (function () {
function anonymouse() {
return "MUHAHAHA! ALL MINE!!!";
}
function HelloWorld() {
this.greeting = "Hello World";
}
//public
HelloWorld.prototype.greet = function () {
console.log("Hello, " + this.greeting + " " + anonymouse());
};
return HelloWorld;
}());
var greeter = new HelloWorld();
greeter.greet();
console.log(greeter);
But this does have the side effect of duplicating said function on all instances of your class.
Alternatively, maybe create a namespace to hide it in, and reference your functions from there. That would eliminate the duplicate function issue:
var MySecretClasses;
(function (MySecretClasses) {
function anonymouse() {
return "MUHAHAHA! ALL MINE!!!";
}
var HelloWorld = (function () {
function HelloWorld() {
this.greeting = "Hello World";
}
//public
HelloWorld.prototype.greet = function () {
console.log("Hello, " + this.greeting + " " + anonymouse());
};
return HelloWorld;
}());
MySecretClasses.HelloWorld = HelloWorld;
})(MySecretClasses || (MySecretClasses = {}));
var greeter = new MySecretClasses.HelloWorld();
greeter.greet();
console.log(MySecretClasses);
console.log(greeter);
TYPESCRIPT
As Shlomi Haver points out, you could use TypeScript for this.
module MySecretClasses {
function anonymouse() {
return "MUHAHAHA! ALL MINE!!!";
}
export class HelloWorld {
greeting: string = "Hello World";
constructor() {
}
//public
public greet() {
console.log("Hello, " + this.greeting + anonymouse());
}
}
}
var greeter = new MySecretClasses.HelloWorld();
greeter.greet();
console.log(greeter);

How to use object oriented without using keyword ('new')

What am I trying to do is as following:
var Person = function(name) {
this.name = name;
}
Person.prototype.getName = function () {
return this.name;
}
// This will return error;
console.log(Person('John').getName());
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());
Am I misunderstanding something?
// This will return error;
console.log(Person('John').getName());
it returns an error bcoz Person() by default returns undefined ,but if you use new it will return the newly created object.
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());
this works bcoz a new object with __proto__ set to Person.prototype is returned and since there is a getName() on it , it works as expected.
you may use scope safe constructor for your constructor to work without explicit new.
function Person(name) {
if(this instanceof Person) {
this.name = name;
} else {
return new Person(name);
}
}
http://www.mikepackdev.com/blog_posts/9-new-scope-safe-constructors-in-oo-javascript
If you don't want to have the new keyword all over your code (and I can't think of a good reason to want that, you would be basically hiding an important information), you could just do something like:
var pPerson = function(name) {
this.name = name;
};
pPerson.prototype.getName = function () {
return this.name;
};
var Person = function (name) {
return new pPerson(name);
};
You can use Object.create() if you don't want to use the new keyword. Here's an example from MDN:
// Animal properties and method encapsulation
var Animal = {
type: "Invertebrates", // Default value of properties
displayType : function(){ // Method which will display type of Animal
console.log(this.type);
}
}
// Create new animal type called animal1
var animal1 = Object.create(Animal);
animal1.displayType(); // Output:Invertebrates
// Create new animal type called Fishes
var fish = Object.create(Animal);
fish.type = "Fishes";
fish.displayType(); // Output:Fishes
If you really really hate your self, you can do this
var Person = function(name) {
var This = {};
This.name = name;
//See note
Object.setPrototypeOf(This, arguments.callee.prototype);
return This;
}
Person.prototype.getName = function () {
return this.name;
}
var p = Person('John');
console.log(p.getName());
Note
You absolutely have to read about this.
You can try creating prototype functions as a part of parent function itself.
var Person = function(name) {
this.name = name;
this.get_name = function() {
return this.name;
}
return this;
}
Person.prototype.getName = function() {
return this.name;
}
// This will return error;
console.log(Person('John').get_name());
// While this won't.
var p1 = new Person('john');
console.log(p1.getName());

using inheritance inside a namespace [duplicate]

How do I inherit/extend classes that are using the Revealing Prototype pattern?
And is there a way to make the private variables and functions protected?
Example base object:
myNameSpace.Person = function() {
this.name= "";
this.id = 0;
};
myNameSpace.Person.prototype = function(){
var foo = function(){
//sample private function
};
var loadFromJSON = function (p_jsonObject) {
...
};
var toJSON = function () {
...
};
var clone = function (p_other) {
...
};
return {
loadFromJSON : loadFromJSON,
toJSON: toJSON,
clone: clone
};
}();
There are no protected variables/properties in JavaScript. Though, you can reuse "private" variables when you declare the inheriting classes in the same scope, which seems possible in your case when the private variables are only "hidden utilities" of your prototype.
MyNamespace.Person = function Person(params) {
// private variables and functions, individual for each Person instance
var anything, id;
function execute_something() {}
// public properties:
this.name = "";
this.getId = function getId(){
// called a "privileged function", because it has access to private variables
}
}
MyNamespace.American = function(params) {
MyNamespace.Person.call(this, params); // inherit name and getId()
}
(function() { // new scope for
// hidden utility functions and other private things
function foo() { }
function helpJSON() { }
function fromJSON() { }
var bar;
(function(personProto) { // new scope for prototype module (not explicitly needed)
// "private" /static/ variables (and functions, if you want them private)
var personCount = 0;
personProto.clone = function clone() {
return this.constructor(myself); // or something
};
personProto.toJSON = function toJSON() {
// use of helpJSON()
};
personProto.fromJSON = fromJSON; // direct use
})(MyNamespace.Person.prototype);
(function(amiProto) {
// just the same as above, if needed
amiProto.special = function() {
// use foo() and co
};
})( MyNamespace.American.prototype = Object.create(MyNamespace.Person.prototype) );
})();
This is the JavaScript way of inheritance, which means American's prototype inherits the clone(), toJSON() and fromJSON() functions automagically from the Person's prototype. Of course overwritable. And the feature is
new MyNamespace.American() instanceof MyNamespace.Person; // true
Of course, if you don't need that, and want use the more module-like way, you could reuse the utility functions, i.e. just copy them:
(function() {
// hidden utility functions and other private things
var bar;
var personCount;
function foo() { }
function helpJSON() { }
function fromJSON() { }
function clone() {
return this.constructor(myself); // or something
}
function toJSON() { }
(function(personProto) { // new scope, not really needed
// private variables are useless in here
personProto.clone = clone;
personProto.toJSON = toJSON;
personProto.fromJSON = fromJSON;
})(MyNamespace.Person.prototype);
(function(amiProto) { // new scope, not really needed
// copied from personProto
amiProto.clone = clone;
amiProto.toJSON = toJSON;
amiProto.fromJSON = fromJSON;
// and now the differences
amiProto.special = function() {
// use foo() and co
};
})(MyNamespace.American.prototype);
})();

Passing arguments to anonymous function of module

$(document).ready(function () {
var patient = (function (options) {
var age = options.age;
var name = options.name;
function getName() {
return this.name;
}
function setName(val) {
name = val;
}
function getAge() {
return this.age;
}
function setAge(val) {
age = val;
}
return {
getAge: getAge,
setAge: setAge,
getName: getName,
setName: setName
}
})();
});
I realize that I'm never passing any options in my example here.
If I try to do something like patient.setAge('100') and then console.log(patient.getAge()) I get an error saying cannot read property Age of undefined. The overarching theme that I'm trying to get at is within a module, how can I emulate consturctors to instantiate a new patient object while keeping all the OOP goodness of private variables and all that jazz.
I've seen some examples of constructors in a module pattern on here and I haven't understood them very well. Is it a good idea in general to have a constructor in a module? Is its main purpose similarity with class-based languages?
This is a constructor:
function Patient(options) {
options = options || {};
this.age = options.age;
this.name = options.name;
}
$(document).ready(function () {
var patient = new Patient();
});
You can put it inside a module if you want. What you shouldn’t do is provide getters and setters, especially ones that don’t do anything. If you’re exposing a variable through two properties to get and set it, it should just be one property.
Try this
function Patient (options) {
options = options || {};
var age = options.age;
var name = options.name;
function getName() {
return name;
}
function setName(val) {
name = val;
}
function getAge() {
return age;
}
function setAge(val) {
age = val;
}
return {
getAge: getAge,
setAge: setAge,
getName: getName,
setName: setName
}
}); // pass empty object
$(document).ready(function () {
var p1 = new Patient({});
var p2 = new Patient();
var p3 = new Patient({age:20});
var p4 = new Patient({name:"abcd"});
var p5 = new Patient({age:21, name:"abcd"});
});

Categories