I am refactoring some JS code and need to access Objects like
Object1.Object2.IsValid();
this is what I have right now.
function _Object1(object) {
this._object1 = object;
this.Object2= new _Object2();
function IsValid() {
// tests here
}
}
function _Object2()
{
function IsValid() {
// tests here but needs to use Object1 property above.
}
}
Only problem being, I am not sure how to access Object1 in Object2 without passing any parameter. Nesting Object2 in Object1, perhaps?
Edit: I am tring to implement OOP in JS, which is like reinventing the wheel, but want to try it for now :)
I will explain the question in terms of OOP:
I have a class _Object1 and it has a method IsValid(). _Object1 also has a property Object2 which is of type _Object2.
Now, _Object2 also has method named IsValid(). But here is a catch, _Object2.IsValid need the value of _Object1 for tests.
For the above code if I do:
var Object1 = new _Object1();
I can simply call Object1.Object2.IsValid() for the result. Isn't it?
Disclaimer: I have been using JS for sometime now, but never had to dabble with things like these.
Give _Object2 what it needs:
function _Object1(object) {
this._object1 = object;
this.Object2= new _Object2(this);
function IsValid() {
// tests here
}
}
function _Object2(parentObject)
{
function IsValid() {
// parentObject refers to the _Object1 that created this object
}
}
I think what you're looking for is impossible, unless you are willing to pass the data in to the object.
Just because your _Object2 instance has been created inside the _Object1 constructor, it does not automatically have any reference to the data of your _Object1 instance. You would have to tell the _Object2 instance about the _Object1 values either in the constructor function or via some other method:
function _Object2(parentObject) { /* ... */ }
// or
_Object2.prototype.setParent = function(parent) { /* ... */}
// or
myObject2.parent = this._object1;
Related
everyone, i am trying to wrap my head around factory functions. I want to know what is the proper way to make a factory function that takes in a parameter.
Should the methods we give the objects that it creates refer to its properties by using this. in front on them?
For example:
//using this.
function createPerson(name) {
return {
name,
talk() {
console.log(this.name);
}
}
}
or this way:
//not using this.
function createPerson(name) {
return {
name,
talk() {
console.log(name);
}
}
}
I have tried both and they both seem to perform the same way, which I assume I am probably wrong about. Meaning if i run the following:
const marc = createPerson('marc');
const joe = createPerson('joe');
marc.talk();
joe.talk();
in both cases I get the same output, so is it necessary to use this. in the factory function? What is the common practice? thank you for helping me
Your use case is working with this only because the returned object has that name property.
The context of this is the returned object and not the createPerson function object
If you were to have a variable outside the object and try to access it with this it won't work.
The context of this can be compicated and I think that you can easily get confused knowing what this is in your use case
//not using this.
function createPerson(name) {
// without using new createPerson() "this" is not the function object
const upper = this.upper = name.toUpperCase();
return {
name,
talk() {
console.log('this.upper', this.upper)
console.log('upper', upper);
}
}
}
const foo= createPerson('foo')
foo.talk()
I have a code like that:
User = function(){}
User.a = function(){
return "try";
}
User.b = function(){
}
From User.b() I can call User.a() using:
User.b = function(){
return User.a();
}
but not using this since it's not an instance of user (User.a() and User.b() are something like "static methods").
What i want to do is to be able to call User.a() from User.b() without knowing which is the main function, in this case User.
Something like this to be used in static methods.
In reality there is no methods or static methods in js, there's just functions that are assigned to object properties (functions being objects as well) and they all work the same way. Since you are calling it like User.b(), this will be User for the call.
User.b = function() {
return this.a();
}
The only thing that determines the context of the function is how you call it.
If you call it using a plain identifier (a function name, a variable or a property), the context will be the global window object:
someFunction();
If you call it using a period to access an object member, the context will be the object:
someObject.someFunction();
If you copy a member from an object to a variable, there is no connection to the object any more, and it will be called with window as context:
var x = someObject.someFunction;
x();
If you assign a function as a property to an object, and call it using the object, the context will be the object:
someObject.x = someFunction;
someObject.x();
For your specific case, User is a function, which also is an object.
If you call the function using User.b, its context will be the User object, which happens to be a function in this case. From within the function you can still use this to access the context:
User.b = function(){
return this.a();
}
You don't have normal inheritance in javascript. I guess you are trying to do something like this:
User = function(){
this.a= function(){
return 'try';
}
this.b= function(){
return this.a();
}
}
This way User becomes a constructor. Each new instance of User will have acces to these methods. So if you want to create a new instance of the User class, you can use the new keyword:
var client= new User()
and then you'll have access to all the methods from user using client
client.b() //returns 'try'
Well, functions exist independently of their container objects; they're just values. So if you're not calling them as methods on an object, they inherit whatever this is in the calling context. In that case, expecting them to know about their container would be the same as assigning User.x the value 1 and then expecting the number 1 to somehow know about User.
However, when you call User.a() or User.b(), you are in fact calling them as methods - methods of the (function object) User. So this will be the same as User, and b can just call this.a() and you should be good to go.
Given a class and an instance of it
var class=function() {
this.propA=99;
this.methodA=function() {
console.log(this.propA);
};
};
var object=new Class();
I'd like to be able to perform a call to methodA where this will be the instance of it and the example (this.propA) will work. Exactly as
object.methodA.call(object);
but without having any reference to object. Like this in some pseoducode:
var methodToCall=object.methodA;
...
...
methodToCall.call(getInstanceOwnerOf(methodToCall));
The objective of this is to pass methods as callbacks to async functions and keep this as the instance when the method is called.
Some workarounds would be to pass method and object to that async function, or to store this in a local variable, but these are the things I want to avoid.
Use bind to bind to the context you want function called in. Note this returns a NEW function which is not the same as the original.
I usually create the new function and give it a different name but you can do it multiple ways.
To be more specific, you can't be sure this is the class the function is declared in, depends on how you called the function and if you are in strict mode.
an example below:
Fiddle: https://jsfiddle.net/f7af535L/
class SomeClass {
constructor(someVar) {
this.myVar = someVar;
this.publicSayVar = this.sayVar.bind(this);
}
sayVar() {
console.log(this.myVar);
}
}
var object = new SomeClass("hello");
var testcall = object.publicSayVar;
testcall();
I'm going to try to explain this to the best of my ability. I have an object called BaseForm within that object I have functions and knockout observables. I have a function called Initialize that has an object within it filled with ko observables. One of the observables is called FormVisible and is initialized to true (FormVisible: ko.observable(true)). I also have a function called OnClickRow. In this function it changes FormVisible from true to false. I am instantiating BaseForm multiple times. When I call OnClickRow it only effects the last object that was instantiated. Why does this happen? How can I fix it?
Here's my code:
function BaseForm() {
var that = this;
BaseForm.prototype.Initialize = function(model) {
this.model = model;
this.FormVM = {
FormVisible: ko.observable(true)
}
}
BaseForm.prototype.OnClickRow = function() {
that.FormVM.FormVisible(false);
}
}
this.base1 = new BaseForm();
this.base1.Initialize("new");
this.base2 = new BaseForm();
this.base2.Initialize("old");
this.base3 = new BaseForm();
this.base3.Initialize("other");
this.base1.OnClickRow();
And here is the jsfiddle.
I have actually figured it out. It's a pretty easy fix. I changed this.FormVM to that.FormVM and within OnClickRow I changed that.FormVM.FormVisible(false); to this.FormVM.FormVisible(false). I'm still not enirely sure why this way works and why the other does not. So if anyone has an explanation, that would be great. Thanks!
Here's the updated fiddle.
You need to move the prototype configuration outside of the constructor, and change 'that' to 'this':
function BaseForm() {
var that = this;
}
BaseForm.prototype.Initialize = function(model) {
this.model = model;
this.FormVM = {
FormVisible: ko.observable(true)
}
}
BaseForm.prototype.OnClickRow = function() {
this.FormVM.FormVisible(false);
}
The prototype inheritance chain is called on 'new' or Object.create(). Therefore you should not declare prototype methods in the constructor because there's not guarantee that the prototype chain is initialized yet.
Moving these methods outside the constructor means 'that' would be undefined and using 'this' thus refers to the desired object.
I would suggest a review of the Mozilla Javascript documentation to enhance your knowledge on custom objects.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/A_re-introduction_to_JavaScript#Custom_objects
The solution to this question suggested the use of John Resig's class implementation. This solution covers all my needs except:
How to declare a public global variable inside this class that can be accessed from outside?
I would like to establish something like the following:
var MyClass = Class.extend({
EVENT_NAME : 'event-name',
init : function() {
// ...
}
});
// Now another file can directly read this value without creating the class object
console.log( MyClass.EVENT_NAME );
The "only" way to do what you want to do is to use a function as the "class". This way you are declaring a "class" whose public "static" members can be accessed. Something like this:
function MyObject() {
// constructor stuff here
}
MyObject.EVENT_NAME = "event_name";
console.log(MyObject.EVENT_NAME); // No need to instantiate MyObject
However, seems to me like you are mixing concepts from statically typed languages with Javascript's more dynamic stuff. Why would you want to access a member of an object that has not been created?
Declare it in the window context or don't use the 'var' keyword:
window.globalVar = somevalue
globalVar = somevalue
var MyClass = Class.extend({
EVENT_NAME : 'event-name',
init : function() {
// ...
}
return {
event_name: function() { return EVENT_NAME; }
}
});
console.log( MyClass.event_name );
Actually, to be honest, I'm not sure how the above is going to work with .extend() as I've not actually used extend() before.
However, the return { name:value } technique is a pretty common way of exposing public instance methods in objects. It shouldn't take long to test it properly, sorry I didn't have a chance to do it myself.