Override privileged method of base class - javascript

How can I go about making a child class override a privileged method of a base class?
If its not possible, is there another way to achieve what I am trying to accomplish in the simple code example below?
I cannot convert the baseclass function parseXML() to public because it requires access to private variables
function BaseClass()
{
var map = {};
// I cannot make this function public BECAUSE it accesses & changes private variables
this.parseXML = function( key, value )
{
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass()
{
BaseClass.call(this);
this.parseXML = function( key, value, otherData )
{
alert("ChildClass()::parseXML()");
// How can I call the base class function parseXML()?
//this.parseXML(); // calls this function not the parent function
//MyClass.prototype.doStuff.call
BaseClass.prototype.parseXML.call(this, key, value); // fails
//BaseClass.prototype.parseXML(); // fails
// perform specialised actions here with otherData
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();

function BaseClass() {
var map = {};
this.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
map[key] = value;
}
}
function ChildClass() {
BaseClass.call(this);
var parseXML = this.parseXML;
this.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
parseXML.call(this, key, value);
}
}
ChildClass.prototype = new BaseClass;
var a = new ChildClass();
a.parseXML();
Live Example
Basically you cache the privileged method (which is only defined on the object) and then call it inside the new function you assign to the privileged method name.
However a more elegant solution would be:
function BaseClass() {
this._map = {};
};
BaseClass.prototype.parseXML = function(key, value) {
alert("BaseClass::parseXML()");
this._map[key] = value;
}
function ChildClass() {
BaseClass.call(this);
}
ChildClass.prototype = Object.create(BaseClass.prototype);
ChildClass.prototype.parseXML = function(key, value, otherData) {
alert("ChildClass()::parseXML()");
BaseClass.prototype.parseXML.call(this, key, value);
}
var a = new ChildClass();
a.parseXML();
Live Example
Also bonus implementation using pd

IMO, you need to use a Javascript library like Ext Js to simplify this task. Anyway, the following example illustrates how you can write some helper methods. It's a part of an unreleased open source project that I'm working on.
var JWObject = (function () {
var jwobj = function (){};
jwobj.prototype = { };
return jwobj;
})();
var Prototype = (function () {
var scopeQueue = [ window ];
return {
beginScope: function (namespace) {
var parts = namespace.split('.');
for (var i = 0; i < parts.length; i++) {
var name = parts[i],
parent = this.getScope(),
part = parent[name];
if (part && !part.__namespace) {
throw Error('/* ERROR MESSAGE */');
}
scopeQueue.push(parent[name] = (part || { __namespace: true }));
}
},
endScope: function () {
if (scopeQueue.length > 1) {
scopeQueue.pop();
}
},
getScope: function () {
return scopeQueue.pick();
},
define: function (name, members) {
var scope = this.getScope();
if (scope[name]) {
throw Error('The prototype already exist.');
}
this.extend(members, {
scope: scope,
extend: JWObject,
statics: {}
});
// Getting constructor
var ctor = (members.constructor === Object) ? function() { } : members.constructor;
delete members.constructor;
if (typeof members.extend === 'string') {
members.extend = scope[members.extend];
}
if (!members.extend) {
throw Error('The base class is not specified.');
}
// Deriving from parent type
ctor.prototype = new members.extend();
members.super = members.extend.prototype;
delete members.extend;
members.statics.__class = true;
this.extend(ctor, members.statics, true);
delete members.statics;
// Adding new members
this.extend(ctor.prototype, members, true);
// Adding and returning the created prototype
return scope[name] = ctor;
},
extend: function (expando, members, override) {
for (var m in members) {
if (override || !expando[m]) {
expando[m] = members[m];
}
}
}
};
})();
Prototype.extend(Array.prototype, {
pick: function() {
return this[this.length - 1];
}
});
Here is the result:
Prototype.beginScope('Sample');
/**
* Prototype: Sample.Plugin
*/
Prototype.define('Plugin', {
init: function() {
alert('init!');
}
});
Prototype.beginScope('Extension');
/**
* Prototype: Sample.Extensions.Plugin
* Extend : Sample.Plugin
*/
Prototype.define('Foo', {
extend: Sample.Plugin,
init: function() {
this.super.init.call(this);
alert('child: init!');
},
fun: function() {
this.init();
},
statics: {
create: function() {
return new Sample.Extension.Foo();
}
}
});
Prototype.endScope();
Prototype.endScope();
As you can see in the preceding code, the Prototype object provides some functionality to defining a namespace (Prototype.beginScope, Prototype.endScope and Prototype.getScope) or defining a prototype (Prototype.define).
You can inherit a prototype from another using extend like java.
Prototype.define('Foo', {
extend: Sample.Plugin,
Or call the base class method as follows:
init: function() {
this.super.init.call(this);
Also, every prototype you define with above code will be derived from JWObject by default.

Related

Converting code to ES6 modules

I have just started learning es6 module system. I have some es5 javascript code which I want to transform to es6 modules. There are 3 javascript files
workflow-designer.js
var WorkflowDesigner = (function () {
var constructor = function (element, options) {
var component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
extend(Object, constructor, {
getWorkflowName: function () {
return 'WorkflowName001';
},
nextStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
},
prevStep: function () {
var o = {};
o['id'] = -1;
//some code here
return o;
}
});
return constructor;
})();
(function ($) {
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};
}(jQuery));
extend.js
function extend(parent, child, methods) {
debugger;
let Surrogate = function () {};
Surrogate.prototype = parent.prototype;
child.prototype = new Surrogate();
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
for (let name in methods) {
if (methods.hasOwnProperty(name)) {
child.prototype[name] = methods[name];
}
}
// so we can define the constructor inline
return child;
}
There a third file utils.js which contain extension methods like
if (!Array.prototype.find) {
Array.prototype.find = function (predicate) {
//some code here
}
}
if (!Array.prototype.doSomething) {
Array.prototype.doSomething = function (predicate) {
//some code here
}
}
$(document).keyup(function (event) {
//somthing here.
});
I know that to convert the code to es6 modules, I can simply export the extend function like export function extend(.....) in the extend.js file. However, I am not 100% sure how to convert the workflow-designer and utils.js to es6 modules.
I suspect that I need to something like below to convert my workflow-designer.js to es6 module:
export default function workflowDesigner() {
let constructor = function (element, options) {
options = options || {};
let component = this;
if ($(element).hasClass('panel')) {
component.panel = $(element);
} else {
component.panel = $(element).closest('.panel');
}
};
//rest of the code here....
return constructor;
};
Please let me know if I am moving into the right direction or not.
UPDATE:
As per #Bergi's suggesion I changed the extend function like below:
export default function extend(parent, child, methods) {
child.prototype = Object.create(parent.prototype);
child.prototype.constructor = child;
// Add a reference to the parent's constructor
child.parentConstructor = parent;
// Copy the methods passed in to the prototype
Object.assign(child, methods);
// so we can define the constructor inline
return child;
}
However, now I am getting error message that "workflowDesigner.getWorkflowName is not a function"
In the debug mode I can see that this function is available at workflowDesigner.__proto__.constructor.getWorkflowName. With the old code it works fine.
Just drop the IIFE from your module pattern - ES6 modules come with their own scope.
import extend from './extend.js';
export default function WorkflowDesigner(element, options) {
if ($(element).hasClass('panel')) {
this.panel = $(element);
} else {
this.panel = $(element).closest('.panel');
}
}
extend(Object, WorkflowDesigner, {
getWorkflowName: () => 'WorkflowName001',
…
});
const $ = jQuery; // you might want to solve this with a proper `import`
$.fn.createWorkflowDesigner = function (options) {
debugger;
return this.map(function (index, element) {
return new WorkflowDesigner($(element), options);
});
};

Call parent method in JavaScript class but stll have access to prototype methods inside object instance?

Is it possible to call parent method in JavaScript class but to still have access to prototype methods from parent and child class. Here is code example:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod = function() {
// call baseInitMethod from Base class
}
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
var s = new Specific();
console.log(s.baseMethod());
console.log(s.baseInitMethod());
console.log(s.basePrototypeMethod());
console.log(s.specificMethod());
console.log(s.specificInitMethod());
console.log(s.specificPrototypeMethod());
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class but so that all function calls from above still works. Is that possible?
Your Specific.prototype object should inherit from the Base.prototype object. Currently you're copying over all its properties to the object with this code:
for(var p in Base.prototype) {
Specific.prototype[p] = Base.prototype[p]
}
But you should actually use Object.create to establish a real prototype chain:
Specific.prototype = Object.create(Base.prototype);
Specific.prototype.specificPrototypeMethod = function() {
return 'specificPrototypeMethod' + '-' + this.baseInitMethod();
}
I want to call baseInitMethod in Base class from baseInitMethod method inside Specific class
Yes. In your Specific constructor, you first need get Base's baseInitMethod instance method, before you overwrite the property of the instance:
function Specific() {
Base.call(this);
var parentInitMethod = this.baseInitMethod;
this.baseInitMethod = function() {
// call baseInitMethod from Base class:
parentInitMethod.call(this /*, arguments…*/);
}
…
}
so that all function calls from above still works.
I'm not sure what you mean by that exactly. The specificPrototypeMethod will always call the baseInitMethod of the current instance, which would be Specific's overwritten one not the original that was defined in Base.
Here is what you need to do:
var Base = function () {
};
Base.prototype.baseMethod = function () {
return 'baseMethod';
};
Base.prototype.baseInitMethod = function () {
return 'baseInitMethod';
};
Base.prototype.basePrototypeMethod = function () {
return "basePrototypeMethod";
};
var Specific = function () {
Base.apply(this, arguments);
};
Specific.prototype.baseInitMethod = function () {
Base.prototype.baseInitMethod.apply(this,arguments);
};
Specific.prototype.specificMethod = function () {
return 'specificMethod';
};
Specific.prototype.specificInitMethod = function () {
var basePrototypeMethodCallResult = Base.prototype.basePrototypeMethod.apply(this,arguments);
};
You're overwriting the baseInitMethod of Base inside Specific, with Specific's definition, so why would you ever want to call the Base version? If you simply remove the overwrite of the function you should call the Base definition:
var Base = function() {
this.baseMethod = function(){
return 'baseMethod';
};
this.baseInitMethod = function() {
return 'baseInitMethod';
}
}
Base.prototype.basePrototypeMethod = function() {
return "basePrototypeMethod";
};
var Specific = function() {
Base.call(this);
this.baseInitMethod(); // calls the Base definition only
this.specificMethod = function(){
return 'specificMethod';
}
this.specificInitMethod = function() {
return this.basePrototypeMethod();
}
}
One might argue "Why always trying to mimic 'classical' behaviour and fuss with call and apply instead of embracing the prototype delegation pattern instead?"
Here is what I would code :
var Base = {
baseVariable1: "baseValue1",
baseVariable2: "baseValue2",
baseMethod: function () {
return 'baseMethod';
},
baseInitMethod: function () {
return 'baseInitMethod';
}
}
var Specific = Object.create(Base);
Specific.variable1 = "value1";
Specific.variable2 = "value2";
Specific.specificInitMethod = function () {
return 'specificInitMethod' + '-' + this.baseInitMethod();
}
Specific.specificMethod = function () {
return 'specificMethod' + '-' + this.baseInitMethod();
}
var s = Object.create(Specific);
console.log(s.baseInitMethod());
console.log(s.baseVariable1);
console.log(s.baseVariable2);
console.log(s.variable1);
console.log(s.variable2);
console.log(s.baseMethod());
console.log(s.specificInitMethod());
console.log(s.specificMethod());
class Parentable {
get parent() {
return this.__proto__.__proto__;
}
}
class A extends Parentable {
say() {
console.log('Hello from A');
}
}
class B extends A {
say() {
console.log('Im not A, I am B! But A send you a message:');
this.parent.say();
}
}
(new B()).say();

How to create a Javascript function that inspects objects/ function based on property names that will survive minifcation?

Suppose I have a function proxyThrough like this:
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
childPropertyName and methodName are both strings, and it looks up the functions by name.
I know that this will not survive minification as a result.
How can I get functions like this to survive minification?
Example
This is what I am doing currently:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
BarView.prototype.anAction = function() {
this._barView.anAction.apply(this._barView, arguments);
};
BarView.prototype.anotherAction = function() {
this._barView.anotherAction.apply(this._barView, arguments);
};
This is what I would like to do instead:
var BaseView = require('./BaseView');
var FooView = require('./FooView');
function BarView() {
this._fooView = new FooView();
}
BarView.prototype = Object.create(BaseView.prototype);
BarView.prototype.constructor = BarView;
function proxyThrough(parentClass, childObjPropertyName, methodName) {
parentClass.prototype[methodName] = function() {
this[childObjPropertyName][methodName].apply(this[childObjPropertyName], arguments);
};
}
['anAction', 'anotherAction'].forEach(proxyThrough.bind(null, BarView, '_fooView'));
I guess it depends on how the minifier works, but if it renames the same property name consistently, you could use a helper function to get the minified property name:
function minifiedName(obj) {
for (var prop in obj) {
return prop;
}
}
[
minifiedName({anAction: null}),
minifiedName({anotherAction: null})
].forEach(proxyThrough.bind(null, BarView, '_fooView'));

Using the JavaScript revealing prototype pattern, how can I namespace functions contained within prototypes?

I'm using the Revealing Prototype Pattern and have 2 different prototypes that I'm putting into the same JavaScript file. These links are to articles I found which relate to this.
http://bit.ly/U83hdg, http://bit.ly/VmJ71h.
I was under the impression that these would operate like atomic classes, where functions associated with one would be unaware of functions in the other.
For instance, both of these prototypes have an "init" and a "set" function. The behavior I'm seeing in the browser is that the last version of "init" gets executed, even when the code references the first prototype name.
This is generic stripped-down code from my two prototypes.
var operationA = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationA.prototype = function () {
init = function () {
// do something
return this;
}
set = function () {
// do something
return this;
};
return {
init: init,
set: set
};
}
var operationB = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationB.prototype = function () {
init = function () {
// do something
return this;
}
set = function () {
// do something
return this;
};
return {
init: init,
set: set
};
}
This is how I'm instantiating the first object.
var objectASettings = {
property1: 48,
property2: 37
};
var objectA = new operationA('#mySelector', objectASettings);
objectA.init().set();
When the above runs, the init and set functions from the prototype for operationB are being executed, instead of executing the init and set functions from the prototype for operationA.
I assumed these prototypes basically namespaced their contained functions. Am I required to create unique public function names for operationA and operationB (like initA , setA, initB, setB)?
Is there a way to self-contain and/or namespace these public functions, so I can expose the same operation names of init and set on 2 different prototypes in the same file?
Thanks for your help.
A couple of things to get it working:
Add var before the first member in the prototype function.
Separate each member with a comma (you can certainly put var in front of each member but I like to keep it clean...personal preference though).
The function assigned to the prototype must be self-invoked for the pattern to work properly.
Here's an example that should work for you:
<html>
<head>
<script>
var operationA = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationA.prototype = function () {
var init = function () {
// do something
return this;
},
set = function () {
alert('set A');
return this;
};
return {
init: init,
set: set
};
}();
var operationB = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationB.prototype = function () {
var init = function () {
// do something
return this;
},
set = function () {
alert('set B');
return this;
};
return {
init: init,
set: set
};
}();
window.onload = function() {
var objectASettings = {
property1: 48,
property2: 37
};
var objectBSettings = {
property1: 50,
property2: 50
};
var objectA = new operationA('#mySelector', objectASettings);
objectA.init().set();
var objectB = new operationB('#foo', objectBSettings)
objectB.init().set();
}
</script>
</head>
You're omitting the var keyword when defining init and set so they're both assigned to the global object.
Just define the prototypes as Objects.
var operationA = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationA.prototype = {
init: function () {
// do something
return this;
},
set: function () {
// do something
return this;
}
}
var operationB = function (control, settings) {
this.control = control;
this.settings = settings;
};
operationB.prototype = {
init: function () {
// do something
return this;
},
set: function () {
// do something
return this;
}
};

How to Create Protected Object Properties in JavaScript

Is there a JavaScript pattern which mimics "Protected" object properties like what you see in languages like C++ ??
Basically, I'd like to create an Object A which has a number of "protected" object properties which can be accessed ONLY from methods which are defined from the prototype of Object A. i.e. - NOT accessible publicly from non-prototyped methods of A.
For instance, ideally would be like so:
function A(){
var prop1 = 1;
}
A.prototype.myFunc = function(){
var newVar = this.prop1; //newVar now is equivalent to 1
}
var instanceOfA = new A();
var newVar2 = instanceOfA.prop1; //error given as prop1 is "protected"; hence undefined in this case
BTW - I do not want the pattern of privileged member functions accessing private properties since the member function is still public.
There is no object property that can only be accessed from prototyped methods of A and not from non-prototyped methods of A. The language doesn't have that type of feature and I'm not aware of any work-around/hack to implement it.
Using Doug Crockford's methods, you can create member properties that can only be accessed from predefined non-prototyped methods (those defined in the constructor). So, if you're trying to limit access only to a predefined set of methods, this will accomplish that. Other than that, I think you're out of luck.
If you want other ideas, you'd probably get more help if you describe more about what you're actually trying to accomplish in your code rather than just how to emulate a feature in another language. Javascript is so much different than C++ that it's better to start from the needs of the problem rather than try to find an analogy to some C++ feature.
You cannot do it in Javascript.
I found a way for creating protected members. Therefor I call the base constructor and return an object with the protected members at the same time:
var protected = BaseClass.call(this);
Here an example:
function SignedIntegerArray(size)
{
var public = this;
var protected = {};
// private property:
var _maxSize = 10000;
// protected property:
protected.array = [];
// public property:
public.Length = size;
if(!isInteger(size) || size < 0 || size > _maxSize) { throw "argument exception"; }
for(var index = 0; index != size; index++) { protected.array[index] = 0; }
// private method:
function isInteger(i) { return i == i + 0 && i == ~~i; }
// protected method:
protected.checkIndex = function(index) { return index >= 0 && index < size; }
// public methods:
public.SetValue = function(index, value) { if(protected.checkIndex(index) && isInteger(value)) { protected.array[index] = value; } };
public.GetValue = function(index) { if(protected.checkIndex(index)) { return protected.array[index]; } else { throw "index out of range exception"; }}
return protected;
}
function FloatArray(size, range)
{
var public = this;
var protected = SignedIntegerArray.call(this, size); // call the base constructor and get the protected members
// new private method, "isInteger" is hidden...
function isFloat(argument) { return argument != ~~argument; }
// ...but "checkIndex" is accessible
public.SetValue = function(index, value) { if(protected.checkIndex(index) && isFloat(value) && value >= public.MinValue && value <= public.MaxValue) { protected.array[index] = value; } };
// new public properties:
public.MinValue = -range;
public.MaxValue = range;
return protected; // for sub-classes
}
function newObject(className, args) { return new function() { className.apply(this, args)}} // you need to use function.call or function.apply to initialize an object. otherwise the protected-object is empty.
window.addEventListener("load", function()
{
var o = newObject(FloatArray, [4, 50.0]);
o.SetValue(3, 2.1);
console.log(o.GetValue(3));
console.log(o.Length); // property from the base-class
});
This is probably what you're looking for: http://javascript.crockford.com/private.html
function ClassA(init)
{
var protected = {};
protected.prop = init * 10;
if(this.constructor != ClassA) { return protected; }
}
function ClassB()
{
var protected = ClassA.call(this, 5); //console.log(protected.prop);
}
//var a = new ClassA(123);
//var b = new ClassB();
I was interested to find a way to answer your question, and here's what I was able to do.
You'll need this helper:
var ProtectedHandler = (function () {
/// <Sumarry>
/// Tool to handle the protected members of each inheritance.
/// </Summary>
/// <param name="current">Current protected variable.</param>
/// <param name="args">The arguments variable of the object.</param>
/// <param name="callback">The function to initialise the variable in the 'object'.</param>
/// <param name="isParent">Is this the ultimate base object.</param>
function ProtectedHandler(current, args, callback, isParent) {
this.child = getChild(args);
if (callback)
this.callback = callback;
if (isParent)
this.overrideChild(current);
}
// Get the ProtectedHandler from the arguments
var getChild = function (args) {
var child = null;
if (args.length > 0 && (child = args[args.length - 1]) && child.constructor === ProtectedHandler)
return child;
};
// Chain Initialise the protected variable of the object and its inheritances.
ProtectedHandler.prototype.overrideChild = function (newValue) {
if (this.callback != null) {
this.callback(newValue);
}
if (this.child != null) {
this.child.overrideChild(newValue);
}
};
// Static function to create a new instance of the protectedHandler object.
ProtectedHandler.handle = function (protected, arguments, callback, isParent) {
return new ProtectedHandler(protected, arguments, callback, isParent);
};
return ProtectedHandler;
})();
This helper will allow you to handle multiple inheritances. The trick is to copy the protected variable from the base object to your new object (child).
To prove you it's working, here's an example:
// That's the default extends function from typescript (ref: http://www.typescriptlang.org/)
var __extends = this.__extends || function (d, b) {
for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p];
function __() { this.constructor = d; }
__.prototype = b.prototype;
d.prototype = new __();
};
var BaseClass = (function () {
function BaseClass() {
// Members
var private = {},
protected = {},
public = this;
// Constructor
ProtectedHandler.handle(protected, arguments, function () {
protected.type = "BaseClass";
}, true);
// Methods
protected.saySomething = function () {
return "Hello World";
};
public.getType = function () {
return protected.type;
};
}
return BaseClass;
})();
var Person = (function (_super) {
__extends(Person, _super);
function Person(name) {
// Members
var private = {},
protected = {},
public;
// Constructor
_super.call(public = this, ProtectedHandler.handle(protected, arguments, function (p) {
protected = p; //This is required to copy the object from its base object.
protected.name = name;
protected.type = "Person";
}));
//Method
public.getName = function () {
return protected.name;
};
public.saySomething = function () {
return protected.saySomething();
};
}
return Person;
})(BaseClass);
var Child = (function (_super) {
__extends(Child, _super);
function Child(name) {
// Members
var private = {},
protected = {},
public;
// Constructor
_super.call(public = this, name, ProtectedHandler.handle(protected, arguments, function (p) {
protected = p; //This is required to copy the object from its base object.
protected.type = "Child";
}));
//Method
public.setName = function (value) {
return protected.name = value;
};
}
return Child;
})(Person);
And here's the tests:
var testBase = new BaseClass();
testBase.getType(); //"BaseClass"
testBase.saySomething; //undefined
var testPerson = new Person("Nic");
testPerson.getType(); //"Person"
testPerson.saySomething(); //"Hello World"
testPerson.name; //undefined
testPerson.getName() //"Nic"
testPerson.setName; //undefined
var testChild = new Child("Bob");
testChild.getType(); //"Child"
testChild.saySomething(); //"Hello World"
testChild.name; //undefined
testChild.getName(); //"Bob"
testChild.setName("George");
testChild.getName(); //"George"
There is a pattern that I have come to like that does not work the same way as protected access does in most languages, but provides a similar benefit.
Basically, use a builder method to create a closure for properties, and then have that method create a "full" object with liberal access as well as an "exposed" object with more limited access. Place the exposed object into a property of the full object, and return that full object to the caller.
The caller can then make use of the full object (and pass that to other appropriate collaborators), but provide only the exposed object to collaborators that should have the more restricted access.
A contrived example…
// Ring employs a typical private/public pattern while
// RingEntry employs a private/exposed/full access pattern.
function buildRing( size ) {
var i
, head = buildRingEntry( 0 )
, newEntry;
;
head.setNext( head );
for( i = size - 1; i ; i-- ) {
newEntry = buildRingEntry( i );
newEntry.setNext( head.getNext() );
head.setNext( newEntry );
}
function getHead() { return head.exposed; }
return {
getHead : getHead
}
}
function buildRingEntry( index ) {
var next
, exposed
;
function getIndex() { return index; }
function setNext( newNext ) { next = newNext; }
function getNextFullEntry() { return next; }
function getNextExposedEntry() { return next.exposed; }
exposed = {
getIndex : getIndex
, getNext : getNextExposedEntry
};
return {
getIndex : getIndex
, setNext : setNext
, getNext : getNextFullEntry
, exposed : exposed
};
}
If we use that to build a ring of 4 entries ring = buildRing(4);, then ring.getHead().getIndex() gives us 0, ring.getHead().getNext().getIndex() gives us 1, ring.getHead().getNext().getNext().getIndex() gives us 2, etc.
If we try to execute ring.getHead().setNext({}) or ring.getHead().getNext().setNext({}), however, we get an error because setNext is not a property of an exposed entry object.
Caveat:
Since this is in the family of patterns that build the methods again in a new closure for each new object, it is not suitable for situations in which a very high volume of instantiation may be needed.
Take a look at workaround proposed by Maks on his website: Emulating protected members in JavaScript
It emulates protected access level to methods and properties of an object.

Categories

Resources