A framework for emulating instance and static variables? - javascript

I have one here:
http://jsfiddle.net/s9dLb/2/
What I noticed is that in this framework, all variables are static ( they are on the prototype chain ), and are only "instance" based if you set them in the constructor.
I'm using these terms from CS101 usually taught via Java.
Is there a better way to do this?
By default I set instance variables to a string 'instance' which will be replaced once the constructor is called.
var klass = function (obj, config_module) {
if (config_module === 'constructor') {
var object_public;
if (obj.constructor) {
object_public = obj.constructor;
delete obj.constructor;
}
_.some(obj, function (val, key) {
object_public.prototype[key] = val;
});
return object_public;
}
};
var Test = klass({
// instance, set in constructor
A : 'instance',
// static, not set in constructor
B : 4,
constructor: function (some_var) {
this.A = some_var;
},
get: function () {
return 2;
},
set: function () {
}
}, 'constructor');
var instanceA = new Test('A');
var instanceB = new Test('B');
console.log('Start');
console.log(instanceA.A);
console.log(instanceB.A);

Give MooTools a try. It is as close as it can get without the use of other languages which compile to JavaScript (like CoffeScript or TypeScript).
Here is an example MooTools class:
Foo = new Class({
// instance variable:
name: '',
// construtor:
initialize: function(name) {
this._setName(name);
},
// instance method:
getName: function(){
return this.name;
},
// protected instance method:
_setName: function(name) {
this.name = name;
}.protect()
});
// static variable:
Foo.bar = 'bar';
// static method
Foo.bar = function(){}
// instance object:
var myFoo = new Foo('my new name');
var theName = myFoo.getName();
var checkInstance = instanceOf(myFoo, Foo);
Fiddle

Related

Javascript class properties behave as shared variable

I have the following declaration to easily create classes in Javascript. The Class is from this article: http://ejohn.org/blog/simple-javascript-inheritance/
JSfiddle: http://jsfiddle.net/xUCQp/
The problem is that it seems like that options of the object seems shared through the objects, but I need them to be instance variables. What is the problem with the code?
Code:
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function() {
var initializing = false, fnTest = /xyz/.test(function() {
xyz;
}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.NClass = function() {
};
// Create a new Class that inherits from this class
NClass.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn) {
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function NClass() {
var $this = this;
// All construction is actually done in the init method
if (!initializing && this.init)
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
NClass.prototype = prototype;
// Enforce the constructor to be what we expect
NClass.prototype.constructor = NClass;
// And make this class extendable
NClass.extend = arguments.callee;
return NClass;
};
})();
(function (scope, undefined) {
scope.ssTypeBase = NClass.extend({
options: {
test: 0
},
init: function(test){
this.options.test = test;
}
});
var a = new scope.ssTypeBase(1);
var b = new scope.ssTypeBase(2);
console.log(a.options.test,b.options.test);
})(window);
Prototype properties are always shared between the objects. So in this case if you want options object to be instance variable than set options object inside constructor like this
(function (scope, undefined) {
scope.ssTypeBase = NClass.extend({
sharedOptionsObject: {
test: 0
},
init: function(test){
// create options object here, it will create seperate options object for each instance
this.options = {
test: 0
}
this.options.test = test;
}
});
});

Advantages of extending prototype instead of declaring whole object

When should I use first notation:
var object = {
a: function() {
// object.a method body
},
b: function() {
// object.b method body
},
c: function() {
// object.c method body
},
};
and when the second one?
function Class() {};
Class.prototype.a = function() {
// object.a method body
};
Class.prototype.b = function() {
// object.b method body
};
Class.prototype.c = function() {
// object.c method body
};
var object = new Class();
The main advantage is that the functions are shared by all instances in second case, which makes the objects lighter. It explicitly defines the objects as instances of what is conceptually a class.
But the correct syntax is
function MyClass(){
}
MyClass.prototype.a = function(){
};
...
var o = new MyClass();
It also allows you to define an inheritance chain :
function OtherClass(){
}
OtherClass.prototype = new MyClass(); // makes OtherClass extend MyClass
OtherClass.prototype.b = function(){
};
...
var o2 = new OtherClass();
o2 has the functions of both OtherClass and MyClass.
The MDN gives more details in its Introduction to Object-Oriented JavaScript.

Static variables with John Resig's simple class pattern?

