Welcome to JS Bin
Load cached copy from
 
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>JS Bin</title>
</head>
<body>
</body>
</html>
 
;(function(global) {
    
    // 'new' an object
    const FormatNum = function(num, digits, unit) {
        return new FormatNum.init(num, digits, unit);   
    }
    
    // hidden within the scope of the IIFE and never directly accessible
    const supportedUnit = ['normal', 'scientific'];
    
    const unit = {
        normalUnit: [
          { value: 1000000000,  symbol: "B" },
          { value: 1000000,  symbol: "M" },
          { value: 1000,  symbol: "k" }
        ],
        siUnit: [
          { value: 1E18, symbol: "E" },
          { value: 1E15, symbol: "P" },
          { value: 1E12, symbol: "T" },
          { value: 1E9,  symbol: "G" },
          { value: 1E6,  symbol: "M" },
          { value: 1E3,  symbol: "k" }
        ],
    }
    
    // prototype holds methods (to save memory space)
    FormatNum.prototype = {
        
        validate: function() {
            // check that is a valid language
            // references the externally inaccessible 'supportedUnit' within the closure
             if (supportedUnit.indexOf(this.unit)  === -1) {
                throw "Invalid unit";   
             }
        },
      
        calculate: function(unitType) {
          const unitMap = unit[unitType]; 
          const rx = /\.0+$|(\.[0-9]*[1-9])0+$/;
          for (let i = 0; i < unitMap.length; i++) {
            if (this.num >= unitMap[i].value) {
              return (this.num / unitMap[i].value).toFixed(this.digits || 1).replace(rx, "$1") + unitMap[i].symbol;
            }
          }
        },
      
        formatScientific: function() {
          return this.calculate('siUnit');
        },
        
        formatNormal: function() {
          return this.calculate('normalUnit');
        },
        // chainable methods return their own containing object
        format: function(unit) {
            let formattedNum;
            
            // if undefined or null it will be coerced to 'false'
            if (unit === 'scientific') {
                formattedNum = this.formatScientific();  
            }
            else {
                formattedNum = this.formatNormal();  
            }
          
            this.formattedNum = formattedNum;
            // 'this' refers to the calling object at execution time
            // makes the method chainable
            return this;
        },
        
        log: function() {
            if (console) {
                console.log('formattedNum is: ' + this.formattedNum); 
            }
            
            // make chainable
            return this;
        },
        
    };
    
    // the actual object is created here, allowing us to 'new' an object without calling 'new'
    FormatNum.init = function(num, digits, unit) {
        
        const self = this;
        self.num = num || '';
        self.digits = digits || '';
        self.unit = unit || 'normal';
        
        self.validate();
        
    };
    
    // trick borrowed from jQuery so we don't have to use the 'new' keyword
    FormatNum.init.prototype = FormatNum.prototype;
  
    global.FormatNum = global.F$ = FormatNum;
    
}(window));
Output

You can jump to the latest bin by adding /latest to your URL

Dismiss x