带有对象的 Javascript 纯函数示例

2023-12-02

我有下面一个不纯函数的例子。注意变量a超出了正在更改的函数范围。为了解决这个问题,人们可以克隆函数内的对象并返回一个副本,但这是正确的方法吗?

实现该功能有哪些选项transformObject pure?

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/


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

该函数具有单一职责

该函数应该只做一件事。

该功能没有副作用

该函数不会在其范围之外更改状态。

该函数是引用透明的

该函数对于相同的输入输出相同的值。

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

你的函数已经满足了第一个原则,尽管名称应该改进;)

它也满足第二个原则,因为它不会修改其范围(其输入参数)之外的任何其他内容。

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

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

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

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

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

引用透明的函数需要不可变的数据。

一个很好的答案已经发布了尼娜·肖尔茨:

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

但它仅在输入对象不包含嵌套在其中的任何其他对象时才起作用。

现在有一些很好的库可以为您提供不可变的结构(例如不可变JS).

使用 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

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

带有对象的 Javascript 纯函数示例 的相关文章

随机推荐