关于如何写好JavaScript的一些小技巧(续) | 青训营笔记

89 阅读3分钟

这是我参与「第四届青训营」笔记创作活动的第5天

本堂课重点内容:

  • 写代码我们最应该关注什么
  • 当年的Leftpad事件
  • 分红包算法

详细知识点介绍:

写代码我们最应该关注什么?

  • 写代码我们应该要注重风格、效率、约定、 使用场景(算法) 和设计等方面。

当年的Leftpad事件

下面是当年npmLeft-pad事件:

  function leftpad(str, len, ch) {
      str = String(str);
      var i = -1;
      if (!ch && ch !== 0) ch = ' ';
      len = len - str.length;
      while (++i < len) {
          str = ch + str;
      }
      return str;
  } 

当时这个模块被用于很多的npm包中,但是后面被作者下线了,所以引起了很大的风波,因为很多人在用的库突然被下线了。

事件本身的槽点:

  • NPM 模块粒度
  • 代码风格
  • 代码质量/效率

考虑到效率问题,后来有人将代码改造成了如下所示,减少了计算次数,提升了运行效率:

  function leftpad(str, len, ch) {
      str = "" + str;
      const padLen = len - str.length;
      if(padLen <= 0) {
        return str;
      }
      return (""+ch).repeat(padLen)+str;
  } 

上方代码使用了repeat函数,优化了运行时的计算次数,那么接下来我们不妨看看repeat函数源码吧:

 /*! https://mths.be/repeat v1.0.0 by @mathias */

  'use strict';

  var RequireObjectCoercible = require('es-abstract/2019/RequireObjectCoercible');
  var ToString = require('es-abstract/2019/ToString');
  var ToInteger = require('es-abstract/2019/ToInteger');

  module.exports = function repeat(count) {
    var O = RequireObjectCoercible(this);
    var string = ToString(O);
    var n = ToInteger(count);
    // Account for out-of-bounds indices
    if (n < 0 || n == Infinity) {
      throw RangeError('String.prototype.repeat argument must be greater than or equal to 0 and not be Infinity');
    }

    var result = '';
    while (n) {
      if (n % 2 == 1) {
        result += string;
      }
      if (n > 1) {
        string += string;
      }
      n >>= 1;
    }
    return result;
  };

分红包算法

微信红包相信大家都使用过,那么大家是否曾试想过,他的随机红包是如何实现的呢?为何别人可以抢到很多很多,而自己却总是很少呢?那我们就一起来剖析吧。

<h2>红包生成器</h2>
<div id="setting">
  <div><label>红包金额:<input id="amount" value=100.00></input></label></div>
  <div><label>红包数量:<input id="count" value="10"></input></label></div>
  <div><button id="generateBtn">随机生成</button></div>
</div>

<ul id="result">
</ul>
const amountEl = document.getElementById('amount');
const countEl = document.getElementById('count');
const generateBtn = document.getElementById('generateBtn');
const resultEl = document.getElementById('result');

generateBtn.addEventListener('click', () => {
  const money = parseFloat(amountEl.value)
  const count = parseInt(countEl.value)
  if (money * 100 < count) {
    resultEl.innerText = '金额不足'
    return
  }
  let arr = distribute(money, count)
  let res = ''
  for (const num of arr) {
    res += (num / 100).toFixed(2) + '\n'
  }
  resultEl.innerText = res
})

function distribute(money, count) {
  money *= 100
  return new Array(count).fill(money / count)
}

以上两段代码就简单的实现了红包的平分功能(效果如下):

  • 平分法 那既然如此,随机分配又如何实现呢? 在夏天,我们都会吃西瓜来解渴,于是在切西瓜时,我们可能会切得大小不一,一块大一点,一块小一点,但平均来说大小都不会差距太多,那么随机分配红包的道理也不尽相同:
  • 切西瓜法 切西瓜法

可以看到,这次的随机分配结果不尽相同,有多有少。 此时细心的同学可能会发现,虽然是随机分配了,但是随机数直接的差距并不会有太大,也就没有了抢红包时 的那种刺激感,看不见一个人可以抢到很多,而另一个人只能抢到很少的结果了,那么,这该如何去优化呢?

  • 抽牌法 抽牌法 没错,那便是抽排法,相信同学们应该都玩过扑克牌,扑克牌在洗牌阶段,牌的顺序是随机的,且这种随机性比较大,大牌和小牌被分配的位置没有大致的准确性,随机性极高,那么我们也可以采用这种方法,达到随机分配红包金额的目的。

课后个人总结:

写代码时,我们应该注重以下几个方面:

  • 风格:选择什么风格都没有错,关键是风格要统一(分号、行尾花括号等等)。
  • 效率:在写代码时要考虑什么样的代码写起来效率是最高的,能写高效率的代码就不要写低效率的代码;当然,也要追求一个平衡就是,要结合它的场景来使用。
  • 约定:在开发前,团队要约定好代码规范和风格,比如 eslint 、 airbnb 等等。
  • 使用场景:不要为了追求好的时间复杂度而抛弃代码本身的使用场景。

引用参考:

文章引用月影老师的代码片段,老师主页:juejin.cn/user/712139…