I'm referring to this article.
In it, he defines a function that looks something like this:
function makeClass() {
return function _class() {
if(this instanceof _class) {
if(typeof this.init === 'function') {
this.init.apply(this, arguments);
}
} else {
throw new Error('Constructor called as a function');
}
};
}
And then you can use it with something like this:
var MyClass = makeClass();
MyClass.prototype = {
init: function(width, height) { ... },
clear: function(ctx) {... },
draw: function(ctx) { ... }
}
But now I want to initialize some static variables that should be shared across all instances. How do I do that?
Well, the easiest approach is to define a static variable as a prototype property:
MyClass.prototype.xxx: 3, // ...
var t1 = new MyClass();
console.log(t1.xxx); // 3
... but it won't behave as static properties in other languages usually do:
var t2 = new MyClass();
t2.xxx = 5;
console.log(t1.xxx); // still 3 :(
The other way around is to use the fact that properties might be attached to functions as well:
MyClass.xxx = 3;
... but that narrows the ways we can use this property (it can't be called by t1.xxx from the previous examples).
There's another way, though. One can define static properties as variables, local to init method, accessible by methods, defined... in this init method as well. ) Like this.
init: function() {
var xxx = 3;
MyClass.prototype.getXXX = function() {
return xxx;
};
MyClass.prototype.setXXX = function(newXXX) {
xxx = newXXX;
}
}
Then all one can use this property simply by this:
var t1 = new MyClass();
var t2 = new MyClass();
console.log(t1.getXXX()); // 3
console.log(t2.getXXX()); // 3
t1.setXXX(5);
console.log(t1.getXXX()); // 5 now
console.log(t2.getXXX()); // 5 as well, behold the power of closures!
And here's a fiddle used.
UPDATE: this approach is better be used, I suppose, when we need to work with a (sort of) container of the static class data, that is to be shared by all objects - but we don't know exactly what can actually be stored in this container. Then we use just two functions - getStatic and setStatic - to store and retrieve data by string keys or some other identifiers. It may seem a bit confusing, and it is, but I think it may be worth an effort. )
Just add it to MyClass itself.
MyClass.myVariable = 42;
It's not really static in the Java/C# sense, but gives you the same effect.
I "solved" this problem by using a naming convention.
I wanted the convenience of the Class.extend({ }) syntax, but also a way to declare "static" properties within it.
I opted for a leading underscore to declare a static property, although you could do whatever you liked.
Usage:
var myClass = Class.extend({
_staticProperty: 1337
, instanceProperty: 'foo'
, instanceMethod: function() { }
, ctor: function() {
this.base();
}
});
note I've renamed init and this._super() from the original code
And the code:
/* Simple JavaScript Inheritance
* Modified by Andrew Bullock http://blog.muonlab.com to add static properties
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function () {
var initializing = false, fnTest = /xyz/.test(function () { xyz; }) ? /\bbase\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function () { };
// Create a new Class that inherits from this class
Class.extend = function (prop) {
var base = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// The dummy class constructor
function Class() {
// All construction is actually done in the ctor method
if (!initializing && this.ctor)
this.ctor.apply(this, arguments);
}
// Copy static properties from base
for (var name in this) {
if (name.substr(0, 1) == '_')
Class[name] = this[name];
}
// Copy the properties over onto the new prototype
for (name in prop) {
// Check if we're overwriting an existing function
if (typeof prop[name] == "function" && typeof base[name] == "function" && fnTest.test(prop[name])) {
prototype[name] = (function(name, fn) {
return function() {
var tmp = this.base;
// Add a new .base() method that is the same method
// but on the super-class
this.base = base[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this.base = tmp;
return ret;
};
})(name, prop[name]);
} else if (name.substr(0, 1) == '_') {
Class[name] = prop[name];
} else {
prototype[name] = prop[name];
}
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
If you don't care about browser support, you could also use a WeakMap of constructor/static properties pairs. Here's the idea: http://jsfiddle.net/DfNNU/2/. This requires MyClass.prototype.constructor, which you should not discard. So, you'd need to add back constructor: MyClass to the prototype.
var statics = (function() {
var map = new WeakMap;
return function(inst) {
var ctor = inst.constructor;
return map.get(ctor) || map.set(ctor, {});
};
})();
Use it like:
var a = function() {};
var b = function() {};
var inst1 = new a;
var inst2 = new a;
var inst3 = new b;
statics(inst1).foo = 123;
statics(inst3).foo = 456;
console.log( statics(inst1).foo ); // 123
console.log( statics(inst2).foo ); // 123
console.log( statics(inst3).foo ); // 456
I've modified John Resig's class to provide copy over the parent's static members to the new class, which adds this:
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
Here's a fiddle.
// This is a modified version of John Resig's simple inheritence class to add copying of static methods
// The new code is the for loop commented with "add in the static members"
/* Simple JavaScript Inheritance
* By John Resig http://ejohn.org/
* MIT Licensed.
*/
// Inspired by base2 and Prototype
(function(){
var initializing = false, fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
this.Class = function(){};
// Create a new Class that inherits from this class
Class.extend = function(prop) {
var _super = this.prototype;
// Instantiate a base class (but only create the instance,
// don't run the init constructor)
initializing = true;
var prototype = new this();
initializing = false;
// Copy the properties over onto the new prototype
for (var name in prop) {
// Check if we're overwriting an existing function
prototype[name] = typeof prop[name] == "function" &&
typeof _super[name] == "function" && fnTest.test(prop[name]) ?
(function(name, fn){
return function() {
var tmp = this._super;
// Add a new ._super() method that is the same method
// but on the super-class
this._super = _super[name];
// The method only need to be bound temporarily, so we
// remove it when we're done executing
var ret = fn.apply(this, arguments);
this._super = tmp;
return ret;
};
})(name, prop[name]) :
prop[name];
}
// The dummy class constructor
function Class() {
// All construction is actually done in the init method
if ( !initializing && this.init )
this.init.apply(this, arguments);
}
// Populate our constructed prototype object
Class.prototype = prototype;
// Enforce the constructor to be what we expect
Class.prototype.constructor = Class;
//add in the static members
for (var name in this) {
if (!Class[name]) {
Class[name] = this[name];
}
}
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
function addText(text) {
document.getElementById('greetings').innerHTML = document.getElementById("greetings").innerHTML + '<br>' + text;
}
//parent class with a prototype method and two static methods
var Parent = Class.extend({
hello: function () {
addText('parent.hello');
}
});
Parent.static = function() {
addText('Parent.static');
}
Parent.overrideStatic = function() {
addText('Parent.overrideStatic');
}
//child class that overrides one of the parent's static methods
var Child = Parent.extend();
Child.overrideStatic = function() {
addText('Child.overrideStatic');
}
var parent = new Parent();
parent.hello();
Parent.static();
var child = new Child();
child.hello(); //should output parent.hello
Child.static(); //should output Parent.static
Child.overrideStatic();
<div id="greetings"></div>
Pass in an optional list of static members in the call to 'extend'. This method adds the static properties (if any) to a 'statics' attribute on the constructor function.
Code Changes
Changes as follows. These lines added just after the 'dummy class constructor' code:
if(staticProp) {
Class.statics = [];
for (var name in staticProp) {
!Class.statics[name] && (Class.statics[name] = staticProp[name]);
}
}
An additional argument 'staticProp' added when type is declared in order to allow introduction of static members at this stage:
Class.extend = function(prop,staticProp) {
A fiddle can be found here, includes some tests.
Usage Examples
Can define statics at type declaration time like so using the second optional constructor argument:
var A = Class.extend({},{myStatic:1});
Can access/define statics inside an instance method:
var B = Class.extend({test:function(){B.statics.myStatic=2;}});
Or from outside an instance:
A.statics.myStatic=3;
Example with requirejs:
Put Class.js in the baseUrl folder. Example new class definition. Not mandatory to name the file of the new class the same as the 'var C' (i.e. C.js) but probably better for readability so references to the C name within the class's methods are aligned to any external references to its static members:
define(['Class'],function($) {
var C = Class.extend({
init: function(params){
C.statics.myStatic++; // access static data
}
},{
myStatic: 123
});
return C;
});
Another class in D.js refers to static data in class C:
define(['Class', 'C'],function($,C) {
var D = Class.extend({
init: function(params){
C.statics.myStatic++; // static data of another class
}
},{});
return D;
});

declaring protected variable in javascript

How do i declare protected variable. Let me give an example here
// Constructor
function Car(){
// Private Variable
var model;
}
// Public variable
Car.prototype.price = "5 Lakhs";
// Subtype
function Indiancar(){
}
// Prototype chaining
Indiancar.prototype = new Car();
// Instantiating Superclass object
var c = new Car();
// Instantiating subclass object
var ic = new Indiancar();
in this I would like to have a variable that is accessible as ic.variabl that is also present in car class.
You would do something like this:
var Base = function()
{
var somePrivateVariable = 'Hello World';
this.GetVariable = function()
{
return somePrivateVariable;
};
this.SetVariable = function(newText)
{
somePrivateVariable = newText;
};
};
var Derived = function()
{
};
Derived.prototype = new Base();
var instance = new Derived();
alert(instance.GetVariable());
instance.SetVariable('SomethingElse');
alert(instance.GetVariable());
Assuming I understood your question correctly.
EDIT: Updating with true 'private' variable.
There is a way to define protected variables in JavaScript:
A constructor function in javascript may return any object (not necesserily this). One could create a constructor function, that returns a proxy object, that contains proxy methods to the "real" methods of the "real" instance object. This may sound complicated, but it is not; here is a code snippet:
var MyClass = function() {
var instanceObj = this;
var proxyObj = {
myPublicMethod: function() {
return instanceObj.myPublicMethod.apply(instanceObj, arguments);
}
}
return proxyObj;
};
MyClass.prototype = {
_myPrivateMethod: function() {
...
},
myPublicMethod: function() {
...
}
};
The nice thing is that the proxy creation can be automated, if we define a convention for naming the protected methods. I created a little library that does exactly this: http://idya.github.com/oolib/
As has been said, javascript doesn't have protected variables.
In the 10 years since this question was written, Typescript has become a thing, and people interested in OOP in javascript should check it out! It does support protected variables.
That said, I'd like to throw my hat into the ring and provide a method for emulating protected variables using plain javascript, since this is a top Google search result and the top-voted answer as of writing doesn't really fit the bill.
// Declare objects within an anonymous function to limit access.
var objectRefs = (function() {
// This is the object we want to inherit from.
function Base(param1, _protected) {
var _public = this;
var _protected = _protected || {};
var _private = {};
// Declare some variables
_public.shared = "Anyone can access this!";
_protected.inherited = "This is protected";
_private.secretVar = "Children cannot access this.";
// Let's try a few functions.
_public.foo = function() {
// We can access protected and private functions here. This would
// not be possible if we attached it to the prototype.
console.log(_protected.inherited);
console.log(_private.secretVar);
_private.secret();
};
_protected.bar = function() {
// One thing to watch out for: private functions called after
// construction do NOT have access to the object via 'this'. This is
// masked by the fact that I assigned it to the '_public' var.
// More reading: https://stackoverflow.com/q/20279484/3658757
console.log(_public.shared);
};
_private.secret = function() {
// The same warning in _protected.bar applies here too.
console.log(_public.shared);
};
}
// Inherits from Base
function Derived(param1, _protected) {
var _public = this;
var _protected = _protected || {};
var _private = {};
// Inherit (ready for the magic?)
Base.call(this, param1, _protected);
// Since we passed a reference to the "_protected" object as an argument
// to the Base object, it has been attaching all of its protected
// variables to it. We can now access those variables here:
// Outputs "This is protected"
console.log(_protected.inherited);
// We can also access protected functions:
_protected.bar();
// We can even override protected variables and functions.
_protected.inherited = "New value!";
// We cannot access private variables belonging to Base.
// This fails:
// console.log(_private.secretVar);
}
// We don't want to allow public access to the constructors, because this
// would let outside code pass in a '_protected' var. Instead, we create new
// objects that accept all params minus '_protected', and inherit from the
// target object.
return {
Base: function(param1) {
Base.call(this, param1);
},
Derived: function(param1) {
Derived.call(this, param1);
}
};
}());
// Assign the constructors to variables for clarity.
var Base = objectRefs.Base;
var Derived = objectRefs.Derived;
// This is how you construct the object.
var newDerived = new Derived("param1");
// Public functions are accessible.
newDerived.foo();
// Protected functions are not. These fail:
// newDerived.bar();
// newDerived.protected.bar();
So that was fun! This structure makes protected variables function the way you'd expect: inheriting objects can access them, but they're inaccessible from the outside.
For reference, here's what the above code looks like in Typescript:
class Base
{
// Declare some variables
public shared: string = "Anyone can access this!";
protected inherited: string = "This is protected";
private secretVar: string = "Children cannot access this.";
constructor(param1: string) {
// We're not using param1; it's only there as an example.
// If we didn't need any constructor code, we could leave this out.
// Note that Typescript has type checking (hence the name)
}
// Let's try a few functions.
public foo(): void {
console.log(this.inherited)
console.log(this.secretVar)
this.secret();
}
protected bar(): void {
console.log(this.shared);
}
private secret(): void {
console.log(this.shared);
}
}
class Derived extends Base {
constructor(param1: string) {
super(param1);
// Outputs "This is protected"
console.log(this.inherited);
// We can also access protected functions:
this.bar();
// We can even override protected variables and functions.
this.inherited = "New value!";
}
}
// This is how you construct the object.
var newDerived = new Derived("param1");
// Public functions are accessible.
newDerived.foo();
// Protected functions are not. This fails:
// newDerived.bar();
Structurally, this is much clearer. As you're coding, you'll be given an error if you try to access a protected variable from outside the object.
But be aware: if you need the compiled javascript to limit outside access to those variables, Typescript won't do that for you. Here's what the compiled output looks like:
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
if (typeof b !== "function" && b !== null)
throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var Base = (function () {
function Base(param1) {
this.shared = "Anyone can access this!";
this.inherited = "This is protected";
this.secretVar = "Children cannot access this.";
}
Base.prototype.foo = function () {
console.log(this.inherited);
console.log(this.secretVar);
this.secret();
};
Base.prototype.bar = function () {
console.log(this.shared);
};
Base.prototype.secret = function () {
console.log(this.shared);
};
return Base;
}());
var Derived = (function (_super) {
__extends(Derived, _super);
function Derived(param1) {
var _this = _super.call(this, param1) || this;
console.log(_this.inherited);
_this.bar();
_this.inherited = "New value!";
return _this;
}
return Derived;
}(Base));
var newDerived = new Derived("param1");
newDerived.foo();
As you can see, not only are the protected variables public, but so are the private ones!
If you need encapsulation in the browser, then you'll have to stick with workarounds like I outlined in the first chunk of code. If you're using encapsulation to help you reason about the code, Typescript is the way to go.

Is it possible to append functions to a JS class that have access to the class's private variables?

I have an existing class I need to convert so I can append functions like my_class.prototype.my_funcs.afucntion = function(){ alert(private_var);} after the main object definition. What's the best/easiest method for converting an existing class to use this method? Currently I have a JavaScript object constructed like this:
var my_class = function (){
var private_var = '';
var private_int = 0
var private_var2 = '';
[...]
var private_func1 = function(id) {
return document.getElementById(id);
};
var private_func2 = function(id) {
alert(id);
};
return{
public_func1: function(){
},
my_funcs: {
do_this: function{
},
do_that: function(){
}
}
}
}();
Unfortunately, currently, I need to dynamically add functions and methods to this object with PHP based on user selected settings, there could be no functions added or 50. This is making adding features very complicated because to add a my_class.my_funcs.afunction(); function, I have to add a PHP call inside the JS file so it can access the private variables, and it just makes everything so messy.
I want to be able to use the prototype method so I can clean out all of the PHP calls inside the main JS file.
Try declaring your "Class" like this:
var MyClass = function () {
// Private variables and functions
var privateVar = '',
privateNum = 0,
privateVar2 = '',
privateFn = function (arg) {
return arg + privateNum;
};
// Public variables and functions
this.publicVar = '';
this.publicNum = 0;
this.publicVar2 = '';
this.publicFn = function () {
return 'foo';
};
this.publicObject = {
'property': 'value',
'fn': function () {
return 'bar';
}
};
};
You can augment this object by adding properties to its prototype (but they won't be accessible unless you create an instance of this class)
MyClass.prototype.aFunction = function (arg1, arg2) {
return arg1 + arg2 + this.publicNum;
// Has access to public members of the current instance
};
Helpful?
Edit: Make sure you create an instance of MyClass or nothing will work properly.
// Correct
var instance = new MyClass();
instance.publicFn(); //-> 'foo'
// Incorrect
MyClass.publicFn(); //-> TypeError
Okay, so the way you're constructing a class is different than what I usually do, but I was able to get the below working:
var my_class = function() {
var fn = function() {
this.do_this = function() { alert("do this"); }
this.do_that = function() { alert("do that"); }
}
return {
public_func1: function() { alert("public func1"); },
fn: fn,
my_funcs: new fn()
}
}
var instance = new my_class();
instance.fn.prototype.do_something_else = function() {
alert("doing something else");
}
instance.my_funcs.do_something_else();
As to what's happening [Edited]:
I changed your my_funcs object to a private method 'fn'
I passed a reference to it to a similar name 'fn' in the return object instance so that you can prototype it.
I made my_funcs an instance of the private member fn so that it will be able to execute all of the fn methods
Hope it helps, - Kevin
Maybe I'm missing what it is you're trying to do, but can't you just assign the prototype to the instance once you create it? So, first create your prototype object:
proto = function(){
var proto_func = function() {
return 'new proto func';
};
return {proto_func: proto_func};
}();
Then use it:
instance = new my_class();
instance.prototype = proto;
alert(instance.prototype.proto_func());

Categories

Resources