I have the following inputModel:
var UserCreateInputModel = function(req) {
...
this.password = req.body.password;
this.repeatPassword = req.body.repeatPassword;
...
console.log(this.password !== this.repeatPassword);
this.validate();
};
UserCreateInputModel.prototype = InputModel;
UserCreateInputModel.prototype.validate = function() {
console.log('Validating...');
if(this.password !== this.repeatPassword) throw new Error('Passwords are not equal!');
};
module.exports = UserCreateInputModel;
In my test I would like to test if the exception was thrown (using node's assert module):
//Act
assert.throws(function() {
new UserCreateInputModel(req);
}, Error);
Somehow the exception is just not thrown. My console output from the constructor is "this".
On the console I don't see the output "Validating".
I guess this is some JavaScript pitfall or something like that (about this) but I'm just not getting the error ...
Update
I have another inputModel in another file. This "inherites" from InputModel too. So it seems UserCreateInputModel.prototype.validate is overridden in the other inputModel. Still don't get it ...
This line:
UserCreateInputModel.prototype.validate = function() {
console.log('Validating...');
if(this.password !== this.repeatPassword) throw new Error('Passwords are not equal!');
};
is modifying the InputModel object. If you have two different types "inheriting" from InputModel with what you have here, and they both have validate methods, then one is overwriting the other.
To properly inherit from InputModel, use Object.create():
UserCreateInputModel.prototype = Object.create(InputModel.prototype);
And then call the parent constructor from your child constructor:
var UserCreateInputModel = function(req) {
InputModel.call(this, <arguments>);
This way, when you modify UserCreateInputModel.prototype, you will only be modifying UserCreateInputModel.prototype and not anything else.
UserCreateInputModel.prototype = InputModel is not how you do inheritance. Who taught you this???!!!
It's:
after the constructor, util.inherits(UserCreateInputModel, InputModel) (where util is require('util')), and
inside the constructor, calling InputModel.apply(this, arguments); or InputModel.call(this, <explicit list of input model ctr args>).
Get back with another EDIT if it still persists.
Related
I wrote this class and have set up an array property for it. Then, I want to add an item to this array.
However, when I try to do it, I get the error “Uncaught TypeError: Cannot read property push of undefined”.
Isn’t this possible?
class test {
constructor() {
this.myArray = [];
}
myMethod() {
this.myArray.push("ok");
}
};
console.log(test.prototype.myMethod());
That’s not how classes are used. You need to instantiate test first, by using new test(). The constructor was never called in your case, so this.myArray was never defined.
This is the only way this can work:
let testInstance = new test();
testInstance.myMethod();
This way, the constructor is called and there will be no error.
Of course, next you’ll need some way of retrieving your array, in order to see the effect.
try to create the instance first. See the code I've commented it in details
test.prototype = {
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var test = function(){
this.myArray = [];
}
test.prototype = { // add our custom constructor and custom methods
constructor: test,
myMethod: function() {
this.myArray.push("ok");
}
};
var myVar = new test(); // create new instance of test
myVar.myMethod(); // run custom method to push val
console.log( myVar.myArray );
You need to initiate your class test first.
var t = new test();
For your information:
console.log(test.prototype.myMethod());
will give you "undefined". Try e.g. :
var t = new test();
t.myMethod();
console.log(t.myArray);
to get output similar to this:
Array [ "ok" ]
If you look at this code:
function supportAggregate(Meanio) {
Meanio.prototype.aggregated = function(ext, group, callback) {
// Aggregated Data already exists and is ready
if (Meanio.Singleton.config.clean.aggregate === false){
return callback('');
}
if (aggregated[group][ext].data) return callback(aggregated[group][ext].data);
// No aggregated data exists so we will build it
sortAggregateAssetsByWeight();
// Returning rebuild data. All from memory so no callback required
callback(aggregated[group][ext].data);
};
Meanio.prototype.aggregatedsrc = function(ext, group, callback) {
// Aggregated Data already exists and is ready
if (Meanio.Singleton.config.clean.aggregate !== false){
if(ext==='js'){
if(group==='header'){
return callback(['/modules/aggregated.js?group=header']);
}else{
return callback(['/modules/aggregated.js']);
}
}else if(ext==='css' && group==='header'){
return callback(['/modules/aggregated.css']);
}
return callback([]);
}
if (aggregated[group][ext].src) return callback(aggregated[group][ext].src);
// No aggregated data exists so we will build it
sortAggregateAssetsByWeight();
// Returning rebuild data. All from memory so no callback required
callback(aggregated[group][ext].src);
};
// Allows rebuilding aggregated data
Meanio.prototype.rebuildAggregated = function() {
sortAggregateAssetsByWeight();
};
Meanio.prototype.Module.prototype.aggregateAsset = function(type, asset, options) {
options = options || {};
if (!options.inline && !options.absolute && !options.url) {
asset = path.join(Meanio.modules[this.name].source, this.name, 'public/assets', type, asset);
}
Meanio.aggregate(type, asset, options, Meanio.Singleton.config.clean);
};
Meanio.onModulesFoundAggregate = function(ext, options) {
var config = Meanio.Singleton.config.clean;
var aggregator = new Aggregator(options, false, config);
for (var name in Meanio.modules) {
aggregator.readFiles(ext, path.join(process.cwd(), Meanio.modules[name].source, name.toLowerCase(), 'public'));
}
};
Meanio.aggregate = function(ext, asset, options, config) {
var aggregator;
options = options || {};
if (!asset) {
return;
}
aggregator = new Aggregator(options, true, config);
if (options.inline) return aggregator.addInlineCode(ext, asset);
else if (options.url) return aggregator.getRemoteCode(ext, asset);
else if (options.singlefile) return aggregator.processDirOfFile(ext, asset);
else return aggregator.readFile(ext, path.join(process.cwd(), asset));
};
Meanio.prototype.aggregate = Meanio.aggregate;
}
module.exports = supportAggregate;
(https://github.com/linnovate/meanio/blob/master/lib/aggregation.js#L213)
You can see that there are two types of functions for Meanio that are created. Also, by the way, you can see where this is instantiated here: https://github.com/linnovate/meanio/blob/master/lib/mean.js#L114
But I'm just confused. Sometime, Meanio functions are defined like this:
Meanio.prototype.myfunction = function() {}
and sometimes they are defined like this:
Meanio.myfunction = function() {}
I just don't get it; although I have a feeling that dependency injection is somehow involved.
How can this be? How can an object be both a class and an instance of itself?
This code is very confusing to me, and I would really appreciate it if someone could shed some light on this for me. I'm not asking you to heavily research the code, but if you could give me a general understanding, that would be great.
Thanks in advance!
How can an object be both a class and an instance of itself?
That's not what's going on here. The object passed to the function is an instance.
The function does however modify both the instance that you pass to it, and the class of that instance.
If you create two instances of the same class, and pass one of them to the function, the other instance is not modified, but the class that is common to them is modified. Example:
function MyClass() {}
var a = new MyClass();
var b = new MyClass();
supportAggregate(a);
Now both a.rebuildAggregated and b.rebuildAggregated exist, as that is added to the class. The a.onModulesFoundAggregate exists because it's added to the instance, but b.onModulesFoundAggregate doesn't exist.
(Note: The example won't actually work, as there is more going on. The class has to have some more properties to work with that function, the example is only to show the difference between properties added to the prototype and to the instance.)
Let's say I have a constructor
// First I will define a constructor
function MyClass() {
this.classproperty = 1;
}
In Javascript the constructor is also an object instance. When I use "this" keyword inside a constructor I'm telling that I want to create a new property inside a special object present in all javascript objects called prototype.
// Then I add a new property without using prototype obj
MyClass.newProperty = 2;
alert(MyClass.classproperty); // alert 1
alert(MyClass.newProperty); // alert 2
// It will work because I'm using the MyClass main Object
When you create a new instance from Myclass Obj. The new created object will inherit the prototype object from parent (the one used to instantiate), but not the properties added straight to MyClass obj:
var instance = new MyClass();
alert(instance.newProperty); // undefined because the new instance will
// inherit only what is inside prototype obj
I have to add it to the prototype object in order to new instances inherit the property;
Myclass.prototype.newProperty = 2;
var instance = new Myclass();
alert(instance.newProperty) // alert 2
i have this node js script:
var EventEmitter = require('events').EventEmitter,
util = require('util');
var pfioObject = function () {
this.init = function () {
console.log("started server");
};
this.deinit = function () {
console.log("stopped server");
};
this.read_input = function () {
return 0;
};
};
console.log(util.inspect(EventEmitter, false, null)); //<--- this shows no method emit either
var pfio = new pfioObject();
var pfioServer = function () {
this.prev_state = 0;
this.start = function () {
pfio.init();
this.watchInputs();
};
this.stop = function () {
pfio.deinit();
};
}
util.inherits(pfioServer, EventEmitter);
// add some event emitting methods to it
pfioServer.prototype.watchInputs = function () {
var state = pfio.read_input();
if (state !== this.prev_state) {
this.emit('pfio.inputs.changed', state, this.prev_state);
this.prev_state = state;
}
setTimeout(this.watchInputs, 10); // going to put this on the event loop next event, more efficient
};
// export the object as a module
module.exports = new pfioServer();
For some reason the node error says that there is no such object as emit, i have done npm install events to see if that will fix it, it didn't. I'm unsure as to why I'm getting this error.
I think somewhere along my code there is an error but I can't see anything.
To run this code I have another script which does this:
var pfioServer = require('./pfioServer'),
util = require('util');
console.log(util.inspect(pfioServer, false, null)); //<--- this line shows the pfioServer with out the prototype function watchInputs
pfioServer.start();
EDIT
I think I may have missed out on some vital bits of code around the event emitter stuff, am looking into instantiation of the event emitter class
Slight Change
So instead of EventEmitter being inherited, i instantiated it by doing var emitter = new EventEmitter()
Then after that I got errors in the util.inspect about the object having to be an object or be null.
No success yet.
I found two things that had to be changed for the first code-block to run without errors:
Explicitly instantiate events.EventEmitter():
var events = require('events'); var EventEmitter = new events.EventEmitter();
Change the call to util.inherits:
util.inherits(pfioServer, events.EventEmitter);
The last thing to make the server run is what robertklep wrote: fix binding in setTimeout()
setTimeout(this.watchInputs.bind(this), 10);
The reason is this line:
setTimeout(this.watchInputs, 10);
When the timeout is triggered and this.watchInputs is called, it has lost its context.
You need to explicitly set the context object (in other words, what this inside the method should point to) for that call by using bind:
setTimeout(this.watchInputs.bind(this), 10);
console.log(util.inspect(EventEmitter, false, null));
// this shows no method emit either
The EventEmitter constructor function does not have such a method. EventEmitter.prototype has. To print the (non-enumerable) .prototype property, you can use util.inspect(EventEmitter, {showHidden: true}) as #Emissary mentioned in the comments.
// this line shows the pfioServer with out the prototype function watchInputs
console.log(util.inspect(pfioServer, false, null));
Yes. util.inspect does not show inherited properties, only those apparent on the pfioServer instance itself.
setTimeout(this.watchInputs, 10);
// going to put this on the event loop next event, more efficient
I'd rather say it prevents an infinite loop… However, this also destroys the this context in the next invokation, which is no more your pfioServer instance. See How to access the correct `this` context inside a callback?
In your case however, I don't see the necessity of using a constructor and inheriting from a prototype anyway. You're just exporting a singleton object, which you simply could instantiate with an object literal and reference by its variable name.
I cannot thank you enough for your time and help! I've searched for almost 2 days and cannot find my exact answer. To begin:
I've always used object literal notation to create my objects. However, I've recently come across a situation where I need to create multiple instances of the same object. I believe what I'm attempting to create are "constructor functions":
I need to have the ability to create multiple "Window" objects:
var window1 = new Window();
var window2 = new Window();
var window3 = new Window();
I want the ability to be able to organize methods as such:
window1.errorMessage.show();
window2.errorMessage.hide();
window3.errorMessage.hide();
Instead of something like:
window1.showErrorMessage();
window2.hideErrorMessage();
window3.hideErrorMessage();
An example of how I would build my window object in literal notation:
var Window = {
id: null,
init : function(id) {
this.id = id;
},
errorMessage : {
show : function(message) {
// jquery that will simply take the id of this window,
// find the errorMessage html element within the window,
// insert the "message" and show it.
},
hide : function() {
// jquery that will simply take the id of this window,
// find the errorMessage html element within this window and hide it.
}
}
}
An example of how I would attempt to build my window object using constructor functions and prototyping:
function Window(id) {
this.id = id;
this.errorMessage = function() {}
}
Window.prototype.errorMessage = function() {}
Window.errorMessage.prototype.show = function(message) {
// jquery that will simply take the id of this window,
// find the errorMessage html element within the window,
// insert the "message" and show it.
}
Window.errorMessage.prototype.hide = function() {
// jquery that will simply take the id of this window,
// find the errorMessage html element within this window and hide it.
}
When I attempt to execute the following code:
var window1 = new Window();
window1.errorMessage.show('An error message');
(Ultimately I would like to call it using:)
this.errorMessage.show('An error message');
I receive the following console errors from Firefox:
TypeError: Window.errorMessage is undefined
TypeError: Window.errorMessage.show is not a function
Thank so much for you help. I appreciate it.
I would still declare your methods on the function's prototype like you attempted, but you'll have to declare show and hide methods on a new ErrorMessage type. I think something like this is the best and most efficient (because instances of ErrorMessage will all share the same show and hide methods) thing to do (if I understand your needs correctly).
function Window(id) {
this.id = id;
this.errorMessage = new ErrorMessage();
}
function ErrorMessage() { }
ErrorMessage.prototype.show = function() {}
ErrorMessage.prototype.hide = function() {}
You only need to use prototype if you're doing inheritance. Since you're not doing inheritance forget about prototype for now.
Each Window has an instance of ErrorMessage. So I would write it like:
function Window(id) {
this.id = id;
this.errorMessage = new ErrorMessage();
}
function ErrorMessage() {
this.show = function () {};
this.hide = function () {};
}
var window1 = new Window();
window1.errorMessage.show();
Is there a clean way to somehow use underscore.js _.extend function (or any other) to create custom Error classes that inherit from base Error class? I'm looking for a backbone-like way to do this.
Tried this :
InternalError = function(message, args) {
message || (message = {});
this.initialize(message, args);
};
_.extend(InternalError.prototype, Error.prototype, {
initialize: function(message, args) {
this.message = message;
this.name = 'InternalError';
}
});
var error1 = new Error('foo');
var error2 = new InternalError('bar');
console.warn(error1, error2);
throw error2;
But it is not working :(.
(Excuse my small parenthesis about prototypal inheritance. You can skip this and see the answer below.
In order for an object to extend another one, the child's prototype must be an instance of it's parent. You can find many good resources on the web about this, but, unfortunately, many bad ones as well, so I recommend you take a peak at this article : http://javascript.crockford.com/prototypal.html .
A new object instantiated via the new keyword : new f() returns a copy of it's prototype object : f.prototype. Acknowledging this, you realize that in order to extend an object x, your current object's prototype must be a new x instance :
function Person(){};
Person.prototype.speak = function(){
alert("I'm a person");
}
function StackoverflowUser(){};
StackoverflowUser.prototype = new Person();
// now StackOverflowUser is a Person too
)
you don't actually need underscore.js for that :
var InternalError = function(msg,args){
return this.initialize(msg||{},args);
}
// inherit from the Error object
InternalError.prototype = new Error();
// overwrite the constructor prop too
InternalError.constructor = InternalError;
InternalError.prototype.initialize = function(msg,args){
this.message = msg;
this.name = 'InternalError';
}
var err = new InternalError("I'm an internal error!");
alert(err instanceof Error); // true
throw err;
if you really want to use underscore.js :
var InternalError = function(msg,args){
return this.initialize(msg||{},args);
}
_.extend(InternalError.prototype,new Error(),{
initialize : function(msg,args){
this.message = msg;
this.name = 'InternalError';
},
constructor : InternalError
});
Extending the error object (and host objects in general) does not work in all browsers. Error.prototype doesn't even exist on IE. There is no need to extend the Error object though, just using any custom object will do, even object literals: {message: 'Really bad error}.