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()