带有对象的Javascript纯函数示例

时间:2015-10-23 09:39:21

标签: javascript function

我有一个不纯函数的例子。请注意,变量a在函数范围之外。为了解决它,可以克隆函数内的对象并返回一个副本,但这是正确的方法吗?

有哪些选项可以使函数transformObject变为纯粹的?

var a = {
    a : 1,
    b : 2
};

function transformObject(obj) {
    var ref = obj;
    _.each(ref, function(val, index){
        ref[index] = val*2;
    });
    return ref;
}

s=JSON.stringify
$('#code').text(s(transformObject(a)))
$('#code2').text(s(a))

https://jsfiddle.net/br17kk2h/1/

2 个答案:

答案 0 :(得分:2)

纯函数遵循三个主要原则:

该功能只有一个责任

该功能应该只做一件事。

该功能无副作用

该功能不会改变其范围之外的状态。

该功能是参考透明的

该功能为相同的输入输出相同的值。

下一步是探索这些原则在功能设计中的影响。

你的功能已经符合第一个原则,虽然名称应该改进;)

它也符合第二个原则,因为它不会修改其范围之外的任何其他东西(它的输入参数)。

不幸的是,它不符合第三个原则:

var a = {
  a : 1,
  b : 2
};

var b = transformObject(a);//b = {2, 4}

var c = transformObject(a);//c = {4, 8}

相同的输入(a)但输出不同。这违反了第三条原则。

参考透明函数需要不可变数据。

Nina Scholz已经发布了一个很好的答案:

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

但它只能起作用,因为输入对象不包含嵌套在其中的任何其他对象。

现在有一些好的库可以为你提供不可变的结构(比如ImmutableJS)。

使用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));
    });
});

您可以阅读有关不可变API here

的更多信息

答案 1 :(得分:1)

更改对象:

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>');

保留对象并返回一个带有结果的新对象:

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>');