专栏首页鱼头的Web海洋『初中级前端必看』谈谈如何更有质量地看源码

『初中级前端必看』谈谈如何更有质量地看源码

  • 作者:陈大鱼头
  • github:KRISACHAN

前言

最近有很多童鞋跟鱼头说,面试的时候动不动就问源码。

也有很多童鞋遇到问题的时候,鱼头建议这些童鞋看相关库 / 框架 / 项目的源码。

但是也有很多童鞋向鱼头抱怨说:“源码太难了。”

那么源码真的是一块难啃的硬骨头吗?

其实不是的。

作为一个优秀(或说合格)的开源项目,它的代码一定不会是晦涩难懂的。不仅是代码本身,这些项目配套的注释,单元测试,示例代码,函数名以及文档一定是能够很好地辅助你读源码的。

下面就让鱼头来跟大家谈谈我自己的一些看源码心得。

(注:这不是最佳实践,只算是鱼头个人的经验,不一定适用于所有人,如果你有不同的意见,欢迎在下方评论区域留言。)

正文

看配套说明

在看一个开源项目源码之前,鱼头首先会先看其文档,不一定是会细致到各个API,但是会先理解这个项目的背景,思想,以及解决的问题是什么。

举个例子,我们来看看一个叫做runtime-hooks的开源工具库。这里先上部分代码:

function withHookAfter (originalFn, hookFn) {
  return function () {
    var output = originalFn.apply(this, arguments)
    hookFn.apply(this, arguments)
    return output
  }
}

这段函数我们是看懂了,就是劫持原函数,并且在原函数执行之后,执行我们自己的逻辑。但是如果没有相关的业务经验,我们不一定能理解为什么这么干,不理解就很容易会忘记。

但是我们可以看看相关文档里,作者对这个库说明的部分节选:

假设有一个被业务广泛使用的函数,我们是否能够在既不更改调用它的业务代码,也不更改该函数源码的前提下,在其执行前后注入一段我们自定义的逻辑呢?

(来源于:基于原型链劫持的前端代码插桩实践)

哦,那么这么说我们就理解了,通过这种方案,当我们需要入侵某个函数的时候,就不需要再进行一些复杂的hack,魔改动作了。

那么我们就理解了这段函数的存在的意义,因为理解,所以这段代码,自然而然的就记住了,以后遇到类似需要的场景也能够轻而易举的想到这个方案。

看类型文件

现在有许多的开源项目都是用 TypeScript 来写的,既然是如此,通常在根目录下都会有一个.d.ts文件专门定义API类型的。

例如我们来看看一个开源的Web IDE库 ace.js

看看它根目录下的ace.d.ts里的部分代码:

export interface EventEmitter {
    once(name: string, callback: Function): void;
    setDefaultHandler(name: string, callback: Function): void;
    removeDefaultHandler(name: string, callback: Function): void;
    on(name: string, callback: Function, capturing?: boolean): void;
    addEventListener(name: string, callback: Function, capturing?: boolean): void;
    off(name: string, callback: Function): void;
    removeListener(name: string, callback: Function): void;
    removeEventListener(name: string, callback: Function): void;
}

通过上面的类型注解,我们很容易就能知道每个API的具体用法。

鱼头我为什么要拿这个来说呢,因为有的时候要解决的问题,可能只是API熟悉的问题,但是有些开源项目的文档写的并不走心,上述的这个就是这样,所以有的时候为了了解一个API,又不想花太多时间去找具体源码位置时,就可以打开类型文件来看看具体的API使用法则。

看注释

在我们深入到某一个具体的函数或者文件时,如果我们能先知道它是干啥的,那么对于我们要理解这段代码来说,是事半功倍的。

举个例子,我们来看看redux。

redux/src/createStore.js的开头有这么一段注释:

Creates a Redux store that holds the state tree. The only way to change the data in the store is to call dispatch() on it. 创建一个保存状态树的Redux仓库。更改仓库中数据的唯一方法是对其调用dispatch()

哦,那么通过上面的注释,我们就知道dispatch方法是用来对数据进行调度的。而且是唯一的一个改变数据的方法。

有意思的是这个文件约300行代码里,估计有100行是注释,那么当我们看完注释之后,即使不看具体实现,也很容易明白它究竟做了什么。

当我们再去看具体实现的时候,我们带着“ 它主要是干了这事 ”的想法去看,那么对具体实现的理解就更轻松了。

看测试样例

除了上述的几个方法,我们还可以看测试样例。其实测试样例,对于我们理解源码,或迅速上手一个陌生项目来说是非常高效的。

