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.
Related
I have a class I reuse, often, to the tune of possibly tens of thousands of instances in a given session. It occurred to me that creating all these properties within the constructor may be replication, that is each function is unique in memory and not a pointer, so I created a little test setup:
const testTree = function (){
console.log(this, this.konnichiwa);
}
const testFjord = function (aloha){
return function() {
console.log(this, aloha, this.konnichiwa);
}
}
class Clown extends Object{
constructor(props){
super(props);
const aloha = "Hello!"; //<- Private party
this.konnichiwa = "Also hello I think"; //<- Everyone's invited
this.testWan = () => {
console.log(this, aloha, this.konnichiwa);
}
this.testTree = testTree;
this.testFjord = testFjord(aloha);
}
testToo = () => {
console.log(this, this.konnichiwa);
}
}
//export default Clown; //this is an export in my application, used lots
const test = new Clown();
const otherTest = new Clown();
console.log(test.testWan === otherTest.testWan);
console.log(test.testToo === otherTest.testToo);
console.log(test.testTree === otherTest.testTree);
console.log(test.testFjord === otherTest.testFjord);
test.testWan();
test.testToo();
test.testTree();
test.testFjord();
Part 1
As you can test above, testWan, testToo, and testFjord are all unique per instance, but testTree is not. Is there any way to declare a "pointer"/"reusable function" but inside class constructor?
The issue here with testToo and testTree is that they can't access private vars within the constructor like testWan can. testFjord is a factory and can be passed these, but then the returned function is unique and won't be able to interact well with vars passed into it.
It's very likely not possible - I think it's a catch 22 scope thing - but you may know better. The only recourse I can think of is to add a property to this for each thing I need to use in testTree, but that exposes things I may not want exposed outside of the class.
Part 2
This part only applies if this is a generally consistent behavior, and not something completely unique per-browser. Does the engine hold onto references to things like conditionals (which I suspect are sorta anonymous-function-like behind the scenes) once the constructor has run?
I have a fairly knarly conditional setup I'm not going to shove in the code here. This is entirely within the constructor right now. I suspect that, although not a function declaration itself, it is also not a pointer, but an entirely fresh instance per the 'new' in new Clown. It needs to manipulate some private vars and so per Part 1 I haven't figured out a good way to extract this.
Example, there are references to private vars inside the constructor for exposed functions: aloha above is private but used by public testWan function, and so needs to be held after constructor has executed. Is the entire constructor held for the life of test & otherTest or is the constructor going to be dropped after use and just the reference to aloha held in memory?
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 JavaScript class that has this kind of structure:
class MyClass () {
myMethod() {
myCallback = (response) => {
// Do a bunch of stuff by referencing and altering properties in this
}
apiFunction(this.CLASS_PROP, myCallback);
}
}
myMethod is already pretty long, and the contents of myCallback make it even longer, so I tried converting it to this structure:
class MyClass () {
myMethod() {
apiFunction(this.CLASS_PROP, this.myCallback);
}
myCallback = (response) => {
// Do a bunch of stuff by referencing and altering properties in this
}
}
Whereas the first version works fine, the second one loses its reference to the MyClass instance and instead this is pointing to, I think, the call is the API that actually called it. I'm not positive as to why, but my theory is that "lexical context" doesn't mean where the function is defined, but where it's called.
But my question is, is there a way to break that function out of being inside of myMethod into an instance method of MyClass?
There are many ways to write that, one of them being
class MyClass {
myMethod() {
apiFunction(this.CLASS_PROP, r => this._myCallback(r));
}
_myCallback(response) {
// Do a bunch of stuff by referencing and altering properties in this
}
}
Note that in apiFunction there's an arrow function and _myCallback is an ordinary method (=not arrow). The other way around, like in your code, it won't work.
The underscore in _myCallback indicates a private method (a convention, not a special syntax).
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 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;