Javascript pure function example with objects

前端 未结 2 1455
醉话见心
醉话见心 2021-01-21 13:15

I have the example below of an impure function. Note the variable a is outside of the function scope is being changed. To get around it, one could clone the object

相关标签:
2条回答
  • 2021-01-21 13:56

    Change the object:

    function transformObject(a) {			
        Object.keys(a).forEach(function (k) { a[k] *= 2; });
    }
    
    var a = {
            a : 1,
            b : 2
        };
    transformObject(a);		
    document.write('<pre>' + JSON.stringify(a, 0, 4) + '</pre>');

    Keep the object and return a new object with the result:

    function transformObject(a) {
        var b = {};
        Object.keys(a).forEach(function (k) { b[k] = a[k] * 2; });
        return b;
    }
    
    var a = {
            a : 1,
            b : 2
        },
        b = transformObject(a);		
    document.write('<pre>' + JSON.stringify(a, 0, 4) + '</pre>');
    document.write('<pre>' + JSON.stringify(b, 0, 4) + '</pre>');

    0 讨论(0)
  • 2021-01-21 14:16

    A pure function follows three main principles:

    The function has a single responsibility

    The function should do only one thing.

    The function has no side effects

    The function does not change state outside its scope.

    The function is referentially transparent

    The function outputs the same value for the same inputs.

    The next step is to explore the impact of these principles in the design of the function.

    Your function already meets the first principle, although the name should be improved ;)

    And it meets the second principle too, because it doesn't modify anything else outside its scope (its input parameters).

    Unfortunately it doesn't meet the third principle:

    var a = {
      a : 1,
      b : 2
    };
    
    var b = transformObject(a);//b = {2, 4}
    
    var c = transformObject(a);//c = {4, 8}
    

    Same inputs (a) but different outputs. That violates the third principle.

    Referentially transparent functions needs immutable data.

    A good answer has already been posted by Nina Scholz:

    function transformObject(a) {
      var b = {};
      Object.keys(a).forEach(function (k) { b[k] = a[k] * 2; });
      return b;
    }
    

    But it only works because the input object does not contain any other object nested in it.

    Right now there are some good libraries that gives you immutable structures (like ImmutableJS).

    A simple example using ImmutableJS:

    describe('a List', () => {
    
        function addMovie(currentState, movie) {
            return currentState.push(movie);
        }
    
        it('is immutable', () => {
    
            let state = List.of('Avengers', 'Antman');
            let nextState = addMovie(state, 'Superman');
    
            expect(nextState).to.equal(List.of(
                'Avengers',
                'Antman',
                'Superman'
            ));
    
            expect(state).to.equal(List.of(
                'Avengers',
                'Antman'
            ));
        });
    
        it('can be updated and returns another immutable List', () => {
    
            let state = List.of(1,2,3,4);
    
            let nextState = state.map(value => value*2);
    
            expect(nextState).to.equal(List.of(2,4,6,8));
            expect(state).to.equal(List.of(1,2,3,4));
        });
    });
    

    You can read more about immutable API here

    0 讨论(0)
提交回复
热议问题