前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何写好JavaScript - 笔记

如何写好JavaScript - 笔记

作者头像
TagBug
发布2023-03-17 10:57:39
5560
发布2023-03-17 10:57:39
举报
文章被收录于专栏:TagBugTagBug

什么是好的 JS 代码:各司其职、组件封装、过程抽象 使用 JS 解决实际问题:如何评价一段代码的好坏、写代码最应关注什么

# 如何写好 JavaScript - 笔记

# 各司其职

我们知道,前端 web 对于 HTML、CSS、JavaScript 的分工都很明确。

HTML 负责页面骨架、CSS 负责页面的渲染、JavaScript 负责页面的行为。

# 一个🌰

对于一个切换页面深色模式切换的需求,如果要用 JS,该怎么实现?

很容易想到:

使用 button,监听点击事件,更改页面背景颜色和文字颜色

代码语言:javascript
复制
const btn = document.getElementById('modeBtn');
btn.addEventListener('click', (e) => {
    const body = document. body ;
    if(e.target.innerHTML === '🌞'){
        body.style.backgroundColor = 'black';
        body.style.color = 'white';
        e.target.innerHTML = '🌜';
    } else {
        body.style.backgroundColor = 'white';
        body.style.color = 'black ';
        e.target.innerHTML = '🌞';
    }
});

但是这个版本的实现语义不清,如果让别人来阅读这段代码,可能一时间不知道是在实现什么功能。

于是,我们想出优化方案:

同样使用 button,监听点击事件,但这次直接修改容器的 class,通过在 css 中写的 class 样式修改页面表现

代码语言:javascript
复制
const btn = document.getElementById('modeBtn');
btn.addEventListener('click', (e) => {
    const body = document. body ;
    if(body.className === 'night'){
        body.className = '';
    } else {
        body.className = 'night';
    }
});

很明显,这个版本已经比上个版本好多了,我们一眼就能看出来这段代码是在做什么。

但实际上,我们还有一种更好的解决方案 —— 只使用 CSS 实现

  • 使用 checkbox + :checked 伪类 + 兄弟元素选择器来实现

那么,实际上来说,表现层的工作就让负责表现层的 CSS 来做才是最好的

总结下来就是以下几点:

  • HTML/CSS/JS 各司其责
  • 应当避免不必要的由 JS 直接操作样式
  • 可以用 class 来表示状态
  • 纯展示类交互寻求零 JS 方案

# 组件封装

组件是指 Web 页面上抽出来一个个包含模版(HTML)、功能 (JS)和样式 (CSS) 的单元。

好的组件具备封装性、正确性、扩展性、复用性。

# 如何实现一个轮播图组件?

HTML 结构设计

代码语言:javascript
复制
<div id="my-slider" class="slider-list">
  <ul>
    <li class="slider-list__item--selected">
      <img src="https://p5.ssl.qhimg.com/t0119c74624763dd070.png"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p4.ssl.qhimg.com/t01adbe3351db853eb3.jpg"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p2.ssl.qhimg.com/t01645cd5ba0c3b60cb.jpg"/>
    </li>
    <li class="slider-list__item">
      <img src="https://p4.ssl.qhimg.com/t01331ac159b58f5478.jpg"/>
    </li>
  </ul>
</div>

CSS 展现效果

代码语言:javascript
复制
#my-slider{
  position: relative;
  width: 790px;
}

.slider-list ul{
  list-style-type:none;
  position: relative;
  padding: 0;
  margin: 0;
}

.slider-list__item,
.slider-list__item--selected{
  position: absolute;
  transition: opacity 1s;
  opacity: 0;
  text-align: center;
}

.slider-list__item--selected{
  transition: opacity 1s;
  opacity: 1;
}

行为设计:API

注意:API 设计应保证原子操作,职责单一,满足灵活性。

image-20220117201004121
image-20220117201004121

行为设计:Event 控制流

使用自定义事件来解耦

代码语言:javascript
复制
<a class="slide-list__next"></a>
<a class="slide-list__previous"></a>
<div class="slide-list__control">
  <span class="slide-list__control-buttons--selected"></span>
  <span class="slide-list__control-buttons"></span>
  <span class="slide-list__control-buttons"></span>
  <span class="slide-list__control-buttons"></span>
</div>

代码语言:javascript
复制
const detail = {index: idx}
const event = new CustomEvent('slide', {bubbles:true, detail})
this.container.dispatchEvent(event)

总的来说,就是要遵循以下基本方法:

  • 结构设计
  • 展现效果
  • 行为设计
    • API(功能)
    • Event(控制流)

# 优化

# 解耦
  • 将控制元素抽取成插件
  • 插件与组件之间通过依赖注入方式建立联系
  • 将 HTML 模板化,更易于扩展
# 抽象
  • 将通用的组件模型抽象出来,形成组件框架

# 过程抽象

