zoukankan      html  css  js  c++  java
  • a primary example for Functional programming in javascript

    1. background

    In pursuit of a real-world application, let’s say we need an e-commerce web application
    for a mail-order coffee bean company. They sell several types of coffee and in different
    quantities, both of which affect the price.

    1. Imperative methods

    First, let’s go with the procedural route. To keep this demonstration down to earth, we’ll
    have to create objects that hold the data. This allows the ability to fetch the values from a
    database if we need to. But for now, we’ll assume they’re statically defined:

    // create some objects to store the data.
    var columbian = {
        name: 'columbian',
        basePrice: 5
    };
    var frenchRoast = {
        name: 'french roast',
        basePrice: 8
    };
    var decaf = {
        name: 'decaf',
        basePrice: 6
    };

    // we'll use a helper function to calculate the cost
    // according to the size and print it to an HTML list
    function printPrice(coffee, size) {
      if (size == 'small') {
        var price = coffee.basePrice + 2;
      }
      else if (size == 'medium') {
        var price = coffee.basePrice + 4;
      }
      else {
        var price = coffee.basePrice + 6;
      }
      // create the new html list item
      var node = document.createElement("li");
      var label = coffee.name + ' ' + size;
      var textnode = document.createTextNode(label+' price: $'+price);
      node.appendChild(textnode);
      document.getElementById('products').appendChild(node);
    }
    // now all we need to do is call the printPrice function
    // for every single combination of coffee type and size
    printPrice(columbian, 'small');
    printPrice(columbian, 'medium');
    printPrice(columbian, 'large');
    printPrice(frenchRoast, 'small');
    printPrice(frenchRoast, 'medium');
    printPrice(frenchRoast, 'large');
    printPrice(decaf, 'small');
    printPrice(decaf, 'medium');
    printPrice(decaf, 'large');

     
    1. Functional programming

    While imperative code tells the machine, step-by-step, what it needs to do to solve the
    problem, functional programming instead seeks to describe the problem mathematically so
    that the machine can do the rest.
    With a more functional approach, the same application can be written as follows:

    // separate the data and logic from the interface
    var printPrice = function(price, label) {
        var node = document.createElement("li");
        var textnode = document.createTextNode(label+' price: $'+price);
        node.appendChild(textnode);
        document.getElementById('products 2').appendChild(node);
    }
    // create function objects for each type of coffee
    var columbian = function(){
        this.name = 'columbian';
        this.basePrice = 5;
    };
    var frenchRoast = function(){
        this.name = 'french roast';
        this.basePrice = 8;
    };
    var decaf = function(){
        this.name = 'decaf';
        this.basePrice = 6;
    };
    // create object literals for the different sizes
    var small = {
        getPrice: function(){return this.basePrice + 2},
        getLabel: function(){return this.name + ' small'}
    };
    var medium = {
        getPrice: function(){return this.basePrice + 4},
        getLabel: function(){return this.name + ' medium'}
    };
    var large = {
        getPrice: function(){return this.basePrice + 6},
        getLabel: function(){return this.name + ' large'}
    };
    // put all the coffee types and sizes into arrays
    var coffeeTypes = [columbian, frenchRoast, decaf];
    var coffeeSizes = [small, medium, large];
    // build new objects that are combinations of the above
    // and put them into a new array
    var coffees = coffeeTypes.reduce(function(previous, current) {
        var newCoffee = coffeeSizes.map(function(mixin) {
            // `plusmix` function for functional mixins, see Ch.7
            var newCoffeeObj = plusMixin(current, mixin);
            return new newCoffeeObj();
        });
        return previous.concat(newCoffee);
    },[]);
    // we've now defined how to get the price and label for each
    // coffee type and size combination, now we can just print them
    coffees.forEach(function(coffee){
    printPrice(coffee.getPrice(),coffee.getLabel());
    });
    
    
    The first thing that should be obvious is that it is much more modular. This makes adding
    a new size or a new coffee type as simple as shown in the following code snippet:
    var peruvian = function(){
        this.name = 'peruvian';
        this.basePrice = 11;
    };
    var extraLarge = {
        getPrice: function(){return this.basePrice + 10},
        getLabel: function(){return this.name + ' extra large'}
    };
    coffeeTypes.push(Peruvian);
    coffeeSizes.push(extraLarge);

    Arrays of coffee objects and size objects are “mixed” together,—that is, their methods and
    member variables are combined—with a custom function called plusMixin (see Chapter
    7, Functional and Object-oriented Programming in JavaScript). The coffee type classes
    contain the member variables and the sizes contain methods to calculate the name and
    price. The “mixing” happens within a map operation, which applies a pure function to each
    element in an array and returns a new function inside a reduce() operation—another
    higher-order function similar to the map function, except that all the elements in the array
    are combined into one. Finally, the new array of all possible combinations of types and
    sizes is iterated through with the forEach() method The forEach() method is yet another
    higher-order function that applies a callback function to each object in an array. In this
    example, we provide it as an anonymous function that instantiates the objects and calls the
    printPrice() function with the object’s getPrice() and getLabel() methods as
    arguments.
    Actually, we could make this example even more functional by removing the coffees
    variable and chaining the functions together—another little trick in functional
    programming.

    coffeeTypes.reduce(function(previous, current) {
        var newCoffee = coffeeSizes.map(function(mixin) {
                // `plusMixin` function for functional mixins, see Ch.7
                var newCoffeeObj = plusMixin(current, mixin);
                return new newCoffeeObj();
            });
            return previous.concat(newCoffee);
    },[]).forEach(function(coffee) {    
        printPrice(coffee.getPrice(),coffee.getLabel());
    });

    Also, the control flow is not as top-to-bottom as the imperative code was. In functional
    programming, the map() function and other higher-order functions take the place of for
    and while loops and very little importance is placed on the order of execution. This makes
    it a little trickier for newcomers to the paradigm to read the code but, once you get the
    hang of it, it’s not hard at all to follow and you’ll see that it is much better.

     
  • 相关阅读:
    TCP/IP和HTTP的举例理解
    c#中栈和堆的理解
    c#设计模式之单例模式
    JSON.stringify实例应用—将对象转换成JSON类型进行AJAX异步传值
    JSON.stringify初识
    c# 过滤字符串中的重复字符
    C#中jQuery Ajax实例(二)
    C#中jQuery Ajax实例(一)
    jQuery动态对表格Table进行添加或删除行以及修改列值操作
    asp.net中控件的Attributes用法
  • 原文地址:https://www.cnblogs.com/uchenm/p/4981579.html
Copyright © 2011-2022 走看看