I have a class dynObj, but it appears that seperate instances of it adopt the values of the most recently defined instance.
draw() {
tmov1 = new dynObj(args...); //Displays as a white ball on webpage, as intended
tmov2 = new dynObj(different args...); //Seemingly overwrites the properties of tmov1
objects.push(tmov1, tmov2)
for (var i in objects) {
objects[i].dostuff() //Normally causes the object to display as intended,
}; //but will only ever display one
};
The class dynObj is as follows:
class baseObj {
constructor(position, dimentions, properties) {
this.pos = createVector(position.x,position.y) || null;
this.shape = properties.shape
if (this.shape == "ellipse") {
this.dim = dimentions || {diam:0}
} else if (this.shape == "quadrilateral") {
this.dim = dimentions || { x: 0, y: 0 };
}
};
};
class dynObj extends baseObj {
constructor(position, dimentions, suvat, properties) {
super(position, dimentions, properties);
self = this
self.type = 'dynamic'
self.properties = properties
//more definitions with self.x = someval
};
getDistance(a,b){
if (a == undefined || b == undefined) return false;
var dist = p5.Vector.sub(b,a)
//console.log(dist)
return dist
};
tick(ticksize) {
self.assignLastTick(function(lasttick){
self.lasttick = lasttick
self.time = self.time + ticksize
self.updateSuvat(ticksize)
})
};
//assorted methods...
}
Why do the instances affect eachother?
(Can supply a link to this in action if more context is needed)
The problem is that you're creating a global variable self, and using that instead of this. All the instances are accessing the same global variable, which contains the value of this from the last object that was created.
In the callback function in tick(), you need a way to reference the original object, so you need to bind a local variable self there, rather than using a global variable. See How to access the correct `this` inside a callback?
class dynObj extends baseObj {
constructor(position, dimentions, suvat, properties) {
super(position, dimentions, properties);
this.type = 'dynamic'
this.properties = properties
//more definitions with this.x = someval
};
getDistance(a,b){
if (a == undefined || b == undefined) return false;
var dist = p5.Vector.sub(b,a)
//console.log(dist)
return dist
};
tick(ticksize) {
let self = this;
this.assignLastTick(function(lasttick){
self.lasttick = lasttick
self.time = self.time + ticksize
self.updateSuvat(ticksize)
})
};
//assorted methods...
}
Related
Is there any solution to get the function name of an object?
function alertClassOrObject (o) {
window.alert(o.objectName); //"myObj" OR "myClass" as a String
}
function myClass () {
this.foo = function () {
alertClassOrObject(this);
}
}
var myObj = new myClass();
myObj.foo();
for (var k in this) {...} - there is no information about the className or ObjectName. Is it possible to get one of them?
Get your object's constructor function and then inspect its name property.
myObj.constructor.name
Returns "myClass".
Example:
function Foo () { console.log('Foo function'); }
var f = new Foo();
console.log('f', f.constructor.name); // -> "Foo"
var Bar = function () { console.log('Anonymous function (as Bar)'); };
var b = new Bar();
console.log('b', b.constructor.name); // -> "Bar"
var Abc = function Xyz() { console.log('Xyz function (as Abc)'); };
var a = new Abc();
console.log('a', a.constructor.name); // -> "Xyz"
class Clazz { constructor() { console.log('Clazz class'); } }
var c = new Clazz();
console.log('c', c.constructor.name); // -> "Clazz"
var otherClass = class Cla2 { constructor() { console.log('Cla2 class (as otherClass)'); } }
var c2 = new otherClass();
console.log('c2', c2.constructor.name); // -> "Cla2"
As this was already answered, I just wanted to point out the differences in approaches on getting the constructor of an object in JavaScript.
There is a difference between the constructor and the actual object/class name. If the following adds to the complexity of your decision then maybe you're looking for instanceof. Or maybe you should ask yourself "Why am I doing this? Is this really what I am trying to solve?"
Notes:
The obj.constructor.name is not available on older browsers.
Matching (\w+) should satisfy ES6 style classes.
Code:
var what = function(obj) {
return obj.toString().match(/ (\w+)/)[1];
};
var p;
// Normal obj with constructor.
function Entity() {}
p = new Entity();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
// Obj with prototype overriden.
function Player() { console.warn('Player constructor called.'); }
Player.prototype = new Entity();
p = new Player();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// Obj with constructor property overriden.
function OtherPlayer() { console.warn('OtherPlayer constructor called.'); }
OtherPlayer.constructor = new Player();
p = new OtherPlayer();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// Anonymous function obj.
p = new Function("");
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// No constructor here.
p = {};
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// ES6 class.
class NPC {
constructor() {
}
}
p = new NPC();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
// ES6 class extended
class Boss extends NPC {
constructor() {
super();
}
}
p = new Boss();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
Result:
Code: https://jsbin.com/wikiji/edit?js,console
If you use standard IIFE (for example with TypeScript)
var Zamboch;
(function (_Zamboch) {
(function (Web) {
(function (Common) {
var App = (function () {
function App() {
}
App.prototype.hello = function () {
console.log('Hello App');
};
return App;
})();
Common.App = App;
})(Web.Common || (Web.Common = {}));
var Common = Web.Common;
})(_Zamboch.Web || (_Zamboch.Web = {}));
var Web = _Zamboch.Web;
})(Zamboch || (Zamboch = {}));
you could annotate the prototypes upfront with
setupReflection(Zamboch, 'Zamboch', 'Zamboch');
and then use _fullname and _classname fields.
var app=new Zamboch.Web.Common.App();
console.log(app._fullname);
annotating function here:
function setupReflection(ns, fullname, name) {
// I have only classes and namespaces starting with capital letter
if (name[0] >= 'A' && name[0] <= 'Z') {
var type = typeof ns;
if (type == 'object') {
ns._refmark = ns._refmark || 0;
ns._fullname = fullname;
var keys = Object.keys(ns);
if (keys.length != ns._refmark) {
// set marker to avoid recusion, just in case
ns._refmark = keys.length;
for (var nested in ns) {
var nestedvalue = ns[nested];
setupReflection(nestedvalue, fullname + '.' + nested, nested);
}
}
} else if (type == 'function' && ns.prototype) {
ns._fullname = fullname;
ns._classname = name;
ns.prototype._fullname = fullname;
ns.prototype._classname = name;
}
}
}
JsFiddle
Try this:
var classname = ("" + obj.constructor).split("function ")[1].split("(")[0];
I was facing a similar difficulty and none of the solutions presented here were optimal for what I was working on. What I had was a series of functions to display content in a modal and I was trying to refactor it under a single object definition making the functions, methods of the class.
The problem came in when I found one of the methods created some nav-buttons inside the modal themselves which used an onClick to one of the functions -- now an object of the class. I have considered (and am still considering) other methods to handle these nav buttons, but I was able to find the variable name for the class itself by sweeping the variables defined in the parent window.
What I did was search for anything matching the 'instanceof' my class, and in case there might be more than one, I compared a specific property that was likely to be unique to each instance:
var myClass = function(varName)
{
this.instanceName = ((varName != null) && (typeof(varName) == 'string') && (varName != '')) ? varName : null;
/**
* caching autosweep of window to try to find this instance's variable name
**/
this.getInstanceName = function() {
if(this.instanceName == null)
{
for(z in window) {
if((window[z] instanceof myClass) && (window[z].uniqueProperty === this.uniqueProperty)) {
this.instanceName = z;
break;
}
}
}
return this.instanceName;
}
}
All we need:
Wrap a constant in a function (where the name of the function equals the name of the object we want to get)
Use arrow functions inside the object
console.clear();
function App(){ // name of my constant is App
return {
a: {
b: {
c: ()=>{ // very important here, use arrow function
console.log(this.constructor.name)
}
}
}
}
}
const obj = new App(); // usage
obj.a.b.c(); // App
// usage with react props etc,
// For instance, we want to pass this callback to some component
const myComponent = {};
myComponent.customProps = obj.a.b.c;
myComponent.customProps(); // App
Most efficient way to get your class name during runtime
let className = this.constructor.name
I am using the module pattern for my JavaScript "classes". Is there any significant downside to declaring a var self outisde of the class I am returning and then setting it to this inside the class constructor so that I don't have to worry about the context switching when I don't want it to. In this small example it's probably unnecessary, this is just an example.
Example:
var Seat = (function() {
var self = null;
function Seat(startX, startY, inputSeatNumber, inputTableNumber) {
self = this;
self.radius = 10;
self.x = startX; self.y = startY;
self.seatNumber = inputSeatNumber;
self.tableNumber = inputTableNumber;
}
Seat.prototype.moveTo = function(newX, newY) {
if(newX >= 0 && newY >= 0) {
self.x = newX; self.y = newY;
}
};
return Seat;
})();
EDIT: example added
var SeatingChartView = (function() {
function SeatingChartView(canvas_id, seatingChartController, seatForm) {
this.stage = new createjs.Stage(canvas_id);
this.controller = seatingChartController;
this.seatForm = seatForm;
this.disableRightClick(canvas_id);
}
SeatingChartView.prototype.render = function() {
this.stage.update();
}
SeatingChartView.prototype.addSeat = function(newSeat) {
var newCircle = new createjs.Shape();
newCircle.graphics.beginFill("black").drawCircle(0, 0, 10);
newCircle.x = newSeat.x;
newCircle.y = newSeat.y;
newCircle.seat = newSeat;
newCircle.on('click', function(event) {
if(event.nativeEvent.button == 2) {
this.seatForm.open(event.currentTarget.seat);
}
});
newCircle.on('pressmove', this.controller.moveSeat)
this.stage.addChild(newCircle);
}
SeatingChartView.prototype.removeSeat = function(seat) {
this.stage.children.forEach(function(child) {
if(child.seat === seat) {
this.stage.removeChild(child);
}
});
}
SeatingChartView.prototype.setBackground = function(imageLocation) {
this.background = new createjs.Bitmap(imageLocation);
window.setTimeout(function() {
this.stage.canvas.width = this.background.image.width;
this.stage.canvas.height = this.background.image.height;
this.stage.addChild(this.background);
this.stage.update();
}.bind(this), 500);
}
SeatingChartView.prototype.disableRightClick = function(canvas_id) {
$(function() {
$('#' + canvas_id).bind('contextmenu', function(e) {
return false;
});
});
}
return SeatingChartView;
})();
In that case every new instance of Seat will share the newest Self object since it is set in the constructor. You should avoid doing this.
A more practical demo example might be something like this, where you want to make sure this is the instance of the class.
function Foo() {
var _this = this;
_this.someItem = {};
_this.go = function() {
doSomethingElse(function(result) {
_this.someItem.something = result; // _this and this are different
});
};
};
function doSomethingElse(callback) {
callback('asdf');
}
var foo = new Foo();
foo.go();
For your example using that pattern, you can define the _this in each method if it would be any benefit (this one wouldn't, but a more complex example might):
Seat.prototype.moveTo = function(newX, newY) {
var _this = this;
if(newX >= 0 && newY >= 0) {
_this.x = newX; _this.y = newY;
}
};
Yes, by doing it this way, all instances of Seat will have the same this, causing problems all over the place. Just remove the var self and use this in all places where you were using self. In the code you've given, there's no point where you will lose reference to this.
(#added example) Now your question makes more sense.
Instead of trying to handle this for all methods at once, you'll have to handle it at each point where you're using a function that has a different this (any function that isn't on the prototype or instance).
If you don't need this inside the callback, I would just use .bind to make the instance this available inside. Note however that .bind isn't supported in some (very)old versions of IE, so you'll either need a polyfil to work for those, or store this in a var.
SeatingChartView.prototype.addSeat = function(newSeat) {
var newCircle = new createjs.Shape();
newCircle.graphics.beginFill("black").drawCircle(0, 0, 10);
newCircle.x = newSeat.x;
newCircle.y = newSeat.y;
newCircle.seat = newSeat;
newCircle.on('click', function(event) {
if(event.nativeEvent.button == 2) {
this.seatForm.open(event.currentTarget.seat);
}
}.bind(this)); // modified here, added `.bind(this)`
newCircle.on('pressmove', this.controller.moveSeat)
this.stage.addChild(newCircle);
}
This would totally negate the purpose of "classing". But in JS it's called prototyping.
Principally you want the base prototype to be "copied" when creating new instances. The base prototype should be shielded from changes when extended.
Suppose you have done what you did, all instances of Seat will have the same properties. Even worst, when creating new "copies" of Seat, all other previously created copies will have their values changed.
Since you want this to maintain reference to Seat, I would recommend using the following pattern:
var Base = {
init: function(arg) {
this.name = arg;
},
getName: function() {
return this.name;
}
}
Base.init('foo');
Base.getName(); // returns 'foo'
Your transformed code:
var Seat = {
init: function(startX, startY, inputSeatNumber, inputTableNumber) {
this.radius = 10;
this.x = startX;
this.y = startY;
this.seatNumber = inputSeatNumber;
this.tableNumber = inputTableNumber;
},
moveTo: function(newX, newY) {
if (newX >= 0 && newY >= 0) {
this.x = newX; this.y = newY;
}
},
setBackground: function(imageLocation) {
var self = this;
this.background = new createjs.Bitmap(imageLocation);
setTimeout(function() {
self.stage.canvas.width = self.background.image.width;
self.stage.canvas.height = self.background.image.height;
self.stage.addChild(self.background);
self.stage.update();
}, 500);
}
}
Extend the prototype:
var vipSeat = Object.create(Seat);
vipSeat.init( //your init values )
You can also not create an init method and simply use Object.create's second argument to assignment initial values to the prototype: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create#Example:_Using_propertiesObject_argument_with_Object.create
I have a 'model' class/prototype defined as below, it has subclass named 'given' which tries to access method 'getNodes()' of model class.
But it gives exception for 'this.getNodes' saying undefined.
var model = {
constructor: function(/*string*/ mode, /*string*/ name, /*object*/ properties) {
this._mode = mode;
this.beginX = 100;
this.beginY = 100;
this.nodeWidth = 200;
this.nodeHeight = 200;
this.x = this.beginX;
this.y = this.beginY;
this.lastNodeVisible = null;
this.ID = 1;
this.taskName = name;
this.properties = properties;
this.checkedNodes = new Array();
// this.model = #call_build_method;
/*
add subclasses with model accessors
*/
this.given = {
getNodes: this.getNodes,
setNodeName: this.setNodeName
};
},
getNodes: function() {
// Summary: returns an array containing the nodes in the given model
return #someobject;
},
}
I assume that you want to call a method in the parent class with the correct scope.
Here are two ways to do this, one using dojo hitch, and one without:
require([
"dojo/_base/lang"
],function(lang){
model = function(){
var obj = {
data: "ok",
getData4: function(){
return this.data;
}
};
obj.sub = {
getData5: lang.hitch(obj, obj.getData4),
getData6: function(){return obj.getData4.apply(obj,arguments);}
};
return obj;
};
m = new model();
console.log("call getData4: ", m.getData4()); // returns "ok"
console.log("call getData5: ", m.sub.getData5()); // returns "ok"
console.log("call getData6: ", m.sub.getData6()); // returns "ok"
});
You need to store this in variable in outter scope:
this.model = <SOMETHING>;
var self = this;
this.given = {
getNodes: function(){self.getNodes(self.model);}
// inside a function this is this.given
};
I found a Module pattern in JS:
<script>
var MODULENAME = (function(my, $) {
my.publicVar = "5";
my.publicFn = function() {};
return my;
}(MODULENAME || {}, jQuery));
</script>
However I cannot perform instantiation. Does the module pattern allow for that?
Instantiantion means basically that you'll run a function using new.
So maybe you're looking for this?
var Some = function (param) {
var somePrivateVar = 'private';
this.somePublicVar = 'public';
this.method = function () {
return param;
};
};
var some = new Some('abla');
console.log(some.method());
// some.somePrivateVar === undefined
// some.somePublicVar === 'public'
In your case MODULENAME is an object (object, not a function) with publicVar and publicFn. It's not meant to be instantiated the same way you wouldn't call new jQuery().
Your module object can contain anything. Perhaps you're looking for including a constructor in it:
var MODULENAME = (function(my, $) {
var privateVar = 10;
my.SomeConstructor = function() {
this.publicVar = 5;
}
my.SomeConstructor.prototype.someMethod = function() {};
my.SomeConstructor.prototype.getPrivate = function() { return 10; };
return my;
}(MODULENAME || {}, jQuery));
var instance = new MODULENAME.SomeConstructor();
instance.publicVar; // 5
instance.privateVar; // undefined
instance.getPrivate(); // 10
You can do this also with prototype Inheritance :
var MyClass = function(name)
{
//sharing name within the whole class
this.name = name;
}
MyClass.prototype.getName = function(){
return this.name;//now name is visible to getName method too
}
MyClass.StaticMethod = function()
{
console.log("Im Static");
// and since is not in prototype chain, this.name is not visible
}
var myclass = new MyClass("Carlos");
console.log(myclass.getName())//print "Carlos"
MyClass.StaticMethod()// print "Im Static"
myclass.StaticMethod() // error
Se all this article
Is there any solution to get the function name of an object?
function alertClassOrObject (o) {
window.alert(o.objectName); //"myObj" OR "myClass" as a String
}
function myClass () {
this.foo = function () {
alertClassOrObject(this);
}
}
var myObj = new myClass();
myObj.foo();
for (var k in this) {...} - there is no information about the className or ObjectName. Is it possible to get one of them?
Get your object's constructor function and then inspect its name property.
myObj.constructor.name
Returns "myClass".
Example:
function Foo () { console.log('Foo function'); }
var f = new Foo();
console.log('f', f.constructor.name); // -> "Foo"
var Bar = function () { console.log('Anonymous function (as Bar)'); };
var b = new Bar();
console.log('b', b.constructor.name); // -> "Bar"
var Abc = function Xyz() { console.log('Xyz function (as Abc)'); };
var a = new Abc();
console.log('a', a.constructor.name); // -> "Xyz"
class Clazz { constructor() { console.log('Clazz class'); } }
var c = new Clazz();
console.log('c', c.constructor.name); // -> "Clazz"
var otherClass = class Cla2 { constructor() { console.log('Cla2 class (as otherClass)'); } }
var c2 = new otherClass();
console.log('c2', c2.constructor.name); // -> "Cla2"
As this was already answered, I just wanted to point out the differences in approaches on getting the constructor of an object in JavaScript.
There is a difference between the constructor and the actual object/class name. If the following adds to the complexity of your decision then maybe you're looking for instanceof. Or maybe you should ask yourself "Why am I doing this? Is this really what I am trying to solve?"
Notes:
The obj.constructor.name is not available on older browsers.
Matching (\w+) should satisfy ES6 style classes.
Code:
var what = function(obj) {
return obj.toString().match(/ (\w+)/)[1];
};
var p;
// Normal obj with constructor.
function Entity() {}
p = new Entity();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
// Obj with prototype overriden.
function Player() { console.warn('Player constructor called.'); }
Player.prototype = new Entity();
p = new Player();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// Obj with constructor property overriden.
function OtherPlayer() { console.warn('OtherPlayer constructor called.'); }
OtherPlayer.constructor = new Player();
p = new OtherPlayer();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// Anonymous function obj.
p = new Function("");
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// No constructor here.
p = {};
console.log("constructor:", what(p.constructor), "name:", p.constructor.name, "class:", what(p));
// ES6 class.
class NPC {
constructor() {
}
}
p = new NPC();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
// ES6 class extended
class Boss extends NPC {
constructor() {
super();
}
}
p = new Boss();
console.log("constructor:", what(p.constructor), "name:", p.constructor.name , "class:", what(p));
Result:
Code: https://jsbin.com/wikiji/edit?js,console
If you use standard IIFE (for example with TypeScript)
var Zamboch;
(function (_Zamboch) {
(function (Web) {
(function (Common) {
var App = (function () {
function App() {
}
App.prototype.hello = function () {
console.log('Hello App');
};
return App;
})();
Common.App = App;
})(Web.Common || (Web.Common = {}));
var Common = Web.Common;
})(_Zamboch.Web || (_Zamboch.Web = {}));
var Web = _Zamboch.Web;
})(Zamboch || (Zamboch = {}));
you could annotate the prototypes upfront with
setupReflection(Zamboch, 'Zamboch', 'Zamboch');
and then use _fullname and _classname fields.
var app=new Zamboch.Web.Common.App();
console.log(app._fullname);
annotating function here:
function setupReflection(ns, fullname, name) {
// I have only classes and namespaces starting with capital letter
if (name[0] >= 'A' && name[0] <= 'Z') {
var type = typeof ns;
if (type == 'object') {
ns._refmark = ns._refmark || 0;
ns._fullname = fullname;
var keys = Object.keys(ns);
if (keys.length != ns._refmark) {
// set marker to avoid recusion, just in case
ns._refmark = keys.length;
for (var nested in ns) {
var nestedvalue = ns[nested];
setupReflection(nestedvalue, fullname + '.' + nested, nested);
}
}
} else if (type == 'function' && ns.prototype) {
ns._fullname = fullname;
ns._classname = name;
ns.prototype._fullname = fullname;
ns.prototype._classname = name;
}
}
}
JsFiddle
Try this:
var classname = ("" + obj.constructor).split("function ")[1].split("(")[0];
I was facing a similar difficulty and none of the solutions presented here were optimal for what I was working on. What I had was a series of functions to display content in a modal and I was trying to refactor it under a single object definition making the functions, methods of the class.
The problem came in when I found one of the methods created some nav-buttons inside the modal themselves which used an onClick to one of the functions -- now an object of the class. I have considered (and am still considering) other methods to handle these nav buttons, but I was able to find the variable name for the class itself by sweeping the variables defined in the parent window.
What I did was search for anything matching the 'instanceof' my class, and in case there might be more than one, I compared a specific property that was likely to be unique to each instance:
var myClass = function(varName)
{
this.instanceName = ((varName != null) && (typeof(varName) == 'string') && (varName != '')) ? varName : null;
/**
* caching autosweep of window to try to find this instance's variable name
**/
this.getInstanceName = function() {
if(this.instanceName == null)
{
for(z in window) {
if((window[z] instanceof myClass) && (window[z].uniqueProperty === this.uniqueProperty)) {
this.instanceName = z;
break;
}
}
}
return this.instanceName;
}
}
Most efficient way to get your class name during runtime
let className = this.constructor.name
All we need:
Wrap a constant in a function (where the name of the function equals the name of the object we want to get)
Use arrow functions inside the object
console.clear();
function App(){ // name of my constant is App
return {
a: {
b: {
c: ()=>{ // very important here, use arrow function
console.log(this.constructor.name)
}
}
}
}
}
const obj = new App(); // usage
obj.a.b.c(); // App
// usage with react props etc,
// For instance, we want to pass this callback to some component
const myComponent = {};
myComponent.customProps = obj.a.b.c;
myComponent.customProps(); // App