npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@jkt/lose-weight

v2.0.0

Published

用于提取 Array 类型和 Object 类型数据的字段

Downloads

10

Readme

lose-weight

:loudspeaker: 旧版文档请访问 1.x

:heart: 这是我在公司前端组里写的一个工具,最开始只是为了方便处理接口返回的数组类型数据,后来做了点扩展,增加了对象类型数据的支持。数据的来源也不仅限于接口,支持引入文件或其他任何形式得到的数据。

:heavy_exclamation_mark: 这是一个可选的工具,通过了解将要处理的数据结构和本文档,权衡各种因素后,再确定是否使用该工具!在实际工作中,请求接口得到的数据,引入文件(包,组件,工具或任何可被引入的东西)得到的数据,或其他任何形式得到的数据。其中的字段有些直接可用,有些需要加工后使用,有些需要重命名后使用,有些可以完全忽略。我们需要解构这些数据,期间按需对字段加工(如:使用 moment 对时间戳进行格式化)或重命名,如果是以数组形式组织的数据,还得循环解构。完成这些工作的代码量有时并不少,或许散落在各处,有时字段的出处难以明确!一般来说通过在接口处,引入文件处或任何生成数据的地方施加控制(如:约定),或者将原来的代码进行重构乃至重写,就能解决问题,至少是大大缓解问题。

特色

  • 可以处理数组类型和对象类型的数据;任何途径或形式产生的(如:接口返回,引入文件等)数据,只要符合类型要求;
  • 可以将解构,重命名,数据加工代码聚拢在一起。

环境要求

在用户代理(以下简称 ua) 运行时环境;

  • 需要支持 rest parameters(剩余参数)
  • 需要支持 Array.isArray api
  • 需要支持 Array.prototype.map api
  • 需要支持 Array.prototype.reduce api
  • 需要支持 Function.prototype.bind api

在 nodejs 运行时环境:

  • nodejs 需要较新(当前版本的上一个主要版本)的 lts 版(长期支持版)

:heavy_exclamation_mark: 在 ua 中(包含 pc 浏览器,手持设备浏览器,pc 或手持设备或一些 app 的 webview 端等)。如果是使用项目创建工具(如:create-react-app,vue-cli,Angular CLI 等类似工具)生成的项目,开发过程中,引用这个工具时,不用担心运行时环境要求(那些项目创建工具内部一般包含 babel)。在构建时通常也会转译成兼容 ua 的代码。

安装

在项目中安装

# 如果是在 windows powershell 中,可能需要这样
# npm install ‘@jkt/lose-weight’ --save
npm install @jkt/lose-weight --save

在代码中引用

// node
const {choose, assist} = require('@jkt/lose-weight')

或者

// ua
/*
  类似 create-react-app,vue-cli,Angular CLI 等工具创建的前端项目,
  内部一般都有 babel 提供支持
 */
import {choose, assist} from '@jkt/lose-weight'

// 或者
import * as loseWeight from '@jkt/lose-weight'
// loseWeight.choose
// loseWeight.assist

:heavy_exclamation_mark: 不支持在全局环境中引用,如 window.loseWeightwindow.choosewindow.assist

案例

案例 1

/* import someApi from 'somePackage' */
import {choose} from '@jkt/lose-weight'
import discoveryModel from "models/discovery";

/* class某某某... */

export default connect(
  // mapStateToProps
  ({discovery}) => ({...discovery}),
  // mapDispatchToProps
  choose(
    'getIndex',
    'getList', 
    'resetIndex', 
    'resetList', 
    'setKeyword', 
    'setListHasMore', 
    'setPageStart'
  ).from(discoveryModel.actions),
  /* 原来的写法
  {
    getIndex: discoveryModel.actions.getIndex,
    getList: discoveryModel.actions.getList,
    resetIndex: discoveryModel.actions.resetIndex,
    resetList: discoveryModel.actions.resetList,
    setKeyword: discoveryModel.actions.setKeyword,
    setListHasMore: discoveryModel.actions.setListHasMore,
    setPageStart: discoveryModel.actions.setPageStart,
  } 
  */
)(Layout(Discovery));