# 什么是过程抽象?

  • 用来处理局部细节控制的一些方法
  • 函数式编程思想的基础应用

# 过程抽象有什么好处?

一个🌰:操作次数限制

假如有一个需求,要求对某个函数的调用设置次数限制,我们可以直接在这个函数里面写上限制代码。

但是实际上,这个需求是可以通用的,如果对每一个函数都是有需求时更改内部代码,未免显得有点重复。

所以我们实际上可以通过一个代理函数 (高阶函数),写一个新的函数,接收一个函数参数,对其封装,并返回封装好的新函数,这样我们就完美地实现了这个需求。

代码语言:javascript
复制
function once(fn){
    return (...args) => {
        if(fn){
            fn.apply(this, args);
            fn = null;
        }
    }
}

# 常用高阶函数

  • Function Once:只能执行一次
  • Function Throttle:节流,每隔一段时间可以调用一次
  • Function Debounce:防抖,停下来一段时间后再调用
  • Function Consumer:缓存队列,延迟执行
  • Function Iteraticve:让函数支持批量操作

# 为什么要使用高阶函数?

函数分为两种,纯函数和非纯函数。

纯函数的意思是:任何时候,以相同的参数调用纯函数,输出也是相同的

那么其实非纯函数的意思就是相对的:非纯函数依赖外部环境,当外部环境参数改变时,即使用相同的参数调用,输出也会改变

显而易见,纯函数方便于后期的统一测试,而非纯函数还需要保证外部环境每次要统一(有时很难做到或很麻烦),所以现在更倾向于使用纯函数

代码语言:javascript
复制
// 纯函数
function add(a, b) {
    return a + b;
}
// 非纯函数
let sum = function() {
    let res = 0;
    return (value) => res += value;
}

当使用高阶函数时,由于高阶函数一般都是纯函数,这样的话,由高阶函数封装的函数在测试时,就只需要测试原始函数即可,降低了测试成本

# 编程范式

JavaScript 是一种既可以使用命令式又可以使用声明式的编程语言,例如:

代码语言:javascript
复制
// 命令式
function toggle(event) {
    if(event.target.className === 'on'){
        event.target.className = 'off';
    }else{
        event.target.className = 'on';
    }
}
// 声明式
function toggleBuilder(...actions) {
    return function(...args){
        let action = actions.shift();
        actions.push(action);
        return action.apply(this, args);
    }
}
let toggle = toggleBuilder(
    event => event.target.className = 'off',
    event => event.target.className = 'on'
);

那么我们应该使用什么编程范式呢?

思考这样一个问题,对于状态切换这个需求,如果我们需要调整状态的数量、先后,那么:

  • 对于命令式的 toggle 来说,我们需要直接修改这个函数,当需求频繁变化时,就会即为耗费人力和时间;
  • 而对于声明式的 toggleBuilder 来说,我们只要在构建 toggle 时,调整传入的行为参数即可,既简单又直观。

发现了吗,声明式的函数要优于命令式的函数

但是在实际开发中,到底是使用哪种范式,还需要具体问题具体分析,在两种范式之间选择最适合的,才是最好的

# 使用 JS 解决实际问题

# 如何评价一段代码的好坏

先来看一段代码:

代码语言:javascript
复制
function isUnitMatrix2d(m) {
    return m[0] === 1 && m[1] === 0 && m[2] === 0 && m[3] === 1 && m[4] === 0 && m[5] === 0;
}

这段代码好不好?为什么?

其实有两种观点:

乍一看,对于简洁度和可读性来说,不好,明明可以使用更优雅的迭代来解决,却要用这么笨的方法

但是,其实这个函数的效率极高,如果这个函数需要在 requestAnimationFrame 中被高频调用,那么这种写法也不失为一种好的解决方案

# 写代码最应关注什么?

风格 vs 效率

实际上我们应该根据使用场景来判断,对于效率优先的情况下,肯定要先考虑实现的效率问题,而如果多人协作开发和效率问题起冲突,那么我们就要在这两者之间做权衡了

所以其实没有绝对的判断代码好坏的标准,过度的优化、过度的设计难免会让理解成本成倍增加,所以一切都要从实际出发,结合实际考虑

抽象程度越高,可复用性就越高,同时理解成本也会越高

# 参考资料

  • 字节青训营课程
  • MDN 中文文档
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2022-01-172,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • # 如何写好 JavaScript - 笔记
    • # 各司其职
      • # 一个🌰
    • # 组件封装
      • # 如何实现一个轮播图组件?
      • # 优化
    • # 过程抽象
      • # 什么是过程抽象?
      • # 过程抽象有什么好处?
      • # 常用高阶函数
      • # 为什么要使用高阶函数?
      • # 编程范式
    • # 使用 JS 解决实际问题
      • # 如何评价一段代码的好坏
      • # 写代码最应关注什么?
    • # 参考资料
    相关产品与服务
    容器服务
    腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档