cklanac
2/23/2013 - 3:27 PM

Example of how not to use object prototypes. The Fail example will cause confusion and bugs. The Win example provides a clearer/cleaner stru

Example of how not to use object prototypes. The Fail example will cause confusion and bugs. The Win example provides a clearer/cleaner structure.

'use strict'
/* * * * * * * * *
*
* Win/Fail: How not to create and clear an Object.property using prototypes
*
* Fail.prototype.list adds an array to Fail prototype
* Problem: list appears to be an instance property but is shared across all Fail instances
*
* Fail.prototype.clear resets the list
* Problem, clear actually creates <instance>.list which shadows the common Fail.prototype.list
*
* A shared prototype object is fine if understood. 
* The real problem with "fail.prototype.list = [];" is the clear() method which shadows the common prototype object.
*
* Fix...
* Add the list to the instance in the constructor add method. Or remove the clear() method
*
* * * * * * * * */


function Fail() {} //object constructor

Fail.prototype.list = []; //adds list to common Fail prototype object not the instance

Fail.prototype.add = function(item) {
    this.list.push(item); // add item to the instance
};

Fail.prototype.get = function() {
    return this.list; //get list from the instance
};

Fail.prototype.clear = function() {
    this.list = []; //shadow Fail.list with <instance>.list
};

//Example - create 2 Fail objects
var FailA = new Fail();
var FailB = new Fail();

FailA.add('foo'); //add 'foo': appears to add to instance but actually adds to Fail.list
FailB.add('bar'); //add 'bar': appears to add to instance but actually adds to Fail.list
console.log(FailA.get(), FailB.get()); //prove: foo & bar available on both objects

//The common/shared object is fine if that's intended, but the clear() method really messes things up

FailA.clear(); //appears to clear/reset the array but actually shadows is with an <instance>.list array
FailB.clear();

FailA.add('baz');
FailB.add('qux');

console.log(FailA.get(), FailB.get()); //FailA has ["baz'] and FailB has ["qux"]

console.log(FailA.__proto__.list, FailB.__proto__.list); //foo & bar still exist on prototype


//Better form: create instance array in the constructor or the add method
function Win() {
    this.list = [];
}

Win.prototype.add = function(item) {
    //this.list = this.list || [];
    this.list.push(item);
};

Win.prototype.get = function() {
    return this.list;
};

Win.prototype.clear = function() {
    this.list = [];
};

var WinA = new Win();
var WinB = new Win();

WinA.add('xxx');
WinB.add('yyy');

console.log(WinA.get(), WinB.get());
WinA.clear();
WinB.clear();

WinA.add('xxx');
WinB.add('yyy');

console.log(WinA.get(), WinB.get());
console.log(WinA.__proto__.list, WinB.__proto__.list); //no common prototype object exists