Write small and plain functions

"do one thing and do it well".

dedicate time not only to implementation, but also to a correct structure of your functions

https://rainsoft.io/the-art-of-writing-small-and-plain-functions/?utm_source=codropscollective

Measure seven times, cut once.

假设一个场景:当一个功能函数需要通过返回"数组","map","简单js对象"去计算他的特性的值。

 

* 1 point for null or undefined

* 2 points for a primitive type

* 4 points for an object or function.

primitive type:简单键值对对象

    
    function getCollectionWeight(collection) {  
      let collectionValues;
      if (collection instanceof Array) {
        collectionValues = collection;
      } else if (collection instanceof Map) {
        collectionValues = [...collection.values()];
      } else {
        collectionValues = Object.keys(collection).map(function (key) {
          return collection[key];
        });
      }
      return collectionValues.reduce(function(sum, item) {
        if (item == null) {
          return sum + 1;
        } 
        if (typeof item === 'object' || typeof item === 'function') {
          return sum + 4;
        }
        return sum + 2;
      }, 0);
    }
    let myArray = [null, { }, 15];  
    let myMap = new Map([ ['functionKey', function() {}] ]);  
    let myObject = { 'stringKey': 'Hello world' };  
    getCollectionWeight(myArray);  // => 7 (1 + 4 + 2)  
    getCollectionWeight(myMap);    // => 4  
    getCollectionWeight(myObject); // => 2  

getCollectionWeight()

Now the goal is to split the big function into smaller, independent and reusable ones

    
    function getWeightByType(value) {  
      const WEIGHT_NULL_UNDEFINED  = 1;
      const WEIGHT_PRIMITIVE       = 2;
      const WEIGHT_OBJECT_FUNCTION = 4;
      if (value == null) {
        return WEIGHT_NULL_UNDEFINED;
      } 
      if (typeof value === 'object' || typeof value === 'function') {
        return WEIGHT_OBJECT_FUNCTION;
      }
      return WEIGHT_PRIMITIVE;
    }
    function getCollectionWeight(collection) {  
      let collectionValues;
      if (collection instanceof Array) {
        collectionValues = collection;
      } else if (collection instanceof Map) {
        collectionValues = [...collection.values()];
      } else {
        collectionValues = Object.keys(collection).map(function (key) {
          return collection[key];
        });
      }
      return collectionValues.reduce(function(sum, item) {
        return sum + getWeightByType(item);
      }, 0);
    }
    let myArray = [null, { }, 15];  
    let myMap = new Map([ ['functionKey', function() {}] ]);  
    let myObject = { 'stringKey': 'Hello world' };  
    getCollectionWeight(myArray);  // => 7 (1 + 4 + 2)  
    getCollectionWeight(myMap);    // => 4  
    getCollectionWeight(myObject); // => 2  

    if (item == null) {
      return sum + 1;
    } 
    if (typeof item === 'object' || 
        typeof item === 'function') {
      return sum + 4;
    }
    return sum + 2;
function getWeightByType(value) {  
  const WEIGHT_NULL_UNDEFINED = 1;
  const WEIGHT_PRIMITIVE = 2;
  const WEIGHT_OBJECT_FUNCTION = 4;
  if (value == null) {
    return WEIGHT_NULL_UNDEFINED;
  } 
  if (typeof value === 'object' || 
        typeof value === 'function') {
    return WEIGHT_OBJECT_FUNCTION;
  }
  return WEIGHT_PRIMITIVE;
}
// Code extracted into getMapValues()
function getMapValues(map) {  
  return [...map.values()];
}
// Code extracted into getPlainObjectValues()
function getPlainObjectValues(object) {  
  return Object.keys(object).map(function (key) {
    return object[key];
  });
}
function getCollectionWeight(collection) {  
  let collectionValues;
  if (collection instanceof Array) {
    collectionValues = collection;
  } else if (collection instanceof Map) {
    collectionValues = getMapValues(collection);
  } else {
    collectionValues = getPlainObjectValues(collection);
  }
  return collectionValues.reduce(function(sum, item) {
    return sum + getWeightByType(item);
  }, 0);
}
  
  else if (collection instanceof Map) {
    collectionValues = [...collection.values()];
  } else {
    collectionValues = Object.keys(collection)
        .map(function (key) {
      return collection[key];
    });
  }
   
     function getWeightByType(value) {  
      const WEIGHT_NULL_UNDEFINED = 1;
      const WEIGHT_PRIMITIVE = 2;
      const WEIGHT_OBJECT_FUNCTION = 4;
      if (value == null) {
        return WEIGHT_NULL_UNDEFINED;
      } 
      if (typeof value === 'object' || 
            typeof value === 'function') {
        return WEIGHT_OBJECT_FUNCTION;
      }
      return WEIGHT_PRIMITIVE;
    }
    function getMapValues(map) {  
      return [...map.values()];
    }
    function getPlainObjectValues(object) {  
      return Object.keys(object)
        .map(function (key) {
           return object[key];
        });
    }
    function getCollectionValues(collection) {  
      if (collection instanceof Array) {
        return collection;
      }
      if (collection instanceof Map) {
        return getMapValues(collection);
      }
      return getPlainObjectValues(collection);
    }
    function reduceWeightSum(sum, item) {  
      return sum + getWeightByType(item);
    }
    function getCollectionWeight(collection) {  
      return getCollectionValues(collection)
        .reduce(reduceWeightSum, 0);
    }
 
  let collectionValues;
  if (collection instanceof Array) {
    collectionValues = collection;
  } else if (collection instanceof Map) {
    collectionValues = getMapValues(collection);
  } else {
    collectionValues = getPlainObjectValues(collection);
  }
  return collectionValues.reduce(function(sum, item) {
    return sum + getWeightByType(item);
  }, 0);
