Javascript class properties behave as shared variable - javascript

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;
}
});
});

Related

Why does John Resig re-declare the original _super, after using inherited _super?

Taken from:
https://stackoverflow.com/a/15052240/1487102
Scroll down to see the lines I'm curious about
It makes sense that he declares the inherited function this._super before applying
What I don't get is: after he executes the function and gets the return val, why does he replace this._super with whatever it was beforehand??
The comment says that it only needs to be declared temporarily, but why would you not leave it declared?? I don't see how garbage collection would be improved, or any other optimization.
/* Simple JavaScript Inheritance for ES 5.1
* based on http://ejohn.org/blog/simple-javascript-inheritance/
* (inspired by base2 and Prototype)
* MIT Licensed.
*/
(function(global) {
"use strict";
var fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// The base Class implementation (does nothing)
function BaseClass(){}
// Create a new Class that inherits from this class
BaseClass.extend = function(props) {
var _super = this.prototype;
// Set up the prototype to inherit from the base class
// (but without running the init constructor)
var proto = Object.create(_super);
// Copy the properties over onto the new prototype
for (var name in props) {
// Check if we're overwriting an existing function
proto[name] = typeof props[name] === "function" &&
typeof _super[name] == "function" && fnTest.test(props[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; // <------ why??
return ret;
};
})(name, props[name])
: props[name];
}
// The new constructor
var newClass = typeof proto.init === "function"
? proto.hasOwnProperty("init")
? proto.init // All construction is actually done in the init method
: function SubClass(){ _super.init.apply(this, arguments); }
: function EmptyClass(){};
// Populate our constructed prototype object
newClass.prototype = proto;
// Enforce the constructor to be what we expect
proto.constructor = newClass;
// And make this class extendable
newClass.extend = BaseClass.extend;
return newClass;
};
// export
global.Class = BaseClass;
})(this);
A bit of confusion about what this was referring to
When declaring this._super = function, the entire class instance will have a key _super, which points to a specific function (obviously not desired)

function inside and outside subclass definition

Below are some code from cocos2dx-js binding official javascript sample
cc.Class = function(){};
cc.Class.extend = function (prop) { //John Resig's extend
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;
fnTest = /xyz/.test(function(){xyz;}) ? /\b_super\b/ : /.*/;
// 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.ctor)
this.ctor.apply(this, arguments);
}
// 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;
};
var Explosion = cc.Sprite.extend({
tmpWidth:0,
tmpHeight:0,
active:true,
ctor:function () {
this._super();
//blahblah
},
destroy:function () {
//blahblah
}
});
Explosion.sharedExplosion = function () {
//blahblah
};
Just wonder why sharedExplosion is putted outside the definition of var Explosion
It's a simple extension of Explosion outside its declaration. It is just an implication, I don't think there has to be particular reason for doing it.

Simple JavaScript Inheritence plugin error

