Javascript 如何在函数样式的对象数组中仅更改一个特定对象?

Javascript 如何在函数样式的对象数组中仅更改一个特定对象?,javascript,functional-programming,underscore.js,code-readability,Javascript,Functional Programming,Underscore.js,Code Readability,让我们假设我们想要创建一些可读性很强的代码,然后执行以下操作: 遍历列表的所有元素 除一个特定元素外,对所有元素进行同等更改(即使多个元素可以满足搜索条件) 返回包含已更改元素的列表 使用下划线power 例如,我想将属性isChosen和true值仅添加到具有hasRoom属性的第一个元素,其他元素应该为这个新属性hasRoom获得false值 下面是使用下划线库创建的代码: var i = 0 var changedList = [] _.each(list, function(

让我们假设我们想要创建一些可读性很强的代码,然后执行以下操作:

  • 遍历列表的所有元素
  • 除一个特定元素外,对所有元素进行同等更改(即使多个元素可以满足搜索条件)
  • 返回包含已更改元素的列表
  • 使用下划线power
  • 例如,我想将属性
    isChosen
    true
    值仅添加到具有
    hasRoom
    属性的第一个元素,其他元素应该为这个新属性
    hasRoom
    获得
    false

    下面是使用下划线库创建的代码:

      var i = 0
      var changedList = []
      _.each(list, function(el) {
        if (el.hasRoom && i === 0) {
          _.extend(el, { isChosen: true })
          i++
        } else {
          _.extend(el, { isChosen: false })
        }
        changedList.push(el)
      })
    
    这段代码可以工作,但我认为可以有更好的方法来实现这一点,也许可以使用u.chain()

    因此,作为输入,我们可以

    [
        {hasRoom: false}, 
        {hasRoom: true}, 
        {hasRoom: true}
    ]
    
    因此,我们应该

    [
        {hasRoom: false, isChosen: false}, 
        {hasRoom: true,  isChosen: true}, 
        {hasRoom: true,  isChosen: false}
    ]
    

    您可以使用通常称为
    first
    的方法来查找与您的条件匹配的第一个元素:

    function first (array, filter_function) {
        var index, len = array.length;
        for (index = 0; index < len; index += 1) {
            if (filter_function(array[index], index)) {
                return index;
            }
        }
        return -1;
    }
    
    rooms = [
        { hasRoom: false }, 
        { hasRoom: true }, 
        { hasRoom: true }
    ];
    
    free_room = first(rooms, function (room) {
        return room.hasRoom;
    });
    if (free_room === -1) {
        throw "Dilbert lied!";
    }
    rooms[free_room].isChosen = true;
    
    函数优先(数组、过滤器函数){
    var指数,len=array.length;
    对于(索引=0;索引


    请注意,
    \u js
    还定义了数组上的
    第一个
    函数,但它更适用于
    函数。您可以就语义进行争论。

    您可以使用通常称为
    first
    的方法来查找与您的条件匹配的第一个元素:

    function first (array, filter_function) {
        var index, len = array.length;
        for (index = 0; index < len; index += 1) {
            if (filter_function(array[index], index)) {
                return index;
            }
        }
        return -1;
    }
    
    rooms = [
        { hasRoom: false }, 
        { hasRoom: true }, 
        { hasRoom: true }
    ];
    
    free_room = first(rooms, function (room) {
        return room.hasRoom;
    });
    if (free_room === -1) {
        throw "Dilbert lied!";
    }
    rooms[free_room].isChosen = true;
    
    var _ = require("underscore");
    var data = [{hasRoom: true}, {hasRoom: true}, {}], found = false;
    
    _.each(data, function(currentObject) {
        _.defaults(currentObject, {isChosen: false});
        if (found === false && currentObject.hasRoom) {
            found = currentObject.isChosen = true;
        }
    });
    
    console.log(data);
    
    函数优先(数组、过滤器函数){
    var指数,len=array.length;
    对于(索引=0;索引

    请注意,
    \u js
    还定义了数组上的
    第一个
    函数,但它更适用于
    函数。你可以争论语义学

    var _ = require("underscore");
    var data = [{hasRoom: true}, {hasRoom: true}, {}], found = false;
    
    _.each(data, function(currentObject) {
        _.defaults(currentObject, {isChosen: false});
        if (found === false && currentObject.hasRoom) {
            found = currentObject.isChosen = true;
        }
    });
    
    console.log(data);
    
    输出

    [ { hasRoom: true, isChosen: true },
      { hasRoom: true, isChosen: false },
      { isChosen: false } ]
    
    输出

    [ { hasRoom: true, isChosen: true },
      { hasRoom: true, isChosen: false },
      { isChosen: false } ]
    

    在功能性风格中,您可以这样做:

    // type: [a] -> (a -> Bool -> b) -> (a -> Bool) -> [b]
    function changeFirstinList(list, change, predicate) {
        var first = true;
        return _.map(list, function(el) {
            return change(el, first && !(first = !predicate(el)));
        });
    }
    
    changeFirstinList([
        {hasRoom: false}, 
        {hasRoom: true}, 
        {hasRoom: true}
    ], function(el, isFirstwithpred) {
        return {hasRoom: el.hasRoom, isChosen: isFirstwithpred};
    }, function(el) {
        return el.hasRoom;
    });
    

    在功能性风格中,您可以这样做:

    // type: [a] -> (a -> Bool -> b) -> (a -> Bool) -> [b]
    function changeFirstinList(list, change, predicate) {
        var first = true;
        return _.map(list, function(el) {
            return change(el, first && !(first = !predicate(el)));
        });
    }
    
    changeFirstinList([
        {hasRoom: false}, 
        {hasRoom: true}, 
        {hasRoom: true}
    ], function(el, isFirstwithpred) {
        return {hasRoom: el.hasRoom, isChosen: isFirstwithpred};
    }, function(el) {
        return el.hasRoom;
    });
    

    此解决方案修改设置isChosen的函数:

    function notChosen(place){
      return false;
    }
    
    function chosen(place){
      if( !place.hasRoom ) return notChosen(place);
      setChosen = notChosen;
      return true;
    }
    
    var setChosen = chosen;
    
    _.each(places, function(place){
        place.isChosen = setChosen(place);
    });
    

    if语句将仅在找到第一个有房间的位置之前执行。

    此解决方案修改设置isChosen的函数:

    function notChosen(place){
      return false;
    }
    
    function chosen(place){
      if( !place.hasRoom ) return notChosen(place);
      setChosen = notChosen;
      return true;
    }
    
    var setChosen = chosen;
    
    _.each(places, function(place){
        place.isChosen = setChosen(place);
    });
    

    if语句将一直执行到找到第一个有房间的位置。

    最后,我的代码开始如下所示:

    function addChosenPropertyToFirstElementWithRooms(hotels) {
      var found = false
      return _.map(list, function(el) {
        return _.merge(el, { isChosen: isFirstElementWithRooms(el) })
      })
    
      function isFirstHotelWithRooms(el) {
        return found ? false : found = el.hasRoom
      }
    }
    
    而且函数的使用也很简单

    var changedList = addChosenPropertyToFirstElementWithRooms(originalList)
    

    最后,我的代码开始如下所示:

    function addChosenPropertyToFirstElementWithRooms(hotels) {
      var found = false
      return _.map(list, function(el) {
        return _.merge(el, { isChosen: isFirstElementWithRooms(el) })
      })
    
      function isFirstHotelWithRooms(el) {
        return found ? false : found = el.hasRoom
      }
    }
    
    而且函数的使用也很简单

    var changedList = addChosenPropertyToFirstElementWithRooms(originalList)
    

    您必须创建一个新对象吗?至于代码可读性标记,当您可以使用布尔值时,为什么要使用数字?@user1066946此代码块位于函数addPropertyToOnlyOneElement(列表)内,它应该返回已更改的列表您必须创建新对象吗?至于代码可读性标记,当你可以使用布尔值时,为什么要使用数字?@user1066946此代码块位于函数addPropertyToOnlyOneElement(列表)内,它应该返回更改的列表如果你将所有内容都放在全局范围内,JavaScript中也有for-each,JavaScript中没有for-each;仅适用于中的
    。我们处理的是数组而不是对象,因此不需要使用中的
    for
    。这是一个概念验证代码,用于演示
    first
    的工作原理,将您的全球范围关注点带到相关的地方。你的评论是错误和误导性的。你确定你的代码比问题中的代码可读性更好吗?有
    Array.prototype.forEach
    和for-in循环,在编辑问题之前,你将答案中的每个变量都放在全局范围内,答案的长度是问题的两倍。对不起,我使用了Chrome,我不知道你在运行IE8,你把所有的东西都放在全局范围内,JavaScript中有一个for-each,JavaScript中没有for-each;仅适用于中的
    。我们处理的是数组而不是对象,因此不需要使用中的
    for
    。这是一个概念验证代码,用于演示
    first
    的工作原理,将您的全球范围关注点带到相关的地方。你的评论是错误和误导性的。你确定你的代码比问题中的代码可读性更好吗?有
    Array.prototype.forEach
    和for-in循环,在编辑问题之前,你将答案中的每个变量都放在全局范围内,答案的长度是问题的两倍。对不起,我使用了Chrome,不知道你在运行IE8