例如我们看vuex的vuex/test/unit/store.spec.js里的一个例子:

describe('Store', () => {
  it('committing mutations', () => {
    const store = new Vuex.Store({
      state: {
        a: 1
      },
      mutations: {
        [TEST] (state, n) {
          state.a += n
        }
      }
    })
    store.commit(TEST, 2)
    expect(store.state.a).toBe(3)
  })
  it('dispatching actions, with returned Promise', done => {
    const store = new Vuex.Store({
      state: {
        a: 1
      },
      mutations: {
        [TEST] (state, n) {
          state.a += n
        }
      },
      actions: {
        [TEST] ({ commit }, n) {
          return new Promise(resolve => {
            setTimeout(() => {
              commit(TEST, n)
              resolve()
            }, 0)
          })
        }
      }
    })
    expect(store.state.a).toBe(1)
    store.dispatch(TEST, 2).then(() => {
      expect(store.state.a).toBe(3)
      done()
    })
  })
})

即使是不懂vuex的童鞋,通过上述的两个样例,我们也很容易就理解mutations是同步的,而actions是异步的。甚至依靠着这两个样例,我们也能轻松的上手vuex了。

看官方例子

还有就是官方例子辣,其实鱼头发现很多童鞋,在学一个库/框架的时候,并不喜欢看官方例子,反而喜欢看网上各种教程,虽然看教程不是不好,但是如果本身该库/框架就有官方例子,那么再去找二手知识,就有点本末倒置了。

例如我们看webpack的webpack/examples/typescript

const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin");

module.exports = (env = "development") => ({
 mode: env,
 entry: {
  output: "./index.ts"
 },
 module: {
  rules: [
   {
    test: /\.tsx?$/,
    loader: "ts-loader",
    options: {
     transpileOnly: true
    }
   }
  ]
 },
 resolve: {
  extensions: [".ts", ".js", ".json"]
 },
 plugins: [new ForkTsCheckerWebpackPlugin({ async: env === "production" })]
});

就这样,这是一个可以直接CV的typescript配置,多简单,这样就不需要再去网上找各种不知结果又添加了各种个人理解让你蒙圈的教程了。

本文分享自微信公众号 - 鱼头的Web海洋(krissarea),作者:陈大鱼头

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-12

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 提升开发幸福感的10条JS技巧

    鱼头总结一些能够提高开发效率的JS技巧,这些技巧很实用,觉得挺好,想推荐给大家,所以有了这篇文章。

    陈大鱼头
  • 『1W7字中高级前端面试必知必会』终极版

    如果两个 URL 的 protocol 、 port (如果有指定的话)和 host 都相同的话,则这两个 URL 是同源。

    陈大鱼头
  • 【Hello CSS】第四章-HTML的标签与语意

    上一篇分享了CSS的逻辑属性与盒子模型中分享了一些有关设备屏幕的知识以及浏览器视口的坐标构成。本篇则会分享HTML相关的一些知识。

    陈大鱼头
  • geotrellis使用(七)记录一次惨痛的bug调试经历以及求DEM坡度实践

         眼看就要端午节了,屌丝还在写代码,话说过节也不给轻松,折腾了一天终于解决了一个BUG,并完成了老板安排的求DEM坡度的任务,那么就分两段来表。 一、B...

    魏守峰
  • H3C | 双smart-link组(v7版本)

    网络技术联盟站
  • 优秀的程序员应该具备哪些能力?

    一般包括4个步骤:第一步,明确和理解问题;第二步,拆分和定位问题;第三步,提出解决方案;第四步总结问题。

    杨熹
  • 小程序- SaUi 之添加评分功能

    关于这个评分功能,界面花啦啦的就搞出来了,中途有一大段时间还偏离轨道…导致折腾了好久。最开始,我觉得数据是全部一起过来的,一页显示几条,上一页,下一页的控制都是...

    ss1121
  • 万字长文之 Serverless 实战详细指南

    Serverless = Faas (Function as a service) + Baas (Backend as a service)

    winty
  • C语言七夕必备神器,待那烟花灿烂时,依旧做个单身狗

    缘是美丽的邂逅,爱是心跳的感觉,情是心灵的交会,恋是甜蜜的思念,走在爱与被爱的边缘,你见或者不见,爱你的心始终不改变!C语言诠释爱——为TA写下心中情,生成程序...

    猫咪爱分享
  • 数据堂:大数据产业调研及分析报告(145页)

    大数据文摘

扫码关注云+社区

领取腾讯云代金券