I read John Resig's blog article on a Simple JavaScript Inheritance plugin that he wrote based on base2 and prototype.
Example code is here: http://jsfiddle.net/rFfX9/
//'use strict';
/* 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;
// And make this class extendable
Class.extend = arguments.callee;
return Class;
};
})();
This works. However when I uncomment 'use strict'; at the top it throws an exception, but can't figure out the solution. Any ideas?
In this case when you call anonymous function this will be undefined you don't call the function as a method of an object. In not strict mode this will be window object.
See also: Why is "this" in an anonymous function undefined when using strict?

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;
});

Javascript inherance and use of super: is this possible?

if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {
}
F.prototype = o;
var f = new F();
if(f.init){
f.init();
};
return f;
};
}
var inherit = function(P, C) {
var i;
for(i in P) {
// if is the current parent
if(P.hasOwnProperty(i) === false) {
continue;
};
// define the uper property
C.uper = {};
// methods
if(typeof P[i] === 'function') {
// set as super
C.uper[i] = P[i];
// if child already defined, skip
if(typeof C[i] === 'function') {
continue;
};
C[i] = P[i];
}
// properties
else {
// if child already defined a property, skip
if(!(typeof C[i] === 'undefined')) {
continue;
};
C[i] = P[i];
}
}
return C;
}
var Parent1 = (function(){
var that = {};
// private var
var _name = 'Parent1';
// public var
that.lastName = 'LastName';
// public method
that.getName = function(){
// if this.uper.getName.call(this)
return _name + this.lastName;
// else
// return _name + that.lastName;
}
// return the literal object
return that;
}());
var Parent2 = {
// fake private var
_name: 'Parent2',
// public method
getName: function(){
// as we call this method with the call method
// we can use this
return this._name;
}
}
var Child1 = inherit(Parent1, (function(){
var that = {};
// overriden public method
that.getName = function(){
// how to call the this.uper.getName() like this?
return 'Child 1\'s name: ' + this.uper.getName.call(this);
}
that.init = function(){
console.log('init');
}
// return the literal object
return that;
}()));
var Child2 = inherit(Parent2, {
getName: function(){
// how to call the this.uper.getName() like this?
return 'Child 2\'s name: ' + this.uper.getName.call(this);
}
});
var child1 = Object.create(Child1);
// output: Child 1's name: Parent1LastName
console.log(child1.getName());
var child2 = Object.create(Child2);
// output: Child 2's name: Parent2
console.log(child2.getName());
// how to call the this.uper.getName() like this?
how to call the this.uper.getName() like this?
Yes
Javascript uses Prototypal inheritance. So essentially objects inherit Objects (and everything is an Object)
Here are a couple links that should help get the point across.
Javascript Module Pattern
Module Pattern In-depth
Here's the basic module pattern:
var MODULE = (function (my) {
my.anotherMethod = function () {
// added method...
};
return my;
}(MODULE));
Then you can do something like this to mimic inheritance:
var MODULE_TWO = (function (old) {
var my = {},
key;
for (key in old) {
if (old.hasOwnProperty(key)) {
my[key] = old[key];
}
}
var super_moduleMethod = old.moduleMethod;
my.moduleMethod = function () {
// override method on the clone, access to super through super_moduleMethod
};
return my;
}(MODULE));
This style of coding takes a bit of getting used to, but I definitely prefer it to classical inheritance at this point. If this code isn't making sense, check out the Douglas Crockford lectures and it should clarify most of it.
addressing the edit:
You can create different instantiations of these objects by using the new operator.
OR
I'd recommend using this little method which extends the Object Prototype (again if this doesn't make sense see the Douglas Crockford video). I forget the exact reasons why this is so heavily recommended by him, but at the very least it eliminates some confusion in that the new operator is a bit different than in classical languages. Needless to say using only using the new operator is insufficient.
What this function does is extends the Object prototype with a method create. It then...
Defines function F in a contained namespace.
Assigns the function F's prototype to the object that is passed
returns the newly constructed Object.
(outlined better by douglas crockford himself in the prototypal inheritance link)
if (typeof Object.create !== 'function') {
Object.create = function (o) {
function F() {}
F.prototype = o;
return new F();
};
}
newObject = Object.create(oldObject);
So using your code...
var a = Object.create(MODULE_TWO),
var b = Object.create(MODULE_TWO);
Answering based on your last edit, you could use something like this:
function Class(ctor, parent) {
var c = Function.prototype.call;
function clas() {
// expose the parent as super
this.super = parent;
ctor.apply(this, arguments);
}
// save the constructor
clas.constructor = ctor;
// provide a static constructor
clas.init = function() {
c.apply(parent.constructor, arguments);
};
// Setup the prototype
clas.prototype = parent ? parent.prototype : {};
// provide an extend method
clas.extend = function(methods) {
for(var i in methods) {
if (methods.hasOwnProperty(i)) {
clas.prototype[i] = methods[i];
}
}
return clas;
};
return clas;
}
Examples:
var Animal = Class(function(name) {
this.name = name;
});
var Cat = Class(function(name) {
this.super(name);
}, Animal).extend({
meow: function() {
console.log('Meow! My name is ' + this.name + '.');
}
});
new Cat('Neko').meow();
There are at least a trillion different ways to implement "Classes" in JavaScript, the more you want to hide the internals the more "magical" the code becomes, the above is very simple though.
You can (and probably need) customize this to fit your needs. But always keep in mind that there might be situations where a full blown Class emulation approach might not be the best one.
I already posted it as a comment, but in case you want to have everything hidden away for you, I've written a pretty feature rich, but still fast, Class library my own:
https://github.com/BonsaiDen/neko.js

Categories

Resources