Javascript inheritance misbehaviour - javascript

I have some js code here link deleted
If you open your js console and you'll run this code snipet
var r = new TempPopupForm("xxx");
r.create();
an error will appear
TypeError: this.init is not a function
this error is saying there is no init method implemented on this object.
But that's not true.As you can see in the code below the init method is declared.
TempPopupForm.prototype = new PopupForm();
TempPopupForm.prototype.constructor = TempPopupForm;
TempPopupForm.superclass = PopupForm.prototype;
function TempPopupForm(name) {
this.init(name);
}
TempPopupForm.prototype.init = function(name) {
TempPopupForm.superclass.init.call(this, name);
};
I guess something is wrong with the inheritance definition,but I can not figure out what it is.
BTW There are some third party dependencies.
EDIT
I was following this article and where the funcs are ordered like I have. The order actually works on the other classes, but not on this one.
http://www.kevlindev.com/tutorials/javascript/inheritance/inheritance10.htm

You need to re-order your functions and instantiation. Since your constructor is using one of its own prototyped method to init, they both need to be above the block where you instantiate the object. JavaScript hoists top-level functions.
Try this -
function TempPopupForm(name) {
this.init(name);
}
TempPopupForm.prototype = new PopupForm();
TempPopupForm.prototype.constructor = TempPopupForm;
TempPopupForm.superclass = PopupForm.prototype;
TempPopupForm.prototype.init = function(name) {
TempPopupForm.superclass.init.call(this, name);
};
var r = new TempPopupForm("xxx");
r.create();

Related

Stats not defined

Cannot figure out why I am getting the error that stats is not defined when it is...
I have tried naming and renaming and calling the previously named function still getting the error
function GameObject(GO){
this.createdAt = GO.createdAt;
this.name = GO.name;
this.dimensions = GO.dimensions;
}
GameObject.prototype.destroy = function(){
return `${this.name} was removed from the game.`;
}
function CharacterStats(stats){
GameObject.call(stats);
this.healthPoints= stats.healthPoints
}
CharacterStats.prototype = Object.create(GameObject.prototype)
CharacterStats.prototype = takeDamage = function(){
return `${this.name} took damage`;
}
function Humanoid(PettyHumans){
this.team = PettyHumans.team;
this.weapons = PettyHumans.weapons;
this.language = PettyHumans.language;
CharacterStats.call(this.PettyHumans)
}
Humanoid.prototype.greet = function(){
return `${this.name} offers a greeting in ${this.language}.`;
}
This code passes undefined to CharacterStats:
function Humanoid(PettyHumans){
this.team = PettyHumans.team;
this.weapons = PettyHumans.weapons;
this.language = PettyHumans.language;
CharacterStats.call(this.PettyHumans)
// ^^^^-------------- The problem is here
}
Assuming you call Humanoid via new Humanoid, you haven't set that property anywhere. PettyHumans is a parameter, not a property. Either set it as a property, or remove the this. from that line.
Side note: In a couple of places it looks like you're trying to implement class-like inheritance (for instance, between CharacterStats and GameObject), but the code doing that isn't quite correct. See this answer (which I also wrote) for how to correct it, either continuing with ES5 syntax or using ES2015+ class syntax. But briefly, the minimal change to make it correct is to add a line:
GameObject.call(stats);
this.healthPoints = stats.healthPoints
}
CharacterStats.prototype = Object.create(GameObject.prototype)
CharacterStats.prototype.constructor = CharacterStats // Add this (and similar when doing other inheritance)
Or, again, use class. (You can transpile if you need to support ES5-only JavaScript engines.)

Richembed not working [duplicate]

