My "base class" does not seem to be populating correctly. Why?
<script type="text/javascript">
var exceptions = {
NotImplementedException: function (message) {
this.name = 'NotImplementedException';
this.message = message || 'Property or method is not implemented.';
}
};
exceptions.NotImplementedException.prototype = Error.prototype;
function ActionButton() {
this.execute = function () {
throw new exceptions.NotImplementedException("Execute is not implemented.");
};
this.render = function (data) {
throw new exceptions.NotImplementedException("Render is not implemented.");
};
this.$template = function () {
throw new exceptions.NotImplementedException("$template is not implemented.");
};
};
function ImageActionButton() {
this.image = { url: '' };
};
function TextActionButton() {
this.text = '';
};
function StandardActionButton() {
this.text = '';
this.image = { url: '' };
};
function MenuActionButton() {
this.buttons = [];
};
ImageActionButton.prototype = new ActionButton();
ImageActionButton.prototype.constructor = ImageActionButton;
TextActionButton.prototype = new ActionButton();
TextActionButton.prototype.constructor = TextActionButton;
StandardActionButton.prototype = new ActionButton();
StandardActionButton.prototype.constructor = StandardActionButton;
MenuActionButton.prototype = new ActionButton();
MenuActionButton.prototype.constructor = MenuActionButton;
// This fails
if (ImageActionButton.prototype != ActionButton) {
alert("ImageActionButton prototype is not ActionButton!");
}
// This works
if (ImageActionButton.prototype.constructor != ImageActionButton) {
alert("ImageActionButton prototype.constructor is not ImageActionButton!");
}
</script>
I think you'll want to use instanceof instead of comparing like you are.
if (ImageActionButton instanceof ActionButton) {
alert("ImageActionButton prototype is not ActionButton!");
}
Related
I was trying to implement some kind of factory that create a class definition in the run time,I figure this work my code look like this
function JsClassFactory() {
this.X = class {
};
this.addMethod = (name, def) => {
let Y = class extends this.X {
constructor() {
super()
this[name] = def
}
}
this.X = Y
return this;
}
this.addAttribute = (name, def) => {
return this.addMethod(name, def)
}
this.getClass = function () {
return this.X
};
}
(function () {
const cf = new JsClassFactory()
cf.addAttribute('age', 35)
cf.addAttribute('name', 'chehimi')
cf.addMethod('myName', function () {
console.log(' i am %s', this.name)
})
cf.addMethod('myAge', function () {
console.log('my age is', this.age)
})
let z = new (cf.getClass())
z.myName();
z.myAge()
cf.addAttribute('name', 'ali')
cf.addAttribute('age', 15)
let t = new (cf.getClass())
t.myName();
t.myAge()
})()
i am asking if there is a better a way to implement this feature?
or a better work arround,
Here is the approach I would take to accomplish this.
class JSClassBuilder {
constructor(){
this.constructedClass = class {};
this.constructedClassAttributes = {};
}
addStatic(name, definition){
this.constructedClass[name] = definition;
return this;
}
addAttribute(name, value){
if(typeof definition != 'function'){
this.constructedClassAttributes[name] = value;
return this;
}
throw new TypeError("parameter value must not be of type: 'function'");
}
addMethod(name, definition){
if(typeof definition == 'function'){
this.constructedClass.prototype[name] = definition;
return this;
}
throw new TypeError("parameter definition must be of type: 'function'");
}
constructClass(){
return Object.assign(
new this.constructedClass(),
this.constructedClassAttributes
);
}
}
const classBuilder = new JSClassBuilder();
const c = classBuilder
.addAttribute('age', 35)
.addAttribute('name', 'Chehimi')
.addMethod('myName', function () {
console.log('I am %s', this.name);
})
.addMethod('myAge', function () {
console.log('I am %s', this.age);
})
.constructClass();
c.myName();
c.myAge();
const a = classBuilder
.addAttribute('name', 'Ali')
.addAttribute('age', 15)
.constructClass();
a.myName();
a.myAge();
We can define a "class" In JavaScript by function, and get its "instance" by the "new" command. Just as follows:
function class_a() {
this.tell = function () {
console.log("This is a_class");
}
}
function class_b() {
this.tell = function () {
console.log("This is b_class");
}
}
var instance_a1 = new class_a();
var instance_b1 = new class_b();
instance_a1.tell();
instance_b1.tell();
My question is: Is there a way to generate these "classes" by the new command from another class? Just like this:
function typex(class_name)
{
...
}
var myclass_a = new typex("class_a");
var myclass_b = new typex("class_b");
var instance_a1 = new myclass_a();
var instance_b1 = new myclass_b();
instance_a1.tell();
instance_b1.tell();
Return the classes from typex but just as reference to the function itself (no invoking inside typex).
Option A: Private classes
function typex(class_name)
{
function class_a() {
this.tell = function () {
console.log("This is a_class");
}
}
function class_b() {
this.tell = function () {
console.log("This is b_class");
}
}
if (class_name === "class_a")
return class_a;
if (class_name === "class_b")
return class_b;
throw new Error("unrecognized classname");
}
Option B: Public classes
function class_a() {
this.tell = function () {
console.log("This is a_class");
}
}
function class_b() {
this.tell = function () {
console.log("This is b_class");
}
}
function typex(class_name)
{
if (class_name === "class_a")
return class_a;
if (class_name === "class_b")
return class_b;
throw new Error("unrecognized classname");
}
Then running the code:
var myclass_a = new typex("class_a");
var myclass_b = new typex("class_b");
var instance_a1 = new myclass_a();
var instance_b1 = new myclass_b();
instance_a1.tell();
instance_b1.tell();
Creates for both the output
This is a_class
This is b_class
Firstly, I end up NOT using the keyword new when calling typex(...), bc I don't want whatever new typex(...) evalutes to to delegate its failed property lookups to typex.prototype.
Secondly, I capitalized MyClass_A and MyClass_B to indicate that they should be paired with the keyword new.
You could just have typex return a constructor function if that is the extent of your use case of these classes/instances.
function typex(class_name) {
var classes = {};
classes.class_a = function() {
this.tell = function() {
console.log('This is a_class');
};
};
classes.class_b = function() {
this.tell = function() {
console.log('This is b_class');
};
};
return classes[class_name];
}
var MyClass_A = typex("class_a");
var MyClass_B = typex("class_b");
var instance_a1 = new MyClass_A();
var instance_b1 = new MyClass_B();
instance_a1.tell(); // "This is class_a"
instance_b1.tell(); // "This is class_b"
instance_a1.constructor === instance_b1.constructor; // false (which is good)
Here's a heavily refactored version that reuses as much code and reduces memory usage as possible.
function typex(class_name) {
var ClassConstructor = function() {
this.class_name = class_name;
};
ClassConstructor.prototype.tell = function() {
console.log('This is ' + this.class_name);
};
return ClassConstructor;
}
var MyClass_A = typex("class_a");
var MyClass_B = typex("class_b");
var instance_a1 = new MyClass_A();
var instance_b1 = new MyClass_B();
instance_a1.tell(); // "This is class_a"
instance_b1.tell(); // "This is class_b"
instance_a1.constructor === instance_b1.constructor; // false (which is good)
So i have this code:
function Class1() {
this.i = 1;
var that=this;
function nn() {
return 21;
}
this.aa = function() {
nn();
};
this.bb = function() {
this.aa();
};
this.cc = function() {
this.bb();
};
}
var o = new Class1();
var b=o.cc();
alert(b); //undefined
But when the alert is fired, I get an undefined error and not 21, Does the private method can not use a return? Thanks!
When using the function() {} syntax to define a function, you always explicitly need to return the value, i.e. not only from nn, but from all intermediate functions as well.
function Class1() {
this.i = 1;
var that = this;
function nn() {
return 21;
}
this.aa = function() {
return nn();
}
this.bb = function() {
return this.aa();
}
this.cc = function() {
return this.bb();
}
}
var o = new Class1();
var b = o.cc();
alert(b); // "21"
Apart from the answer above, the 'this' context seems weird in your functions. Maybe you are better of with arrow functions if you dont want to bind the this context to each function. I also think that it is better to actually separate private and public functions when using a 'class' like this.
function Class1() {
var _nn = function () {
return 21;
}
var _aa = function () {
return _nn();
}
var _bb = function () {
return _aa();
}
var cc = function () {
return _bb();
};
return {
cc
};
}
var o = new Class1();
var a = o.cc();
console.log(a);
Much easier to understand that it is only cc that is a public function.
So with arrow function it would instead look like this, and you can use the Class1 this context inside of your private functions without doing
var that = this; or using bind.
function Class1() {
this.privateThing = 'private';
var _nn = () => { return this.privateThing; };
var _aa = () => { return _nn(); };
var _bb = () => { return _aa(); };
var cc = () => { return _bb(); };
return {
cc
};
}
I'm a beginner with JavaScript Objects and Prototypes and trying to develop my first " multi-level inherited" JS Objects, an unexpected issue came up.
This is my code:
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
Why when I try to call the group manager, it prints only the sayHelloGeneral function?
var GM = new GroupManager;
GM.sayHelloGeneral(); //->ok
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->sayHelloForm is not a function
It seems to be working fine. See the snippet below
var Utils = function () {};
Utils.prototype = {
sayHelloGeneral: function(){
console.log('hello');
}
};
var FormTools = function () {
Utils.call(this);
this.fields = [];
};
FormTools.prototype = Object.create(Utils.prototype);
FormTools.prototype.constructor = FormTools;
FormTools.prototype.sayHelloForm= function (fields) {
console.log('hello form');
};
function GroupManager(value) {
FormTools.call(this);
this.val = typeof values === 'undefined' ? 1 : value;
};
GroupManager.prototype = Object.create(FormTools.prototype);
GroupManager.prototype.constructor = GroupManager;
GroupManager.prototype.helloGroupManager= function (givenValue) {
console.log('Hello group manager');
};
var GM = new GroupManager;
//GM.sayhello(); //->ok---> should be sayHelloGeneral()
GM.sayHelloGeneral();
GM.helloGroupManager(); //--> ok
GM.sayHelloForm(); //->Works fine too
I have a name of a private function in JavaScript as a string, how do I call that function?
var test = function () {
this.callFunction = function(index) {
return this["func" + index]();
}
function func1() { }
function func2() { }
...
function funcN() { }
}
var obj = new test();
obj.callFunction(1);
func1 and friends are local variables, not members of the object. You can't call them like that (at least not in any sane way).
Define them with function expressions (instead of function declarations) and store them in an array.
var test = function () {
this.callFunction = function(index) {
return funcs[index]();
}
var funcs = [
function () {},
function () {},
function () {}
];
}
var obj = new test();
obj.callFunction(0);
As your code stands, the functions are not present as properties of the instance. What you need to do is create them as properties of the context.
var test = function () {
this.callFunction = function(index) {
return this["func" + index];
}
this.func1 = function() { }
this.func2 = function() { }
...
}
var obj = new test();
obj.callFunction(1)();
you can use eval
var test = function () {
this.callFunction = function(index) {
return eval("func" + index + '()');
}
function func1() {
return 1;
}
function func2() {
return 2;
}
function funcN() { }
};
var obj = new test();
obj.callFunction(2);
eval is evil
You can use a private array of functions:
var test = function() {
var func = [
function() { return "one" },
function() { return "two"; }
]
this.callFunction = function(index) {
return func[index]();
}
}
var obj = new test();
var ret = obj.callFunction(1);
console.log(ret);
http://jsfiddle.net/V8FaJ/