The Benefits of JavaScript Prototype - javascript

I've been wondering about JavaScript's prototypal nature, and the benefits of it, and have come down to the following list :
1) Inheritance
cat.prototype = animal
2) Memory Efficiency
a.prototype.b = function() {}
var a1 = new a();
var a2 = new a();
Then a1.b and a2.b are essentially the same object, where as :
var a = function() {
this.b = function() {};
}
var a1 = new a();
var a2 = new a();
a1.b and a2.b would be different function objects and take up more memory.
3) Adding methods/fields to multiple, already created, 'out in the wild' objects.
var a = function() {}
var a1 = new a();
var a2 = new a();
a.prototype.b = function() {}
a1.b();
a2.b();
So the question is, are these correct?
... and are there any other benefits I've missed?
Cheers!

Those are all correct.
Of course, there are "drawbacks" as well:
No closures
function a() {
var ival = 0;
this.start = function(){ ival = setInterval(function(){ }, 300); }
this.finish = function(){ clearTimeout(ival); }
}
compare to:
function a() {
this.ival = 0;
}
a.prototype.start = function(){ this.ival = setInterval(function(){ }, 300); }
a.prototype.finish = function(){ clearTimeout(this.ival); }

http://en.wikipedia.org/wiki/Prototype-based_programming#Comparison_with_class-based_models
Also, please see the discussion of prototype inheritance in the answers to this:
prototype based vs. class based inheritance

Related

ES6 Instantiating a derived class from an existing instance