这是一个普通的使用了 redux 的 react 组件的一小部分代码。mapStateToProps 中的 discovery 里所有的 state 都在当前组件的 this.props 里了,不管是用到的或没用到的。 mapDispatchToProps 使用本工具代替了原来的写法。

案例 2

/* import someApi from 'somePackage' */
import {choose} from '@jkt/lose-weight'
import commonModel from "models/commonModel";
import resumeModel from "models/resumeModel";
import positionModel from "models/positionModel";

  class 某茉某 extend 某某 {
    //...
    batchAllCheck = e => {
      // setUpdateState 出处也许要逐一查看引入的文件才能明确
      let { positionLists, setUpdateState } = this.props;
      let { checked } = e.target;
      positionLists.list.map(item => {
        item.checked = checked;
        return item;
      });
      
      setUpdateState({
        filed: "positionLists",
        value: positionLists
      });
    };
    //...
  }
 
export default connect(
  ({ position, user }) => {
    return {
      ...position,
      userInfo: user.userInfo,
      complate: user.complate
    };
  },
  // mapDispatchToProps
  { ...commonModel.actions, ...resumeModel.actions, ...positionModel.actions }

  // 我使用的写法
  /*
  {
    setUpdateState: commonModel.actions.setUpdateState,
    positionLists: positionModel.actions.positionLists,
    resumeComplate: resumeModel.actions.resumeComplate,
    // 其他 dispatch
  }
  */

  // 用本工具不是不可以
  // 明确 dispatch 来自哪里
  /*
  {
    ...choose('setUpdateState').from(commonModel.actions),
    ...choose('positionLists').from(positionModel.actions),
    ...choose('resumeComplate').from(resumeModel.actions),
    // 其他 dispatch
  }
  */

  // 也可以不明确 dispatch 来自哪里
  /*
  choose(
    'setUpdateState',
    'positionLists',
    'resumeComplate'
  ).from({
    ...commonModel.actions,
    ...positionModel.actions,
    ...resumeModel.actions,
    // 其他 dispatch 的来源
  })
  */
)(Layout(Position));

这还是一个普通的使用了 redux 的 react 组件的一小部分代码。mapDispatchToProps 里这么多 dispatchthis.props 里?我敢打赌大多数并没用到。代码中来一个 setUpdateState(注释中的代码 class 某某某 里面),也许是在 commonModel.actions 里,我不确定,因为这个代码不是我写的:disappointed_relieved:,这里当然可以使用本工具,但是建议权衡后按需使用本工具!

案例 3


<template>
  <div>
    <!-- 略 -->
    <div id="insurance-pane" class="plr30">
      <!-- 略 -->
      <div class="data-table">
        <el-table :data="insurance.list">
          <el-table-column
            fixed
            prop="name"
            label="姓名"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="jobNumber"
            label="工号"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="mobile"
            label="手机号"
            :min-width="130"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="gender"
            label="性别"
            :formatter="sexfmt">
          </el-table-column>
          <el-table-column
            prop="deptName"
            label="部门"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="position"
            label="职位"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="staffStatus"
            label="员工状态"
            :formatter="stafffmt"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="dateOfEntry"
            label="入职日期"
            :formatter="datefmt"
            :min-width="120"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column
            prop="insuredProvince"
            label="社保城市"
            :min-width="100"
            show-overflow-tooltip>
          </el-table-column>
          <el-table-column label="操作" fixed="right">
            <!-- 操作略 -->
          </el-table-column>
        </el-table>
      </div>
      <!-- 分页略 -->
      <!-- 组件略 -->
    </div>
  </div>