I am defining an object like this:
function Project(Attributes, ProjectWidth, ProjectHeight) {
this.ProjectHeight = ProjectHeight;
this.ProjectWidth = ProjectWidth;
this.ProjectScale = this.GetProjectScale();
this.Attributes = Attributes;
this.currentLayout = '';
this.CreateLayoutArray = function()
{....}
}
I then try to create an instance like this:
var newProj = new Project(a,b,c);
but this exception is thrown:
Project is not a constructor
What could be wrong? I googled around a lot, but I still can't figure out what I am doing wrong.
The code as posted in the question cannot generate that error, because Project is not a user-defined function / valid constructor.
function x(a,b,c){}
new x(1,2,3); // produces no errors
You've probably done something like this:
function Project(a,b,c) {}
Project = {}; // or possibly Project = new Project
new Project(1,2,3); // -> TypeError: Project is not a constructor
Variable declarations using var are hoisted and thus always evaluated before the rest of the code. So, this can also be causing issues:
function Project(){}
function localTest() {
new Project(1,2,3); // `Project` points to the local variable,
// not the global constructor!
//...some noise, causing you to forget that the `Project` constructor was used
var Project = 1; // Evaluated first
}
An additional cause of this can be ES2015 arrow functions. They cannot be used as constructors.
const f = () => {};
new f(); // This throws "f is not a constructor"
For me it was the differences between import and require on ES6.
E.g.
processor.js
class Processor {
}
export default Processor
index.js
const Processor = require('./processor');
const processor = new Processor() //fails with the error
import Processor from './processor'
const processor = new Processor() // succeed
I've googled around also and found this solution:
You have a variable Project somewhere that is not a function. Then the new operator will complain about it. Try console.log(Project) at the place where you would have used it as a construcotr, and you will find it.
For my project, the problem turned out to be a circular reference created by the require() calls:
y.js:
var x = require("./x.js");
var y = function() { console.log("result is " + x(); }
module.exports = y;
x.js:
var y = require("./y.js");
var my_y = new y(); // <- TypeError: y is not a constructor
var x = function() { console.log("result is " + my_y; }
module.exports = x;
The reason is that when it is attempting to initialize y, it creates a temporary "y" object (not class, object!) in the dependency system that is somehow not yet a constructor. Then, when x.js is finished being defined, it can continue making y a constructor. Only, x.js has an error in it where it tries to use the non-constructor y.
I have a class in one file that I'm importing into a test file:
//Vec.js
class Vec {
}
module.exports.Vec = Vec;
Changing
//Vec.test.js
const Vec = require('./Vec');
const myVec = new Vec(); //TypeError: Vec is not a constructor
to
//Vec.test.js
const {Vec} = require('./Vec');
const myVec = new Vec(); //Succeeds!
resolved this error for me.
In my case I was using the prototype name as the object name. For e.g.
function proto1()
{}
var proto1 = new proto1();
It was a silly mistake but might be of help to someone like me ;)
Sometimes it is just how you export and import it. For this error message it could be, that the default keyword is missing.
export default SampleClass {}
Where you instantiate it:
import SampleClass from 'path/to/class';
let sampleClass = new SampleClass();
Option 2, with curly braces:
export SampleClass {}
import { SampleClass } from 'path/to/class';
let sampleClass = new SampleClass();
I just want to add that if the constructor is called from a different file, then something as simple as forgetting to export the constructor with
module.exports = NAME_OF_CONSTRUCTOR
will also cause the "Not a constructor" exception.
To add to #wprl's answer, the ES6 object method shorthand, like the arrow functions, cannot be used as a constructor either. 😅
const o = {
a: () => {},
b() {},
c: function () {}
};
const { a, b, c } = o;
new a(); // throws "a is not a constructor"
new b(); // throws "b is not a constructor"
new c(); // works
Car.js
class Car {
getName() {return 'car'};
}
export default Car;
TestFile.js
const object = require('./Car.js');
const instance = new object();
error: TypeError: instance is not a constructor
printing content of object
object = {default: Car}
append default to the require function and it will work as contructor
const object = require('object-fit-images').default;
const instance = new object();
instance.getName();
In my case this happened due to a circular reference between two classes. I imported class B in the class A file and imported class A in the class B file, so the program never reached to the point of actually define A as a class.
I just had a similar error when trying to use the BS5ModalJS in conjunction with webpack, meaning I was trying to import the js file.
Because the single .js file provided was designed to be used via the script tags, it took a while for me to realise that to avoid the "BSModal is not a constructor" error, I had to go into their code and add:
export {BSModal}
I was then able to use
import { BSModal } from './../thirdparty/BS5ModalJS/BS5Modal.js';
and do
let myModal enter code here= new BSModal(...)
without getting that error.
So if you're using webpack, perhaps make sure the classes and functions are exported (and therefore available) to the callers.
In my case I'd forgotten the open and close parantheses at the end of the definition of the function wrapping all of my code in the exported module. I.e. I had:
(function () {
'use strict';
module.exports.MyClass = class{
...
);
Instead of:
(function () {
'use strict';
module.exports.MyClass = class{
...
)();
The compiler doesn't complain, but the require statement in the importing module doesn't set the variable it's being assigned to, so it's undefined at the point you try to construct it and it will give the TypeError: MyClass is not a constructor error.
I had a similar error and my problem was that the name and case of the variable name and constructor name were identical, which doesn't work since javascript interprets the intended constructor as the newly created variable.
In other words:
function project(name){
this.name = name;
}
//elsewhere...
//this is no good! name/case are identical so javascript barfs.
let project = new project('My Project');
Simply changing case or variable name fixes the problem, though:
//with a capital 'P'
function Project(name){
this.name = name;
}
//elsewhere...
//works! class name/case is dissimilar to variable name
let project = new Project('My Project');
It is happening because you must have used another variable named "project" in your code. Something like
var project = {}
For you to make the code work, change as follows:
var project = {} into var project1 = {}
To add the solution I found to this problem when I had it, I was including a class from another file and the file I tried to instantiate it in gave the "not a constructor" error. Ultimately the issue was a couple unused requires in the other file before the class was defined. I'm not sure why they broke it, but removing them fixed it. Always be sure to check if something might be hiding in between the steps you're thinking about.
In browse (assuming your app is running), inspect, source, and make sure the javascript file for the constructor is loaded.
For me this happened because of a small typo.
I had a class export like ->
module.export = class TestClass {
constructor() {}
}
And I was trying to use this class as ->
const testClass = new TestClass();
The problem and typo was at module.export, which should be module.exports so
module.exports = class TestClass { // module.exports here instead of export
constructor() {}
}

Losing context in JS function call chain

I have got some JS "objects" I'm using for some complexe stuff. So the following code is reduced to the needed minimal informations:
function AttributeWrapper(model) {
var self = this;
var attributeModel = model;
self.labelPrimitive = null;
self.mandatorySignPrimitive = null;
self.documentationPrimitive = null;
self.valuePrimitive = null;
self.isHidden = function() {
return false;
}
}
function Primitive(model, wrapper) {
var self = this;
var groupingObject = wrapper;
self.model = model;
self.layoutCell = null;
self.render = function() {
if (self.isHidden()) {
return;
}
self.layoutCell.getDomElement().innerHTML = self.model.id || "TODO";
}
self.isHidden = function() {
return groupingObject.isHidden();
}
}
This objects are used mainly like this:
function AnOtherObject {
var self = this;
self.anyFunction = function() {
var wrapper = new AttributeWrapper(model);
var primitive = new Primitive(anOtherKindOfModel, wrapper);
var isHidden = primitive.isHidden();
}
}
For any reason the first call works fine. So the function in the Primitive "class" is called and the scope is correct (variables are set as expected). Also the call by the Primitive class of its contained object (instance of AttributeWrapper) works, but there the context is messed up. I would expect that I can access the instance variables like attributeModel in the "isHidden" function but they do not exist anymore. Also "self" is not the instance but something else (looking like the global "document" or "window" instance), but "this" revers to the instance...
Is there anything i did wrong at the declaration of the objects? I do not understand why the call of the first objects works but the sub-object is wired...
Problem seems to be solved...
I'm using visual studio for debugging. The "return false" of the "isHidden" function in AttributeWrapper was written to place a breakpoint and continue writting the code for this function (to see the objects and their fields in the debugger). When the breakpoint was hitted I had the descript problem.
Today I had a look on it with a colleague who had the idea that maybe just the debugger is confused somehow and do not show the correct state.
So i finished the code and started debugging again. Suddenly the state was correct when the breakpoint gets hit.
So it seems the problem realy was a confused debugger and everthing was working correctly. By using something from the context in the function this confusion seems to be solved...
Lesson learned: visual studio maybe isnt the best choice to debug javascript =)

Javascript apply — Inheriting classes

The code below is adapted from this answer
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
ErrorMessageClass.prototype = new MessageClass();
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
var errorA = new ErrorMessageClass();
var errorB = new ErrorMessageClass();
errorA.setPrivate('A');
errorB.setPrivate('B');
console.log(errorA.getPrivate());
console.log(errorB.getPrivate());
The original post did not have the MessageClass.apply(this, arguments); since the purpose was to show how inheritance can go wrong in Javascript.
My question is, is saying: ErrorMessageClass.prototype = new MessageClass(); before the ErrorMessageClass constructor has even been declared bad practice? My understanding is that calling undeclared identifiers like that causes a silent declaration to occur, with the result being placed on the global window object, which I understand is bad.
Is this form:
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
ErrorMessageClass.prototype = new MessageClass();
considered to be better practice? This link shows the code written as it was originally above, which is why I even tried it. Does this blogger know something I don't (quite likely)?
EDIT
Lots of great info in the answers below, but I did want to highlight this link which really explains things perfectly
Usually, to avoid this confusion, you would just attach the prototype after, but as Adam Rackis pointed out, function declarations are hoisted, like var statements.
However, you should not instantiate the base object as the prototype. If your base object takes arguments, what are you supposed to use? Use an empty "surrogate" constructor
// Used to setup inheritance
function surrogate () {};
function MessageClass() {
var self = this;
this.clickHander = function(e) { self.someoneClickedMe = true; };
var _private = 0;
this.getPrivate = function() { return _private; };
this.setPrivate = function(val) { _private = val; };
}
// The key steps to creating clean inheritance
surrogate.prototype = MessageClass;
// Sets up inheritance without instantiating a base class object
ErrorMessageClass.prototype = new surrogate();
// Fix the constructor property
ErrorMessageClass.prototype.constructor = ErrorMessageClass
function ErrorMessageClass() {
MessageClass.apply(this, arguments);
}
There's much more to be said. http://js-bits.blogspot.com/2010/08/javascript-inheritance-done-right.html
It works because function declarations are evaluated first. If you tried to move these classes under an object literal "namespace" the first version would fail.
I personally find the second method to be much easier to read - also, don't forget to set the sub-class' prototype.constructor property back to itself. Personally, I use an inherits() method on the Function prototype which wraps up essentially the type of code you're using here.

Object Creation in javascript

Just for the kicks i am trying to create a simple data object in javascript. Here is the code.
var roverObject = function(){
var newRover = {};
var name;
var xCord;
var ycord;
var direction;
newRover.setName = function(newName) {
name = newName;
};
newRover.getName = function() {
return name;
};
newRover.setDirection = function(newDirection) {
direction = newDirection;
};
newRover.getDirection = function() {
return direction;
};
newRover.setXCord = function(newXCord) {
xCord = newXCord;
};
newRover.getXCord = function() {
return xCord;
};
newRover.setYCord = function(newYCord) {
yCord = newYCord;
};
newRover.getYCord = function() {
return yCord;
};
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
return newRover;
};
rover1 = new roverObject();
rover2 = new roverObject();
rover1.setName("Mars Rover");
rover1.setDirection("NORTH");
rover1.setXCord(2);
rover1.setYCord(2);
console.log(rover1.where());
console.log(rover1);
rover2.setName("Moon Rover");
rover2.setDirection("SOUTH");
rover2.setXCord(1);
rover2.setYCord(1);
console.log(rover2.where());
console.log(rover2);
There are few questions that I have around this creation.
I want to create an object where the properties/attributes of object are private and not visible to world. Am I successful in doing that? Can I really not access the object attributes?
Is there a better way to create this kind of object?
If I want to inherit this object, I should do a newObject.prototype = roverObjectwill that work? And will that make sense most of all.
Finally I have a wierd problem. Notice the last method of objet "where" which returns a concatenated string. Here I tried following code instead.
newRover.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
}();
and then did a following console.log
console.log(rover1.where);
console.log(rover2.where);
It threw following error for me:
cannot access optimized closure
Why would it say that? What am I doing wrong?
Thanks for all the help. Any review comments would be appreciated too!
Cheers
Am I successful in doing that? Can I really not access the object attributes?
Indeed. You don't have object attributes, you have local variables in the roverObject function. Local variables can't be accessed from outside, only from the functions inside the roverObject function that have a closure over them.
That you are calling roverObject as a constructor, with new roverObject, is irrelevant, as you are returning a different object from the function. Saying var rover1= roverObject() without the new would do exactly the same thing. Notably the object returned by [new] roverObject is a plain Object as you created it from {}; rover1 instanceof roverObject is false.
If you wanted instanceof to work, you would have to call with new, and use this instead of newRover in the constructor function.
If I want to inherit this object, I should do a newObject.prototype = roverObject will that work? And will that make sense most of all.
No. You currently have no allowance for prototyping. You are using a separate copy of each method for each instance of the roverObject. You can do certainly objects this way but it's a different approach than prototyping. If you wanted to make something like a subclass of roverObject in the arrangement you have now, you'd say something like:
function AdvancedRover() {
var rover= new roverObject();
rover.doResearch= function() {
return rover.where()+' and is doing advanced research';
};
return rover;
}
Note since the ‘private’ local variables in the base class constructor really are private, even the subclass cannot get at them. There's no ‘protected’.
newRover.where = function(){ ... }();
What's that trying to do? I can't get the error you do; all the above does is assigns the string with the location to where (before the setter methods have been called, so it's full of undefineds).
Is there a better way to create this kind of object?
Maybe. see this question for a discussion of class/instance strategies in JavaScript.
Q1: you can create 'private' members in javascript 'classes'. In javascript, privacy is not determined by any access specifier. Instead, access needs to be specifically instrumented. Example:
function MyClass() {
this.val = 100; // public;
var privateVal = 200;
function getVal() { return this.val; } // private method;
this.getPrivateVal = function() { // public method, accessor to private variable
return privateVal;
}
}
Object scope in javascript is governed by a queer concept called closures. AFAIK, there is no parallel concept in any other popular launguage like C+/Java etc.
While I understand what closures are, I cannot put it in words. Perhaps a demonstration will help you:
function closureDemo() {
var done=false;
function setDone() { done=true; }
doLater(setDone);
}
function doLater(func) { setTimeout(func,1000); }
closureDemo();
now, while setDone is called from within doLater, it can still access done in closureDemo, even though done is not in scope (in the conventional procedural sense).
I think you will understand more when you read this.
Q2: I can only say what I do; I don't know if it is better or not. If I wrote your code, it would look like this:
function RoverObject() {
var newRover = {}; // privates
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) {
name = newName;
};
this.getName = function() {
return name;
};
this.setDirection = function(newDirection) {
direction = newDirection;
};
// and so on...
this.where = function(){
return "Rover :: "+ name +" is at Location("+xCord+","+yCord+") pointing to "+direction;
};
}
var rover1 = new RoverObject();
Points to note:
capitalization of "class name"'s first letter
use of this instead of roverObject
this function is a pure constructor. it returns nothing.
Q3: if you want to do inheritance, then my method (use of this) will not work. Instead, the public methods should be a part of the prototype of RoverObject. Read this. Excellent material.
Hope that helps.
EDIT: There is a problem with the way your code is doing work. Problems:
your function does not do what its name suggests. Its name had better be createRoverObject, because that's exactly what it is doing. It is not working like a class constructor
the methods supported by your class are part of the object, but the data members are not. While this may work (and it is not, as your console.log() problem suggests), it is not a good way to implement a class in javascript. The problem here is of closures. Again, i'm unable to articulate what the problem specifically is, but I can smell it.
With regards to 4. - you are trying to log the function, not the result of calling the function. Should be console.log(rover1.where()); My guess firebug(I assume it's firebug's console.log) does not like to log function definitions.
EDIT Oh I get it, you are actually executing the where funcion when you assign rover.where. Are you trying to get what looks like a property to actually be a function? If that's the case it won't work. It will have to be a function if you want it to be evaluated when it's called.
What happens in you case where gets executed in the constructor function. At that point you are still creating the roverObject closure and hence it's too early to access it's private variables.
This is just addressing point 1 of your post.
Here's a good article on javascript private members and more:
Private Members in JavaScript
Defining your object like this gives you private members.
function RolloverObject() {
var name;
var xCord;
var ycord;
var direction;
this.setName = function(newName) { name = newName; };
this.getName = function() { return name; };
this.setDirection = function(newDirection) { direction = newDirection; };
this.getDirection = function() { return direction; };
this.setXCord = function(newXCord) { xCord = newXCord; };
this.getXCord = function() { return xCord; };
this.setYCord = function(newYCord) { yCord = newYCord; };
this.getYCord = function() { return yCord; };
this.where = function() {
return "Rover :: " + name + " is at Location(" + xCord + "," + yCord + ") pointing to " + direction;
};
}
var rolloverObject = new RolloverObject();

Categories

Resources