I've been trying to organize code in a javascript project and have ended up with a bunch of nested functions. Supposedly that's bad practice, and I know it affects performance, but I'm having trouble coming up with an alternative. Here's an example of what I'm trying to do:
Code before nesting:
function Level1(dep1, dep2, dep3, dep4){
var tempResult1 = dep1 + dep2;
var tempResult2 = tempResult1/2;
var tempResult3 = dep3 + dep4;
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
What it looks like after I try to separate responsibilities into a hierarchy:
function Level1(dep1, dep2, dep3, dep4){
var tempResult2 = getTempResult2(dep1, dep2);
var tempResult3 = getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
function getTempResult2(dep1, dep2){
var tempResult1 = getTempResult1(dep1, dep2);
return tempResult1/2;
function getTempResult1(dep1, dep2){
return dep1 + dep2;
}
}
function getTempResult3(dep3, dep4){
return dep3 + dep4;
}
}
Obviously for the operations used here, functions are a bit excessive, but it does help make the ones in my project a lot more manageable. I'm unfamiliar with any other way to do this, as this is my first javascript project. The suggestions I found on here only dealt with 1 level of nested functions, not 2, and I didn't see any good examples of how to implement nested scoping. If someone could give me an example of a way to accomplish the organization I'm looking for here, I'd be very greatful. Thanks.
have ended up with a bunch of nested functions
You can simply unnest them, since they're not used as closures (you pass everything necessary as arguments). You will even get a little performance advantage by not creating a local function object every time the outer function is called (which is well optimized though and probably negligible).
I just read a bunch about how nested functions were bad practice
Notice that sometimes nested functions are necessary, when you want to create a closure.
I don't like the fact that getTempResult1, 2, and 3 are accessible outside of Level1, or that getTempResult1 is accessible outside of getTempResult2.
You could use an IEFE to create an extra scope from which only Level1 is exported:
var Level1 = (function() {
function Level1(dep1, dep2, dep3, dep4) {
var tempResult2 = getTempResult2(dep1, dep2);
var tempResult3 = getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
var getTemptResult2 = (function() {
function getTempResult2(dep1, dep2) {
var tempResult1 = getTempResult1(dep1, dep2);
return tempResult1/2;
}
function getTempResult1(dep1, dep2) {
return dep1 + dep2;
}
return getTempResult2;
})();
function getTempResult3(dep3, dep4) {
return dep3 + dep4;
}
return Level1;
}());
Maybe this is what you want:
function Level1(dep1, dep2, dep3, dep4){
var tempResult2 = Level1.getTempResult2(dep1, dep2);
var tempResult3 = Level1.getTempResult3(dep3, dep4);
var mainResult = tempResult2 + tempResult3;
return mainResult;
}
Level1.getTempResult2 = function (dep1, dep2) {
var tempResult1 = Level1.getTempResult2.getTempResult1(dep1, dep2);
return tempResult1/2;
}
Level1.getTempResult2.getTempResult1 = function (dep1, dep2){
return dep1 + dep2;
}
Level1.getTempResult3 = function (dep3, dep4){
return dep3 + dep4;
}
Currently I tried
function a(val1, val2) { return a.foo(val1, val2) }
a.foo = function (x,y) { return x + y }
in my browser. The command a(1,2) prints 3 as aspected. Other example:
function a() { return a.foo(1,2) }
a.foo = function (x,y) { return a.foo.bar(x,y) }
a.foo.bar = function (x,y) { return x+y }
a(1,2) // -> 3
This is a design question. Since a good and elegant design depends always on quite a number of aspects of your problem domain, it is impossible from the simplified code in your question to really estimate what the best solution would be. I'll try to show you some options which in each case address ways to do data hiding and avoid nested functions or functions that are created multiple times.
Since you ask for data hiding and keeping getTempResult1 hidden from anything other than getTempResult2, I will assume that each of these functions are reasonably complex and might be written by different people, and you want to keep the internals hidden. That warrants creating a different class for each of these rather than just a function.
I will substitute your example code with a more tangible example and use a proper OOP approach to solve the problem. Let's say you are building an e-commerce application. Level1 will be an invoice class, and dep1-4 might be things like: purchase price, profit rate, discount rate, tax rate. We will make a very simple application which will calculate: purchase price - discount + profit + taxes = total price
I hope this ressembles your problem faithfully enough so you can appreciate some of the OOP techniques used (it's still way overkill in structure for the calculations done, but it's a lesson in OOP and allows for a great deal in scalability should the problem domain get more complex in the future, say you go international and must calculate taxes for different countries etc).
I will use the OoJs library to be able to do proper OOP in JavaScript. See the code below working on jsfiddle.
The idea of an ecommerce app is inspired from the book "Dessign patterns explained" by Shalloway and Trott
In conclusion you will find that this solution:
hides implementation details
there are no nested functions
every function is created only once
is scalable and maintainable and flexible in case of changing
requirements
So the code using our classes will look as follows:
// Create your namespace to avoid polluting global
//
var eComm = eComm || {}
// this will be some factory code which will return the needed objects, it won't actually use them.
// Normally this should be a class living in our eComm namespace
//
function factory( db, clientID )
{
// we would assume here that the hardcoded rates would be found in the database using the client id.
//
var discount = new eComm.Discount( 5 ) // in %
var profit = new eComm.Profit ( 20, discount ) // in %
var taxRate = new eComm.TaxRate ( 5 , profit ) // in %
// note that I use a simple aggragation approach, because I don't know the
// actual complexity of your problem domain. It makes this very simple ecommerce
// code not entirely ideal. If we would just perform a chain of operations on
// a number, other design patterns would be more suited, like a decorator.
// It is not appropriate to just pass taxRate to Invoice, because it is no different
// than profit or discount, it just comes later in a chain of calculations.
// I have taken this approach to show that it is possible to hide steps of the
// implementation down a hierarchy.
//
return new eComm.Invoice( taxRate )
}
// now when we will actually use it, it looks like this
// wrapped it in a function call because on global scope
// we would have to put this entirely at the bottom
// if you put all your code in classes you don't have this
// problem. They can occur in any order
//
function usage()
{
var invoice = factory( "database", 1654 /* the client id */ )
invoice.addPurchase( 1574 ) // price in some currency
invoice.addPurchase( 1200 ) // a second purchase
// in reality you would probably also pass an object representing an output
// device to Invoice (a printer, or a pdf generator, ...)
//
console.log( invoice.total() )
}
The actual classes. It looks long, but that's because the less they do, the bigger the overhead (relatively speaking). I ommit more and more code as we go down for brevity as the classes all look very much alike.
;( function class_Invoice( namespace )
{
'use strict'; // recommended
if( namespace[ "Invoice" ] ) return // protect against double inclusions
namespace.Invoice = Invoice
var Static = OoJs.setupClass( namespace, "Invoice" )
// constructor
//
function Invoice( taxRate )
{
// should do validation as javascript is loosely typed
//
if( "TaxRate" !== OoJs.typeOf( taxRate ) )
;// throw an error
// Data members
//
this.taxRate = taxRate
this.totalPrice = 0
this.Protected( "taxRate", "totalPrice" ) // if you want them available to subclasses
var iFace = this.Public( total, addPurchase ) // make these methods public
return iFace
}
// all your method definitions go here
//
function addPurchase( price )
{
this.totalPrice += this.taxRate.calculate( price )
}
function total()
{
return this.totalPrice
}
})( eComm )
;( function class_TaxRate( namespace )
{
namespace.TaxRate = TaxRate
var Static = OoJs.setupClass( namespace, "TaxRate" )
// constructor
//
function TaxRate( rate, profit )
{
// do your validation on profit and rate as above
this.rate = rate
this.profit = profit
this.Protected( "profit" ) // if you want
return this.Public( calculate )
}
function calculate( price )
{
return this.profit.calculate( price ) * ( 1 + this.rate / 100 )
}
})( eComm )
;( function class_Profit( namespace )
{
namespace.Profit = Profit
var Static = OoJs.setupClass( namespace, "Profit" )
// constructor
//
function Profit( rate, discount )
{
this.rate = rate
this.discount = discount
return this.Public( calculate )
}
function calculate( price )
{
return this.discount.calculate( price ) * ( 1 + this.rate / 100 )
}
})( eComm )
;( function class_Discount( namespace )
{
namespace.Discount = Discount
var Static = OoJs.setupClass( namespace, "Discount" )
// constructor
//
function Discount( rate )
{
this.rate = rate
return this.Public( calculate )
}
function calculate( price )
{
return price - price * this.rate / 100
}
})( eComm )
usage()
you don't need to worry about the call stack getting a few levels deep.
this is an example of premature optimization
Try looking at the step module, which is intended for node.js. I use it all the time.
However, you might be to use the step.js script even outside of the node.js environment (note: I have not tested this). At the very least, it shows how you can flatten any number of levels of nesting.
I know this is already answered but I thought I would leave you with some additional resources to help you on this adventure. I think this is a perfect time for you to look deeper into javascript design patterns.
Learning JavaScript Design Patterns by Addy Osmani is a fantastic read / resource to learn about multiple patterns for creating javascript applications, creating reusable code, closures etc. Anyone who is having this internal disscussion on how to better organize my nested functions / scope, etc should read it.
Here is an example snippet from his article regarding The Factory Pattern
// Types.js - Constructors used behind the scenes
// A constructor for defining new cars
function Car( options ) {
// some defaults
this.doors = options.doors || 4;
this.state = options.state || "brand new";
this.color = options.color || "silver";
}
// A constructor for defining new trucks
function Truck( options){
this.state = options.state || "used";
this.wheelSize = options.wheelSize || "large";
this.color = options.color || "blue";
}
// FactoryExample.js
// Define a skeleton vehicle factory
function VehicleFactory() {}
// Define the prototypes and utilities for this factory
// Our default vehicleClass is Car
VehicleFactory.prototype.vehicleClass = Car;
// Our Factory method for creating new Vehicle instances
VehicleFactory.prototype.createVehicle = function ( options ) {
switch(options.vehicleType){
case "car":
this.vehicleClass = Car;
break;
case "truck":
this.vehicleClass = Truck;
break;
//defaults to VehicleFactory.prototype.vehicleClass (Car)
}
return new this.vehicleClass( options );
};
// Create an instance of our factory that makes cars
var carFactory = new VehicleFactory();
var car = carFactory.createVehicle( {
vehicleType: "car",
color: "yellow",
doors: 6 } );
// Test to confirm our car was created using the vehicleClass/prototype Car
// Outputs: true
console.log( car instanceof Car );
// Outputs: Car object of color "yellow", doors: 6 in a "brand new" state
console.log( car );
Hope this article helps you and others looking for similar answers.
It's a good idea to have a function implement as less as possible for optimal re use. For example:
function doChores(){
//actually wash the dishes
//actually walk the dog.
}
Now let's say it's raining and I only want to wash the dishes, since washing the dishes is implemented in doChores I can't call it without walking the dog. Here is how it should be done:
function doChores(){
walkTheDog();
washTheDishes();
}
The function walkTheDog implements walking the dog and washTheDishes implements washing the dishes so they can be called sperately.
The problem you're facing is when you pass variables to a chain of functions. I usually pass one argument to a function and that argument contains an object with the needed parameters. Every function can read or mutate members of the passed object that they are concerned with. If at a later time you need to add more arguments then you don't need to change the signature of your funciton (for example function(arg1, arg2, newArg)) you'll always have function(args)
More info about the parameter passing can be found here: https://stackoverflow.com/a/16063711/1641941 under Passing (constructor) arguments
Related
since JS does not support abstract classes or inheritance, every time we want to add a new type to be created when using factory pattern, we will have to modify the code which mean we violate the open-close principle. for example, in the snapshot bellow - if we want to add a new employee type like Marketing, we will have to update the switch statement which is violation of the open-close principle. Is there any workaround to use the factory pattern without violation open-close principle?
function Accountant(){
console.log('I am accountant');
}
function Developer(){
console.log('I am developer');
}
function Sales(){
console.log('I am sales');
}
function CreateEmployee(employee){
switch(employee){
case('accountant'): return new Accountant();
case('developer'): return new Developer()
case('sales'): return new Sales();
}
}
if we want to add a new employee type, we will have to update the switch statement which is violation of the open-close principle.
No, it doesn't. The OCP is not about forbidding to update code. If we want to implement a new feature, we of course need to touch the code of the program. The OCP is about designing your interfaces so that your program can be easily extended without changing code all over the place - ideally you only have to provide the new code, and change the configuration of the program to make use of it - or if this is not configurable, change only the high-level building blocks.
I would argue that the factory pattern even facilitates application of the OCP - don't think about changes to the factory function, think about the modules that use it. Instead of changing all the code in all the modules that instantiates employee objects, all you need to do is to supply a different factory to them.
A step in the right direction is to create an employeeType object that holds the constructors:
const employeeType = {
Accountant,
Developer,
Salesperson
};
// console.log(new (employeeType["Accountant"])());
// Abstract away the hard-coded type above; the below randomization is strictly for demo purpose
const employeeTypeKeys = Object.keys(employeeType);
const employeeTypeIndex = Math.floor(employeeTypeKeys.length * Math.random());
console.log(new (employeeType[employeeTypeKeys[employeeTypeIndex]])());
function Accountant(){
console.log('I am an accountant');
}
function Developer(){
console.log('I am a developer');
}
function Salesperson(){
console.log('I am a salesperson');
}
I would argue the pattern isn't exactly something I'd like to extend but it's possible.
Say you have access to the CreateEmployee function alone and you'd want to extend it so you can also add Engineers.
import CreateEmployee from "./employee.js";
function Engineer(){
console.log("I'm an Engineer");
}
function CreateEmployeeAndEngineer(employeeType){
if(employeeType === 'Engineer') return new Engineer();
else {
return CreateEmployee(employeeType);
}
}
Simple (ehh... not really) function composition.
However, there's very little value for it in Javascript since it's untyped. Then of course functions, and therefore constructors, are first-class citizens and can be easily passed down to the new operator.
since JS does not support abstract classes or inheritance
Javascript does support inheritance through it's concept of prototype chain.
You could implement the Factory method pattern if you'd want.
If you want new instances to be created on the fly, you should use Object literals. Review the following design for an idea on how you may, or may not, want to go about this:
function ucFirst(string){
const s = string.split('');
return s.shift().toUpperCase()+s.join('');
}
function InstanceController(){
this.instances = [];
this.add = (name, obj)=>{
this.instances.push({name:name, obj:obj});
return this;
}
this.get = name=>{
for(let o of this.instances){
if(o.name === name){
return o.obj;
}
}
return false;
}
this.remove = name=>{
for(let i=0,a=this.instances,l=a.length; i<l; i++){
if(a[i].name === name){
a.splice(i, 1);
break;
}
}
return this;
}
}
const ic = new InstanceController;
const data1 = {
data:'could be from database',
more:'sure there can be more data',
numberTest: 2
}
const data2 = {test:'just a test'};
ic.add('developer', data1).add('accountant', {testing:'see'});
let dev = ic.get('developer'), aco = ic.get('accountant');
if(dev)console.log(dev);
if(aco)console.log(aco);
console.log(ic.get('nope'));
ic.remove('accountant'); aco = ic.get('accountant');
console.log(aco);
I want an chain-able interface similar to jQuery. Still all prototype tutorials, talks, jQuery source is not making this clear, so much appreciate help in solving this.
In jQuery I can call jQuery('.apple') but also jQuery.ajax('param') since jQuery seems to be a constructor function, and therefore can have properties such as the ajax function I assume?
What I want:
Postal('apple') // Return chain-able function/object/constructor thing
Postal('apple').send('China').fee(99) // Used like this
Postal.send // should be undefined, need product-selector
Postal.area // should be function, accepting 1 parameter
Postal.area('Europe') // Use like this
Postal.area('Asia')
Note above: The Area should be accessible for chain-methods such as send()
Functions that can use the "Global Accessor" product selector:
Postal('apple').send('China').fee(9) // Apples to China fee
Postal('apple').fee(9) // Apples to anywhere default fee
Postal('orange').send('USA').fee(9)
My attempt at solving it:
Comments is around my approach to understand and mimic jQuery's source:
// # Assume
// ES2016 and not to much performance downsides or object allocations
//This should become our Globalisk-jQuery-Accessor
var Postal
// Create a non-global scope inside here
(function() {
// Locals that are global for the postal-object-function
var p_area = 'global'
var p_destination = 'unknown'
var p_product = '<unknown product>'
// our main selector, like: jQuery('.container')
var postal = (product) => {
// We use the same postal-object but create a new instance that can
// handle initializations of something
return new postal.prototype.init(product)
}
// All functions that only callable with a product-selector
postal.prototype = {
init: (product) => {
console.log("Init ran "+product)
// here we return this in case of no arguments?
// should we return the base object with slightly different methods?
if (!arguments[0]) {
return this
}
// Make 'product' parameter local to this postal call but shared
// amongst all chaining functions
p_product = product // or?
}
}
area = (area) => {
p_area = area //Save for future calls
console.log("Area set to: " + area)
return
// No return since no chaining possible after area is set
}
send = (destination) => {
p_destination = destination //Save for future chaining
console.log("Sending to " + destination + "...")
return send
}
send.fee = function fee(amount) {
console.log("Setting "+p_destination+" send fee to " + amount + " in " +
p_area + " for product "+ p_product)
return fee
}
// Set so new instance has same "properties" as postal has itself
//Need something like this? postal.prototype.init.prototype = postal.prototype
Postal = postal // Set our global accessor, from now on it should be const
})()
// Call direct function without going trough selector
console.log( Postal.send === undefined )
Postal.area('Europe') // Change the Postal-global "current area" state
Postal('apple').send('China').fee(99) // Applies only to "Europe"
Postal.area('Asia')
Postal('apple').send('China').fee(33)
Postal('orange').send('USA').fee(9)
Expected output:
Assuming code is fixed to work as intended. I am running in node v5.3.0.
true
Area set to: Europe
init ran apple
Sending to China...
Setting China send fee to 99 in Europe for product apple
Area set to: Asia
Sending to China...
Setting China send fee to 33 in Asia for product apple
init ran orange
Sending to USA...
Setting USA send fee to 9 in Asia for product orange
This is easy to accomplish with two accessors such as:
PostalCore.area() for global-methods and Postal('product here') for product-selector-methods, so the essence of the question is really how to do this with a constructor function so one can have both on same object, like jQuery does - I also welcome arguments to why not :)
I'm attempting to reuse the code from here Edit a variable within an array to create something simmilar but less complex.
I made the 'working' function:
var WorkT = function(gain,loss,message) {
coins += this.gain;
coins -= this.loss;
this.message = message;
}
workT1 = new WorkT(30,0,'<span class="red">+ 30 Gold Coins');
workT2 = new WorkT(15,0,'<span class="red">+ 15 Gold Coins');
workT3 = new WorkT(80,0,'<span class="red">+ 80 Gold Coins');
workT4 = new WorkT(1,0,'<span class="red">+ 1 Gold Coin');
WorkTs = [workT1,workT2,workT3,workT4];
And I'm trying to call it later on in my code with this:
$('#output').html(WorkTs[Math.floor(Math.random() * 4)].WorkT());
But, when I click the button, nothing changes. Can anyone tell me why?
Your WorkT instances have no WorkT() function.
You need to declare a function named WorkT (or else) inside your WorkT 'class' :
var WorkT = function(gain,loss,message) {
//...
this.work = function () {
//Do Something.
}
}
Or you won't be able to call it on your instances :
$('#output').html(WorkT[Math.floor(Math.random() * 4)].work());
It all depends on what you're trying to achieve here.
There are lots of errors in your code.
What is the coins in the WorkT Constructor? Is it a global variable, or you wanted to do this.coins?
this.gain and this.loss does not exist. They are just gain and loss.
There is no function called WorkT in the class WorkT. You probably want to define the function, too.
Here is how the code will look like, assuming coins is a global variable.
var WorkT = function(gain,loss,message) {
coins += gain;
coins -= loss;
this.message = message;
this.work = function(){
//Do something here.
}
}
And,
$('#output').html(WorkTs[Math.floor(Math.random() * 4)].work());
I'm trying to write a basic function in order to produce a cash machine. Whenever I run the below code, I get the total staying at 0. Can anyone help me out or explain to me why?
function VirtualCashMachine(){
//object storing food
this.food = {egg: 0.98, milk: 1.23, magazine: 4.99,chocolate: 0.45};
//total bill
this.total = 0;
//record of last transaction
this.lastTransactionAmount = 0;
//assign public methods
this.scan = scan;
this.voidLastTransaction = voidLastTransaction;
//define public methods
//add amount to total property
function scan(/*string*/item,/*integer*/ quantity){
//if food item exists in food object, find price and calculate total
if(this.food.hasOwnProperty(item)){
cost = this.food[item] * quantity;
add(cost);
this.lastTransactionAmount = cost;
}
};
function voidLastTransaction(){
this.total -= lastTransactionAmount;
};
//define private method
//add item price to total
function add(itemCost){
this.total = this.total + itemCost;
};
}
var VCM = new VirtualCashMachine();
VCM.scan("egg", 3);
console.log(VCM.total);
The problem seems to arise when I implemented the add function. My reasoning is that once I find the total costs for 3 eggs in this example, I add the amount to the this.total and can repeat this for other sorts of food.
Re-write add to be a property of this:
this.add = function (itemCost) {
this.total = this.total + itemCost;
}
"this" is often not what you think it is... I.e. when you call function without context (add instead of VCM.scan) the context will be set to global object. There are many articles on the subject - i.e. Understanding JavaScript Context.
There are several options to deal with it.
One is to call it with context by making it "public member" as suggested by tomca32 (Note that it will expose private methods which may not be desirable in many cases):
this.add = function(itemCost) { this.total += itemCost;}
this.add(cost);
Another option is to save this into local variable so you know what exactly you are using:
function VirtualCashMachine(){
var self = this;
....
function add(itemCost){
self.total = self.total + itemCost;
};
Or you can explicitly pass context with function.call:
function add(itemCost) { this.total += itemCost;}
add.call(this, cost);
or you can avoid this in local functions altogether, but you'll need to expose properties with get/set methods. In this case since function will sees all local variables in parent's scope it can correctly modify total:
var total = 0;
this.getTotal() { return total;}
function add(itemCost) { total += itemCost;}
Second approach (with copying this to local variable) is quite common and easiest to follow in my opinion: simply use self (or other commonly used me or that) everywhere inside your class where you would use this..
I suppose this could apply to any dynamic language, but the one I'm using is JavaScript. We have a situation where we're writing a couple of controls in JavaScript that need to expose a Send() function which is then called by the page that hosts the JavaScript. We have an array of objects that have this Send function defined so we iterate through the collection and call Send() on each of the objects.
In an OO language, if you wanted to do something similar, you'd have an IControl interface that has a Send() function that must be implemented by each control and then you'd have a collection of IControl implementations that you'd iterate through and call the send method on.
My question is, with JavaScript being a dynamic language, is there any need to define an interface that the controls should inherit from, or is it good enough to just call the Send() function exposed on the controls?
Dynamic languages often encourage Duck Typing, in which methods of the object dictate how it should be used rather than an explicit contract (such as an interface).
This is the same for PHP; you don't really need interfaces. But they exist for architectural needs. In PHP, you can specify type hints for functions which can be useful.
Second, an interface is a contract. It's a formal contract that all objects from this interface have those functions. Better to ensure that your classes meet those requirements than to remember: "mm, this class has isEnabled() but the other one is checkIfEnabled()". Interfaces help you to standardise. Others working on the derived object don't have to check whether the name is isEnabled or checkIfEnabled (better to let the interpreter catch those problems).
Since you can call any method on any object in a dynamic language, I'm not sure how interfaces would come into play in any truly useful way. There are no contracts to enforce because everything is determined at invocation time - an object could even change whether it conforms to a "contract" through its life as methods are added and removed throughout runtime. The call will fail if the object doesn't fulfill a contract or it will fail if it doesn't implement a member - either case is the same for most practical purposes.
We saw a nice implementation in the page below, this is ours (short version of it)
var Interface = function (methods) {
var self = this;
self.methods = [];
for (var i = 0, len = methods.length; i < len; i++) {
self.methods.push(methods[i]);
}
this.implementedBy = function (object) {
for (var j = 0, methodsLen = self.methods.length; j < methodsLen; j++) {
var method = self.methods[j];
if (!object[method] || typeof object[method] !== 'function') {
return false;
}
}
return true;
}
};
//Call
var IWorkflow = new Interface(['start', 'getSteps', 'end']);
if (IWorkflow.implementedBy(currentWorkFlow)) {
currentWorkFlow.start(model);
}
The whole example is at:
http://www.javascriptbank.com/how-implement-interfaces-in-javascript.html
Another alternative to the interfaces is offered by bob.js:
1. Check if the interface is implemented:
var iFace = { say: function () { }, write: function () { } };
var obj1 = { say: function() { }, write: function () { }, read: function () { } };
var obj2 = { say: function () { }, read: function () { } };
console.log('1: ' + bob.obj.canExtractInterface(obj1, iFace));
console.log('2: ' + bob.obj.canExtractInterface(obj2, iFace));
// Output:
// 1: true
// 2: false
2. Extract interface from the object and still execute the functions properly:
var obj = {
msgCount: 0,
say: function (msg) { console.log(++this.msgCount + ': ' + msg); },
sum: function (a, b) { console.log(a + b); }
};
var iFace = { say: function () { } };
obj = bob.obj.extractInterface(obj, iFace);
obj.say('Hello!');
obj.say('How is your day?');
obj.say('Good bye!');
// Output:
// 1: Hello!
// 2: How is your day?
// 3: Good bye!