</template>
<script>
/* import someApi from 'somePackage' */
import {choose, assist} from '@jkt/lose-weight'
import moment from 'moment'

export default {
  data() {
    return {
      /* 数据略 */
    }
  },
  methods: {
    // 不再需要
    sexfmt(r, c) {
      // procedure
    },
    // 不再需要
    stafffmt(r, c) {
      // procedure
    },
    // 不再需要
    datefmt(r, c) {
      // procedure
    },
    query(options) {
      this.$http.post('/path/to/data', {...parameters})
        .then(res => {
          res = res.body;
          if(res.code == 200) {
            // this.insurance.list = res.result.list || [];
            // 在这里使用本工具
            this.insurance.list = choose(
              'name',
              'jobNumber',
              'mobile',
              [
                'gender', 
                // 后续会有 API 说明
                assist(
                  function(性别字段选项, value) {
                    return newValue // 用性别字段选项处理过的 value
                  },
                  undefined, // 这里按需提供 this
                  性别字段选项 // choose 调用前准备好
                )
              ],
              'deptName',
              'position',
              [
                'staffStatus',
                function(员工状态选项, value) {
                  return newValue // 用员工状态选项处理过的 value
                }.bind(
                  this, /* 组件实例作为 this */
                  员工状态选项/* choose 调用前准备好 */
                )
              ],
              [
                'dateOfEntry',
                function(moment, value) {
                  return newValue // 用 moment 处理过的 value
                }.bind(
                  this, /* 组件实例作为 this */
                  moment/* choose 调用前准备好 */
                )
              ],
              'insuredProvince'
            ).from(res.result.list || [])
            
            // 其他操作
          }
        })
        .catch(err => {
          console.log(err.status, err.statusText);
        });
    },
    // 其他各种方法
  },
  mounted() {
    // procedure
  },
  components: {
    /* 组件略 */
  }
}
</script>
<style scoped lang="scss">/* 省略 */</style>

这是一个普通的 vue 组件,使用了 element-ui,有 3 个字段需要格式化,分别是 genderstaffStatusdateOfEntry,格式化函数定义在组件的 methods 中。可以使用本工具把字段解构和格式化放在一起,参看上例 query 中的调用 choose(/* some keys */).from(/* source */),这样就不再需要 el-table-columnmethods 中分别出现 :formatter="***fmt"***fmt

API

:sparkles: 灵感源于必应词典 choose 词条中的例句 We have to choose a new manager from a shortlist of five candidates.

调用语法

辅助词汇表

  • 字段名:key, key2, key3, ...
  • 新字段名(用于替换旧有字段名):nweKey, newKey2, newKey3, ...
  • 字段值:value, value2, value3, ...
  • 新的字段值(字段值被加工后得到的值):newValue, newValue2, newValue3, ...
  • 函数内部过程:procedure
  • 参数:parameters
  • this 参数:thisArg
  • 字段选项:option, option2, option3, ...
  • 工具:tool, tool2, tool3, ...

调用示例

const result1 = choose(
  'key', 
  ['key2', 'newKey2'], 
  [
    'key3', 
    function(value3) {
      /*
        procedure
      */
      return newValue3
    } 
  ],
  [
    'key4', 
    function(value4) {
      /*
        procedure
      */
      return newValue4
    },
    'newKey4'
  ],
  [
    'key5', 
    assist(
      function(option, option2, tool, tool2, value5) {
        /* 
          this.property
          this.method
          procedure; 
        */
        return newValue5
      },
      thisArg,
      option,
      option2,
      tool,
      tool2
    )
  ],
  [
    'key6', 
    // 也可以
    function(option, tool, value6) {
      /* 
        this.property
        this.method
        procedure; 
       */
      return newValue6
    }.bind(
      thisArg,
      option,
      tool
    ), 
    'newKey6'
  ]
).from([
  {key: 'value', key2: 'value2', key3: 'value3', key5: 'value5'}, 
  {key: 'value__', key2: 'value22', key4: 'value4', key6: 'value6'}
])