Consider the following scenario:
class A {
constructor() {
this.A = 'A';
}
createB() {
//Create a B instance from this current instance
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
I would like to be able to create an instance of B without having to create a new instance of A, but rather use the existing A instance.
My goal is to be able to spawn a B instance by calling a function within A, but also allow a B instance to be created directly and handle constructing a default A.
How can I achieve something like this when B extends A and requires super() to be called?
Not sure this is exactly what you want but it works for your example:
class A {
constructor() {
this.A = 'A';
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = new B();
Object.assign(fromInstance, base);
console.log(fromInstance);
Here is an alternate solution. It is actually pretty common in C# and Java, but since JS has no method overloading, this is kind of cumbersome and not so nice compared to the above solution:
class A {
constructor(source) {
if(source){
//use properties/stuff from source
this.A=source.A;
}
else{
//only perform initialization if source is not provided
this.A = 'A';
}
}
}
class B extends A {
constructor(source) {
super(source);
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = new B(base);
console.log(fromInstance);
Basically, there are two versions of the constructor, one that creates a completely new object, and one that pretty much copies an old object.
I think there is a bit of a misunderstanding, every instance of B is by definition an instance of A, no matter what you do. If you want super to be called, you are calling the constructor of A, and thus "instantiating" A.
If I understand the problem, you want the new instance's A property to reflect the A property of the instance that created it, right? You can set this in createB since it will be called on A instance. This will allow the B instance to have a property that shadows the inherited A
class A {
constructor() {
this.A = 'A';
}
createB() {
let b = new B()
b.A = this.A // set to the instances 'A'
return b
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
console.log(fromInstance)
A generic approach could copy all A instance properties to a new B instance. An even more generic approach would be to copy the B object's properties to temporary storage first, and write them back later, so that if A and B had the same property name, the B object's property would take precedence:
class A {
constructor() {
this.A = 'A';
}
createB() {
let b = new B();
let temp = {};
let aProp, bProp;
// save own properties of b
Object.keys( b).forEach( bProp => (temp[bProp]=b[bProp]));
// install own properties of A instance
Object.keys( this).forEach( aProp => ( b[aProp]=this[aProp]));
// write back b properties over A instance properties
Object.keys( temp).forEach( bProp=> (this[bProp]=temp[bProp]));
return b;
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
// Create a B instance from A so that
// a new A isn't instantiated and
// fromInstance.A === 'C'
var fromInstance = base.createB();
console.log( "derived.A = %s", derived.A);
console.log( "fromInstance.A = %s", fromInstance.A);
Note that in JavaScript terms avoiding Class constructs be syntactically easier because you can change the prototype properties of ordinary functions but not Class constructor functions. However you would probably lose the ability to reliably identify B instances using instanceof B. Using a class expression in CreateB has the same problem - returned objects would not share the same Class constructor.
Just create an instance of B, copy the properties of the current instance of A to it using Object.assign then return it:
createB() {
var b = new B();
Object.assign(b, this);
return b;
}
Example:
class A {
constructor() {
this.A = 'A';
}
createB() {
var b = new B();
Object.assign(b, this);
return b;
}
}
class B extends A {
constructor() {
super();
this.B = 'B';
}
}
var base = new A();
var derived = new B();
base.A = 'C';
var fromInstance = base.createB();
console.log(fromInstance instanceof B);
console.log(fromInstance.A);

difference between these two ways of creating a 'private' property in Javascript

I am trying to simulate a simple Holder "class" in JavaScript with a "private" property that holds something and "public" getter and setter "methods" to access the value.
The approach exhibited by HolderA below is mentioned e.g. here. The other approach I more or less arrived at by mutation but I guess it must be recognizable as an idiom as well. I like it because it contains no this or prototype stuff and seems very elementary and functional. Is there a difference between the two?
The test code (I run it under nodejs) seems to suggest that the two approaches are identical except that in the first case the objects I get have typeof object whereas in the second function.
var test = function(o) {
var initialValueCorrect = (!(typeof o.getX()==='undefined'))&&(o.getX()===0);
var VALUE_TO_SET = 10;
o.setX(VALUE_TO_SET);
var getSetWorks = o.getX()===VALUE_TO_SET;
var xIsPrivate = (typeof o.x === 'undefined');
var xHasCorrectValue;
if (!xIsPrivate)
xHasCorrectValue = o.x === VALUE_TO_SET;
return {initialValueCorrect: initialValueCorrect,
getSetWorks : getSetWorks,
xIsPrivate: xIsPrivate,
xHasCorrectValue: xHasCorrectValue};
};
var HolderA = (function() {
function foo(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
};
return foo;
})();
var createHolderB = (function() {
var x;
function foo(_x) {
x = _x;
return foo;
}
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
var objects = [{object: new HolderA(0), name: "approach with constructor-invocation and 'this'"},
{object: createHolderB(0), name: "approach with normal function invocation and closed variable"}];
for (var i = 0; i<objects.length ; i++) {
var testResult = test(objects[i].object);
console.log('['+objects[i].name+']: the object is a: '+(typeof objects[i].object)
+'\n\n\t\t\t'+JSON.stringify(testResult)+'\n\n\n\n\n');
}
update
As Bergi has pointed out function createHolderB in my code above is plain wrong and only creates a singleton object. So, is not really a "constructor" function. To that end I've now created createHolderC which can be used to really create multiple objects with a hidden private property like this:
var objectC1 = createHolderC()(0);
Now, is there any material difference between HolderA and the createHolderC function or is the difference purely stylistic?
var createHolderC = function () {
return (function() {
var x;
function foo(_x) {
x = _x;
return foo;
};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
};
createHolderB does not create new holders like HolderA does. It's essentially a singleton pattern. You might also want to call it a module. Notice that createHolderB() === createHolderB.
createHolderC is still different from HolderA in that it returns function objects, not instances. You may see the differences better when you strip out the unnecessary IEFEs:
function HolderA(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
// implicit `return this;` when called via `new`
}
function createHolderC() {
var x;
function foo(_x) {
x = _x;
return foo;
};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
}
A typical factory would rather look like this:
function createHolderD(x) {
var foo = {};
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
}
(or even with return {getX: …, setX: …};), the only difference to HolderA is the prototypical inheritance then.
Basically both exhibits the private access behavior to the x variable. But the difference between those two are
Constructor function
var HolderA = (function() {
function foo(x) {
this.getX = function() {
return x;
};
this.setX = function(_x) {
x = _x;
};
};
return foo;
})();
This is a self executing function, where it returns Constructor foo.
That is the reason you are using new while creating this type of holder {object: new HolderA(0)
A function
var createHolderB = (function() {
var x;
function foo(_x) {
x = _x;
return foo;
}
foo.getX = function() {
return x;
};
foo.setX = function(_x) {
x = _x;
};
return foo;
})();
Even this is also a self executing function, but while execution it creates x variable and returns function foo, and foo access x by closure.
You are creating this type of holder just by normal function call object: createHolderB(0).
Both cases are really bad in practice.
If you're making closures (anonymous functions) that hold your "private variable" scope, it means you're creating those functions for every instance of the class. That costs memory and performance. I used to create classes like this, but then once I was making large number of instances and found out that it hits performance hard.
Just as in Python, make private variables private by some convention, like underscore in _name. Then you can break it for debug reasons (because variables in closure scope are not accessible).
This is how I would do it:
function MyClass(arg) {
this._privateVar = arg;
}
MyClass.prototype.getPrivateVar = function() {
return this._privateVar;
}
You can also make getters and setters:
Object.defineProperty(MyClass.prototype, "privateVar", {
get: function() {
return this._privateVar;
}
}
But don't try to push javascript into things it's not designed to, or you'll pay with performance, code readability and debugging complexity. Applies to other languages too.

JavaScript prototype structure and objects

I'm new to the prototype structure, and I'm having trouble figuring this one out. Here's my JavaScript code.
var Game = function ()
{
//some variables
};
Game.prototype.block =
{
spawn: function () {
var t1 = new this.inst;
},
inst : {
x: 5,
y: 0,
type: ''
}
};
When I try to create a new object "inst" I get the following error:
TypeError: object is not a function. What am I doing incorrectly?
If you want to create objects that inherit from the inst object, you can do that using Object.create, with var t1 = Object.create(this.inst);.
var Game = function () {
//some variables
};
Game.prototype.block = {
spawn: function () {
var t1 = Object.create(this.inst);
},
inst : {
x: 5,
y: 0,
type: ''
}
};
So then your code would look something like this;
var game = new Game();
game.block.spawn();
And the .spawn() method would have a variable that references an object that inherits from the Game.prototype.block.inst object.
First of all, inst is not defined within the scope of Game. So, this which refers to Game doesn't have any properties called inst. Secondly, inst must be followed by () to indicate a call to the constructor, which you are missing here.
I guest you need a static factory method to create new "inst". is the below code what you need? you call the Game.spawn method to generate a new inst, and you can put this method in setInterval.
function Game() {
//some variables
}
Game.spawn = function() {
function Inst() {
this.x = 5;
this.y = 0;
this.type = '';
}
return new Inst;
}
var inst1 = Game.spawn();
inst1.x = 1; //test inst1
console.log(inst1.x);
var inst2 = Game.spawn();
inst2.x = 2; //test inst2
console.log(inst2.x);
var inst3 = Game.spawn();
inst3.x = 3; //test inst 3
console.log(inst3.x);

Is it possible to combine the functions easier?

I need to combine some functions (modify 1st function), but I can't do it this way (it works, but is bad for me):
var a = function(){alert('a');};
var b = function(){alert('b');};
var c = a;
a = function(){c(); b();};
a();
Then I try to do this:
var a = function(){alert('a');};
var b = function(){alert('b');};
var rx = /^[\s\S]*\(([\s\S]*)\)\s*{([\s\S]*)}$/;
concat = function(f1,f2)
{
var q = f1.toString().replace(rx,'$1|$2').split('|');
var w = f2.toString().replace(rx,'$1|$2').split('|');
return (q[0]!=='' && w[0]!=='')?
new Function(q[0]+','+w[0],q[1]+w[1]):
(q[0]!=='')?
new Function(q[0],q[1]+w[1]):
new Function(w[0],q[1]+w[1]);
};
a = concat(a,b);
alert(a);
It works, but may be exist an easier way?
function concat(a, b) {
return function() {
a.call(this, arguments);
b.call(this, arguments);
};
}
Eval is evil, and parsing code with regexes is more evil.
You can even add varargs support:
function concat() {
var funcs = arguments;
return function() {
for (var i = 0; i < funcs.length; i++)
funcs[i].call(this, arguments);
};
}

JavasScript inheritance for constructors that return a function

Is there a way in JavaScript to inherit from a constructor function that returns a function? For example:
var A = function() {
return function(input) {
// do stuff
};
};
var B = function() {};
B.prototype = new A();
var b = new B();
Thanks
By returning a function from your constructor, you're not creating an instance of A, but rather an instance of the function. Therefore, inheritance will not work.
var A = function() { return function(input) {}; };
var a = new A();
>>> typeof a;
"function"
var A = function() {};
var a = new A();
>>> typeof a;
"object"
If you need B to inherit the returned function from A, you should set it as a method of A, either locally or in the prototype chain, and pass it that way.
var A = function() {
this.method = function(input) {}
};
var B = function() {}
B.prototype = new A();
var b = new B();
>>> b.method
'function(input) { }'

Categories