I'm in the process of building a "custom" javascript library to use across different projects. The library will be built incrementally i.e. the new classes (functions) will be added as the need arises.
The issue which I'm facing is ensuring that my function name doesn't conflict with other developer's function names. I have thought of the following options, and would like the community to find pros and cons of each. Note each option will make use of the prototype pattern to define classes.
Option 1:
Define classes (function) with your company name append infront of it.
Example:
Mycompany.Dept.Js.Class = function()
{
this.Member1 = 3;
}
MyCompany.Dept.Js.ClassA.prototype.PerformOperation = function()
{
return this.Member1;
}
MyCompany.Dept.Js.ClassB = function()
{
this.Member1 = "Test";
}
MyCompany.Dept.Js.ClassB.prototype.GetValue = function(){ return this.Member1;}
Usage:
var obj1 = new MyCompany.Dept.Js.ClassA();
obj1.PerformOperation();
var obj2 = new MyCompany.Dept.Js.ClassA();
obj2.GetValue();
Issue: I have to use the full class name to define my objects.
Option 2: Module Pattern.
var MyCompany.Dept.Js = function() //IIFE
{
var ClassA = function()
{
this.Member1 = 33;
}`
var ClassB = function()
{
this.Member1 = "Test";
}
ClassA.prototype.PerformOperation = function(){//do something;}
ClassB.prototype.GetValue = function(){//do something;}
return {
BuildObject:function(type)
{
if(type=="ClassA") return new ClassA();
if (type == "ClassB") return new ClassB();
}
}
}();
Usage:
var obj1 = MyCompany.Dept.Js.BuildObject("ClassA");
var obj2 = MyCompany.Dept.Js.BuildObject("ClassB");
obj1.PerformOperation();
obj2.GetValue();
Questions:
Do you see any issues with approach # 2. What are some of the cons? Is there any other technique?
Related
how to create a class in classic jscript? (not jscript.net)
And, how to reference this class?.
I tried with
class someclass {
}
but it does not work.
There are no classes in jscript. You can make an object constructor:
function someclass() {
this.answer = 42;
}
You use it like a class:
var obj = new someclass();
To make methods you add functions to its prototype:
someclass.prototype.getAnswer = function() {
return this.answer;
}
Usage:
var ans = obj.getAnswer();
There are not classes as such, but here's a simple example of how to get basic object-oriented functionality. If this is all you need, great, but if you're after other features of classes, such as inheritance, someone more knowledgeable than myself will have to help.
function SomeClass(n) {
this.some_property = n;
this.some_method = function() {
WScript.Echo(this.some_property);
};
}
var foo = new SomeClass(3);
var bar = new SomeClass(4);
foo.some_method();
bar.some_property += 2;
bar.some_method();
Most recent:
JavaScript/Reference/Classes
Answer from 2011:
You don't really have classes on Javascript, but you have something similar. Check this example on jsFiddle
var classA = function() { // declaring a "class"
this.something = "Text"; // a public class field
};
classA.prototype.b = " b "; // a class field
classA.c = "c"; // a static field
classA.prototype.d = function(x) { // a public class method
};
classA.e = function(x){ // a public static method
};
var a = new classA(); // instantiate a class
Read more on MDC...
Define a function with the name of the class. Any var defined within it as this.whatever will act as a class member:
function SomeClass() {
this.a;
this.b;
}
Then add methods to the prototype:
SomeClass.prototype.methodA = function() {
this.a++;
}
SomeClass.prototype.methodB = function() {
this.b++;
}
I believe you can also define methods inside the constructor like this, but I've not used this syntax for a long time.
function SomeClass {
this.a = 0;
// Method definition
this.methodA = function() {
this.a++;
}
}
Bear with me as I only faintly grasp this myself:
Javascript does not have classes. It has objects. To replicate a class, you create an object. To create "instances" of that "class", you duplicate that object. There are a few ways to do this. One is to create a function that returns an object, then call the function, like so:
function Car(brand, year) {
return {
brand: brand,
year: year
}
}
var modelT = Car("Ford", 1900); //or whenever the model T came out
modelT.brand == "Ford" //true
modelT.year == 1900; //true
Another way is to create an object that is a function and create a "new" of that object. The catch is you have to use new, and that's rather misleading.
var Car = function(make, year) {
this.make = make;
this.year = year;
};
var x = new Car("ford", 1990);
//same tests hold true from earlier example
In my opinion the best way is to use Object.create because it best represents what's actually happening:
var Car = (function() {
var self = Object.create({}, {
make: {
value: "Ford"
}
year: {
value: 1900
}
});
return self;
})();
var modelT = Object.create(Car, {
make: {
value: "Model T"
},
year: {
value: 1901
}
});
Unfortunately, this is extremely cumbersome.
Edit:
This is an extremely helpful resource: JavaScript "classes"
Classes in Jscript (.Net?): http://www.functionx.com/jscript/Lesson05.htm
And Powershell supports it (as well as VisualBasic, even F#). Now I see the question says not in .net. But in my defense, I was googling jscript classes, and this is where I landed.
Add-Type #'
class FRectangle {
var Length : double;
var Height : double;
function Perimeter() : double {
return (Length + Height) * 2; }
function Area() : double {
return Length * Height; } }
'# -Language JScript
[frectangle]::new()
Length Height
------ ------
0 0
I typically see examples of the revealing prototype pattern as shown in syntax #2 below, but i find syntax #1 more consistent. Is there anything different about them other than syntax? Functionally, performance wise, or other?
syntax #1:
function MyClass1(name){
this.name = name;
}
MyClass1.prototype = new function () {
var static = 0;
var getStatic = function () {
return static;
}
this.incStatic = function () {
static++;
return getStatic.call(this);
}
this.constructor = MyClass1
};
exactly the same as this #2:
function MyClass2(name){
this.name = name;
}
MyClass2.prototype = function () {
var static = 0;
function getStatic () {
return static;
}
function incStatic() {
static++;
return getStatic.call(this);
}
return {
incStatic:incStatic,
constructor:MyClass2
};
}();
Here is a fiddle demonstrating the exact same behaviors: http://jsfiddle.net/arctelix/FSk8z/
It appears that both syntax have exactly the same outcome. However, I have never seen an example as shown in #1, so i have to wonder why? For me # 1 is just a more constant syntax and i hate having to identify public members in a special return block.
Personally I consider it improper to reassign something.prototype. Instead, extend the prototype:
(function() {
var static = 0;
MyClass.prototype.getStatic() {return static;}
MyClass.prototype.incStatic() {return static++;}
})();
This whole thing came about because i am creating an MVC framework that utilizes a generic Class constructor. I ran these variations in the larger context of the Class constructor with two different implementation methods. Method 1 reassigns the prototype where method 2 extends it. Method 1 has a uniform prototype chain where method 2 adds a function prototype on top of the object prototype for syntax #1. The performance is about equal for both method 1 and 2.
Blue & Red = syntax #1.
Teal & Green = syntax #2.
Yellow & purple = a variation on syntax #2.
var Class = function (methods, options) {
//allow for Proper class name to show up in browser devtools
options = options || {}
var debug = options.debug || false
var protoTest = options.protoTest || 0
var pInternal = options.pInternal || true
var klassName = methods.constructor.name
console.log('------protoTest =', protoTest, '/ debugClass =', debug, '/ pInternal =', pInternal, '/ klassName = ',klassName)
//compile the constructor & internalMembers
var Class = function () {
//console.log('Class() is building:', !(init instanceof init))
//provide inernal object for constructor
if (pInternal) this.internal = {}
this.constructor.apply(this, arguments);
//remove internal from public scope
if (pInternal){
var int = this.internal
delete this.internal
}
//populate self with this and internal vars
if (pInternal){
var self = {pub:this, int:{}};
for (var v in int){
self.int[v] = int[v];
}
}else var self = this
// Instantiate internalMembers with self
var include = methods.include;
if (include) include.call(this, self);
};
//create constructor function with className (fixes class name in debugger)
if (debug == true && klassName) {
var klass = new Function("init", "return function " + klassName + "(){ init.apply(this,arguments) };")(Class);
}else var klass = Class
console.log('---type', typeof methods.prototype)
if (typeof methods.prototype == 'object'){
//must use traditional revealing prototype
var prototype = methods.prototype;
if (protoTest==0){
//overides prototype
if (prototype) klass.prototype = prototype;
}else{
//does not overide prototype
for (var p in prototype) klass.prototype[p] = prototype[p]
}
}
//create prototype from Class method
//----------------test 0
else if (protoTest==0){
//overides prototype (new has extra proto in chain)
var prototype = methods.prototype;
if (prototype) klass.prototype = new prototype();
}
//----------------test 1
else if (protoTest == 1){
//does not overide prototype and has uniform chain
var pms = new methods.prototype()
for (var p in pms) klass.prototype[p] = pms[p]
}
//----------------end test
//add other Class methods to prototype
var exclude = ['include', 'initialize', 'prototype'];
for (var property in methods) {
if (exclude.indexOf(property) == -1) {
klass.prototype[property] = methods[property];
}
}
return klass; //return the class
};
All the tests: http://jsperf.com/revealing-proto-test/4
The fiddle: http://jsfiddle.net/arctelix/Cp4nG/
There is a debug mode with tests as well: http://jsperf.com/revealing-proto-test/3
How can I add data/functions to all instances of a javascript object created by a constructor so that all instances have the same reference and not a copy of it?
Basically implementing the equivalent of a static method in C#.
For example, given the following code which creates a Widget class.
(function() {
var Widget = function() {
};
Widget.prototype.init = function(data) {
this.data = data;
};
this.Widget = Widget;
}).call(this);
var instance1 = new Widget();
instance1.init('inst1');
var instance2 = new Widget();
instance2.init('inst2');
alert(instance1.data); // inst1
alert(instance2.data); // inst2
In the above case each instance has it's own copy of the data property. However I want to add a function that sets data for all current and future instances.
My current solution is to add a function to the constructor function object, not to it's prototype. See below for example. Is there any pitfalls to this and is there a better way?
(function() {
var Widget = function() {
};
Widget.prototype.init = function(data) {
this.data = data;
};
Widget.addStaticData = function(data) {
this.staticData = data;
};
Widget.prototype.getStaticData = function() {
return Widget.staticData;
};
this.Widget = Widget;
}).call(this);
var instance1 = new Widget();
instance1.init('inst1');
Widget.addStaticData('static');
var instance2 = new Widget();
instance2.init('inst2');
alert(instance1.data); // inst1
alert(instance2.data); // inst2
alert(instance1.getStaticData()); // static
alert(instance2.getStaticData()); // static
Three pitfalls that I can think of:
methodological: the prototype is the place for shared, reused, inherited functionality/properties - utilise it as such
performance: it is quicker to inherit than to set each time on an instance. John Resig (jQuery creator) did some benchmarking on this in a blog post that I appear unable to find at present.
losing the split between inherited and own properties. If you apply everything to an instance via the constructor, everything is an instance property.
Everything via constructor:
function Dog() { this.legs = 4; }
var fido = new Dog();
fido.name = 'Fido';
for (var i in fido) if (fido.hasOwnProperty(i)) alert(i+' = '+fido[i]);
...alerts both properties as they are deemed the instance's own.
Via prototype and constructor
function Dog2() { }
Dog2.prototype.legs = 4;
var fido = new Dog2();
fido.name = 'Fido';
for (var i in fido) if (fido.hasOwnProperty(i)) alert(i+' = '+fido[i]);
...alerts just name because that is the only instance property. (Nonetheless, fido.legs is retrievable - but it comes from the prototype).
[EDIT - in response to the OP's commet below]
If you want a static method, then that should be added to the function after its declaration.
function Dog() {}
Dog.static = function() {}
Consider a local variable staticData instead of the Widget.staticData property. That way, an external command won't be able to write the data directly, so the only way to write it will be through the addStaticData function:
(function () {
var Widget = function () {};
var staticData;
Widget.addStaticData = function ( obj ) {
staticData = obj.data;
};
Widget.prototype.init = function () {
var data = staticData;
// use data
// or just use the staticData variable directly
};
this.Widget = Widget;
}).call( this );
With your code, one could just execute this:
Widget.staticData = { data: 'COMPROMISED!' };
to change the static data. Since you have a dedicated function for setting the static data, you probably don't want it to be possible to change the static data in other ways.
With my code, the above statement has no effect, and the static data can only be changed via the addStaticData function.
Is it possible in javascript to have a variable that is not able to access out side the class's functions, but is able to be accessed by classes that inherit it? I.E:
class1 has protected var x = 4;
class2 inherits class1;
class2.prototype.getVar = function(){return /* parent, uber, super, whatever */ this.x;};
var cl2 = new class2();
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
No. Prototypal inheritance is limited to properties of objects.
Variables within the constructor are only available to other code in that variable scope.
You could probably come up with something like...
function cls1() {
var a = 'foo';
this.some_func = function() {
alert(a);
};
}
function cls2() {
cls1.apply(this, arguments);
var cls1_func = this.some_func;
var b = 'bar'
this.some_func = function() {
cls1_func.apply(this, arguments);
alert(b);
};
}
var x = new cls2;
x.some_func(); // alert "foo" alert "bar"
Or to make it more specific to your pseudo code...
function class1() {
var x = 4;
this.getVar = function() {
return x;
};
}
function class2() {
class1.apply(this, arguments);
var cls1_get_var = this.getVar;
this.getVar = function() {
return cls1_get_var.apply(this, arguments);
};
}
class2.prototype = Object.create( class1.prototype );
var cl2 = new class2;
console.log(cl2.x) // undefined
console.log(cl2.getVar()) // 4
I think you need to use a closure to achieve what your trying to do. Something like this:
Class1 = function() {
var x = 4;
return {
getVar: function() {
return x;
}
}
} ();// executes the function immediately and returns an
//an object with one method - getVar. Through closure this method
//still has access to the variable x
Class2 = function() { };// define a constructor function
Class2.prototype = Class1;//have it inherit from Class1
Cl2 = new Class2();//instantiate a new instance of Class2
console.log(Cl2.x);//this is undefined
console.log(Cl2.getVar());//this outputs 4
This is one of the neat things about javascript in that you can achieve the same things in javascript as you would in a class based language without all the extra key words. Douglas Crockford (always good to consult about javascript) explains prototypal inheritance here
Edit:
Just had a second look at your question.If you want newly created methods in your class to access the variable in the base class then you would have to call the getVar method within your own method.Like such:
Class2 = function() {
this.getVar2 = function() {
return this.getVar();
}
};
console.log(Cl2.getVar2()) //outputs 4
I'm having a little trouble working out how my JavaScript should be structured, etc..
My OOP skills in languages such as PHP, ActionScript 3 and so on are what I'm assuming to be on-par, but JS is lacking this which has thrown me off quite a bit in my learning.
I have a vague understanding of the prototype feature which I used a little in AS2 - I believe this is the closest I'll be able to get. At the moment, I'm laying out my code similar to this:
var slideshow =
{
property: value,
/**
* This is a method
*/
myMethod: function()
{
// do method things
}
};
// ------
slideshow.property ++;
slideshow.myMethod();
This all works okay, but it's void my ability to do something like:
var myslideshow1 = new Slideshow();
var myslideshow2 = new Slideshow();
myslideshow1.property = 10;
myslideshow2.property = 16;
I'm not sure on how to go about creating two different instances of one "object" I've created (in this case, slideshow).
I can't find any resources that explain the prototype feature in a way that makes sense.
Any pointers would be supoib.
Any javascript function can act as a constructor for a class, so try this:
function SlideShow(params) {
return {
property: value,
myMethod: function() {
//do method things
};
};
};
var slideshow1 = new SlideShow(params);
slideshow1.property = 10;
//etc.
I would frown apon using prototype to add methods to a class as there could be performance issues
Here is a sample class structure you could use. JavaScript classes are not much different the functions.
function MyItem(){
this.d = '';
this.clear = function( ) {
this.d = '';
}
}
var myItem = new MyItem( )
myItem.d = "test";
alert(myItem.d);
myItem.clear();
alert(myItem.d)
Some good reading here
You should avoid using the new operator, everything is public. A better way to do what you want to do, and have private variables and functions is to do the following:
var slideshow = function () {
var self = {};
var private_param = "hello";
var private_func = function(say) {
alert(say);
};
var method = function() {
private_func(private_param);
};
var param = 500;
self.method = method;
self.param = param;
return self;
// return object, with the method func and param param publicly accessible
// private_param and private_func are not accessible to the outside
};
var presentation = slideshow(); // new slideshow, you could edit to pass in init params
presentation.method(); // hello