// 或者
const result2 = choose(
  'key',
  'key3' 
).from({
  key: 'value', 
  key2: 'value2', 
  key3: function(parameters) {
    /* procedure */
    return anything
  }
})

函数 choose 参数

必选!可接受参数个数不限,单个参数类型为 String 或 Array 或 Number(在工具内部转换成字符串处理)。

如果类型是 Array:

  • 第 1 项:必选!类型为 String 或 Number(在工具内部转换成字符串处理);
  • 第 2 项:必选!类型为 String 或 Function 或 Number(在工具内部转换成字符串处理);
    • 如果类型是 Function,该函数接受 1 个参数,该参数是对应字段的值。并期待本工具的用户返回一个加工后的值。如果在加工过程中需要注入更多的参数(如:字段选项或格式化工具)和绑定 this,请参考后续 辅助函数 assist 的说明或直接使用 Function.prototype.bind api。
  • 第 3 项:可选!类型为 String 或 Number(在工具内部转换成字符串处理)。

函数 choose 返回值

一个带有 from 方法的对象。

方法 from 参数

必选!可接受 1 个参数!类型为 Array 或 Object。

  • 如果类型是 Array,其中的各项会被当作 Object 类型来处理。

方法 from 返回值

类型和其接受的的参数类型对应。

辅助函数 assist 参数

  • 第 1 个参数:必选!类型为 Function。否则 assist 会返回一个空函数,其中 this 和 parameters 都没有定义。但不会报错!注入该函数的参数依赖于第 3 个参数及后续参数;
    • 如果第 3 个参数及其后续参数存在,那么他们会按序注入到第 1 个函数参数的参数列表中。
  • 第 2 个:可选!this 参数,类型一般为 Object,需要时,明确指定;
  • 第 3 个及后续参数:可选!按需传递,通常是字段选项,字段加工工具(如:moment)。

辅助函数 assist 返回值

类型为 Function,该函数在调用时可按需注入参数,那些参数会按序排列在 assist 第 1 个函数参数的参数列表(如果存在辅助函数 assist 第 3 个参数及后续参数的话)之后(等同于使用 Function.prototype.bind api 返回的结果)

:heavy_exclamation_mark: 辅助函数 assist 是个可选使用的函数。在工具内部大量使用,其原理和实现即 Function.prototype.bind

参与贡献

不写代码

  • 报告 api 使用问题或 bug;
  • 报告文档中语病,用词不当,示例错误,描述不详等问题;
  • 改进建议或新需求提议(需要讨论和决议)。

通过源代码仓库的 issue 来提交。

写代码

  • 修复 api 使用问题或 bug;
  • 修缮文档;
  • 实现改进建议或新需求提议。

代码要求

  • 单个缩进必须是 2 个空格;
  • 标识符采用驼峰式命名;
  • 必须尽可能的“望文生义”;
  • 除了内建对象,标准对象,以及利用柯里化(currying)机制,禁止跨作用域变量查询。

欢迎大家发送 issue 和 pull request :clap::thumbsup:

:raising_hand: 任何与贡献要求有冲突的地方,可以发 issue 讨论!

更新概要

  • 2.0.0 新版本确定
  • 2.0.0-beta.2 修缮文档中版本号文案
  • 2.0.0-beta.1 通过初步的测试
  • 2.0.0-alpha.5 安装后说明版本差异,提供不同版本的文档
  • 2.0.0-alpha.4 更正安装说明
  • 2.0.0-alpha.3 修缮文档,更正版本信息
  • 2.0.0-alpha.2 修缮文档,更正安装说明
  • 2.0.0-alpha.1 相比 1.x,提供更简单的 api,被处理数据除了支持原有的 Array 类型,新增 Object 类型支持,新增字段重命名支持,提供更简单的字段选项和工具注入方式