如何写好javascript(上) | 青训营笔记

91 阅读4分钟

这是我参与「第四届青训营 」笔记创作活动的的第3天,今天开始学习和巩固前端开发中javascript部分的内容和知识。

如何写好JS

各司其职

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

问题

在讲解这个模块的时候老师提出了一个例子:使用按钮控制网页的白天和夜间模式。
首先老师讲解了最简单也是最容易想到的方法:使用addEventListener监听点击事件,判断按钮的变化从而实现对网页样式的切换。

<main>
  <h1>页面颜色模式切换&emsp;<input type="button" value="☀️"></h1>
  <p>如何写好JS代码:各司其职、组件封装、过程抽象</p>
</main>
let main=document.querySelector("main");
document.querySelector("input[type=button]").addEventListener("click",(e)=>{
  if(e.target.value=="☀️"){
    main.style.backgroundColor="black";
    main.style.color="white";
    e.target.value="🌙";
  }
  else{
    main.style.backgroundColor="white";
    main.style.color="black";
    e.target.value="☀️";
  }
}) 

以上代码虽然看着很长,但是含有一些重复代码,所以很容易看懂,但是其中大量的使用JS代码对CSS的样式进行修改,这样在我们项目拥有其他需求的时候需要修改很多代码,不便于后续的维护。

改进

为了提升代码的可维护性,我们可以使用class属性来进行CSS样式的变动,而JS代码只需要修改响应DOM节点的class属性便可以满足需求。

.daylight{
  color:black;
  background-color: white;
}
.night{
  color:white;
  background-color: black;
}
let main=document.querySelector("main");
document.querySelector("input[type=button]").addEventListener("click",(e)=>{
  if(main.className=="daylight"){
    main.className="night";
    e.target.value="🌙";
  }
  else{
    main.className="daylight";
    e.target.value="☀️";
  }
})

此次修改我们通过修改DOM节点的class属性来替代使用JS代码直接对DOM节点的css样式进行操作,相较于上一个方案,此处更加地简洁明了,在有其他需求的时候也更加地便于维护。

再次改进

虽然上个方案既满足了需求也变得更加便于维护,但是还是拥有更加简洁明了的方案。

<input type="checkbox" id="check">
<main class="daylight">
  <h1>
    页面颜色模式切换&emsp;
    <label for="check"></label>
  </h1>
  <p>如何写好JS代码:各司其职、组件封装、过程抽象</p>
</main>
input[type=checkbox]{
  display: none;
}
input+main{
  color: black;
  background-color: white;
}
input+main label::after{
  content: "☀️";
}
input:checked+main{
  color: white;
  background-color: black;
}
input:checked+main label::after{
  content: "🌙";
}

第二次改进后的页面抛弃了JS代码,所有的操作均由css完成。首先我们使用label+checkbox替换之前的button,用checkbox的勾选状态判断两个模式的切换,在隐藏了checkbox的同时,通过labelfor属性对checkbox进行绑定,保证可以在不显示checkbox的情况下也能修改点击状态。之后我们通过input的伪类:checked判断状态,再使用兄弟元素选择器来修改不同勾选状态下页面的样式。最后对于按钮的展示方面使用label的伪元素::after来实现(::before也可),通过修改伪元素中的值来达到修改按钮显示的效果。

组件封装

  • 什么是组件?
    组件是从Web页面上提取出的一个或多个包含HTML模板、CSS样式和JS功能的单元。
  • 组件设计的原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构:插件化、模板化、抽象化(组件框架)

过程抽象

  • 什么是过程抽象?
    过程抽象是用来处理局部细节控制的一些方法;它是函数式编程思想的基础应用。
  • 高阶函数HOF
    • 以函数作为参数
    • 以函数作为返回值
    • 常用于作为函数装饰器
  • 声明式和命令式

声明式和命令式示例

当我们使用一个按钮切换状态时,可以使用声明式和命令式编程两种方式进行。

  <button class="off">off</button>
.on{
  background-color: green;
}
.off{
  background-color: red;
}

命令式

let btn=document.querySelector("button");
btn.onclick=function(e){
  e.target.className=e.target.className=="on"?"off":"on";
  e.target.innerHTML=e.target.className;
}

在使用命令式编程的时候,我们直接使用代码对按钮的状态进行判断和切换。

声明式

function toggle(...actions){
  return function(...args){
    let action=actions.shift();
    actions.push(action);
    return action.apply(this,args);
  }
}
let btn=document.querySelector("button");
btn.onclick=toggle(
  e=>{
    e.target.className="off"
    e.target.innerHTML="off"
  },
  e=>{
    e.target.className="on"
    e.target.innerHTML="on"
  }
);

在使用声明式编程的时候,我们先编写了一个高阶函数toggle(),这个函数接收我们传入的两个操作函数作为参数,然后将另一个函数作为返回值,返回的函数将actions中的第一个操作轮替到最后一个实现操作的切换,这个函数返回actions中当前需要操作的函数给DOM节点的onclick事件实现切换。

小结

这一篇笔记仅记录了部分今日应学习的内容,其中高阶函数的使用是我几乎没有接触过的领域,以至于最后的声明式编程我通过多次调试的方式思考了很久才明白其工作原理,但也说明了这次的学习也是很有收获的,后面也一定会有很多新的内容来考验我,只有迎难直上才能真正学到更多东西。