function getCollectionWeight(collection) {  
  let collectionValues;
  if (collection instanceof Array) {
    collectionValues = collection;
  } else if (collection instanceof Map) {
    collectionValues = [...collection.values()];
  } else {
    collectionValues = Object.keys(collection)
    .map(function (key) {
      return collection[key];
    });
  }
  return collectionValues
    .reduce(function(sum, item) {
    if (item == null) {
      return sum + 1;
    } 
    if (typeof item === 'object' ||
         typeof item === 'function') {
      return sum + 4;
    }
    return sum + 2;
  }, 0);
}
function getWeightByType(value) {  
  const WEIGHT_NULL_UNDEFINED = 1;
  const WEIGHT_PRIMITIVE = 2;
  const WEIGHT_OBJECT_FUNCTION = 4;
  if (value == null) {
    return WEIGHT_NULL_UNDEFINED;
  } 
  if (typeof value === 'object' || 
        typeof value === 'function') {
    return WEIGHT_OBJECT_FUNCTION;
  }
  return WEIGHT_PRIMITIVE;
}
function getMapValues(map) {  
  return [...map.values()];
}
function getPlainObjectValues(object) {  
  return Object.keys(object)
    .map(function (key) {
    return object[key];
  });
}
function getCollectionValues(collection) {  
  if (collection instanceof Array) {
    return collection;
  }
  if (collection instanceof Map) {
    return getMapValues(collection);
  }
  return getPlainObjectValues(collection);
}
function reduceWeightSum(sum, item) {  
  return sum + getWeightByType(item);
}
function getCollectionWeight(collection) {  
  return getCollectionValues(collection)
    .reduce(reduceWeightSum, 0);
}
  1. 可读的getCollectionWeight()函数增加了自解释的代码。
  2. getCollectionWeight()的体积减少
  3. getCollectionWeight()函数现在不随判定值的添加的增加而增加
  4. 分离出来的代码具有低耦合和可复用性了,你的同事也可以将其运用到这些不错的函数在其他项目中,并且是轻而易举的
  5. 如果一旦代码有报错,报错堆栈更清晰,因为他包含了函数名称,你可以轻易的判定出错的部分
  6. 分割出来的代码可测试性更高,可以达到更高的测试覆盖率,测试巨大的函数是很糟糕的,前者你可以为每一个函数构造测试和验证它
  7. 你可以按照commmonjs和ES6去构造你的函数,将其分割成小函数,使你的项目都由小函数构造而成
  1. The readability of getCollectionWeight() increased by self-explanatory code
  2. The size of getCollectionWeight() reduced considerable
  3. getCollectionWeight() function is now protected from fast growth if you plan to implement the weight calculation of other collection types
  4. The extracted functions are now decoupled and reusable components. Your colleague may ask you to import these nice functions into another project: and you can easily do that
  5. If accidentally a function generates an error, the call stack will be more precisebecause it contains the function names. Almost instantly you could determine the function that makes problems
  6. The split functions are much easier to test and reach a high level of code coverage. Instead of testing one big function with all possible scenarios, you can structure your tests and verify each small function separately
  7. You can benefit from CommonJS or ES2015 modules format. Create from extracted functions separated modules. This makes your project files lightweight and structured.

   

filter-nav.js

enterOneFilter()

enterTwoFilter()

enterThreeFilter()

......

map.js

createPoint()

setValObj.attr({'businessId':business_id});
setValObj.attr({'share-url':shareUrl});
setValObj.attr({'share-pic':sharePic});
setValObj.attr({'share-con':shareContent});
setValObj.attr(
    {'businessId':business_id},
    {'share-url':shareUrl},
    {'share-pic':sharePic},
    {'share-con':shareContent}
);
judgeUrlOut:function(type,currPoint,oldImgName){
    if(type == "service"){
        if(oldImgName == 'servicediamond'){
            currPoint.attr('src', ZBJMap.mapUrl.serviceDiamond);
        } else if(oldImgName == 'servicenormal'){
            currPoint.attr('src', ZBJMap.mapUrl.serviceNormal);
        } else if(oldImgName == 'servicecrown'){
            currPoint.attr('src', ZBJMap.mapUrl.serviceCrown);
        } else if(oldImgName == 'servicet'){
            currPoint.attr('src', ZBJMap.mapUrl.serviceT);
        }
    } else if(type == "business"){
        if(oldImgName == 'businessdiamond'){
            currPoint.attr('src', ZBJMap.mapUrl.businessDiamond);
        } else if(oldImgName == 'businessnormal'){
            currPoint.attr('src', ZBJMap.mapUrl.businessNormal);
        } else if(oldImgName == 'businesscrown'){
            currPoint.attr('src', ZBJMap.mapUrl.businessCrown);
        } else if(oldImgName == 'businesst'){
            currPoint.attr('src', ZBJMap.mapUrl.businessT);
        }
    }
},

switch case

switch只计算一次值 然后都是test,jmp, if...else   是每个条件都要计算一遍的.

Write small and plain functions

By pokerone

Write small and plain functions

  • 849