第五届字节跳动青训营 前端进阶学习笔记(二)JavaScript编码规范
文章目录
- 1.前言
- 2.写好JS的一些基本原则
这是我参与「第五届青训营 」伴学笔记创作活动的第 2 天
1.前言
本次课程主要讲解了有关JavaScript编码原则和代码优化的相关问题。
重点内容:
- HTML、CSS、JS各司其责
- 具备正确性、扩展性、复用性的组件封装
- 函数式编程思想
- 代码优化
2.写好JS的一些基本原则
- 各司其责
- 组件封装
- 过程抽象
各司其责
首先,良好的前端代码应该是HTML、CSS和JS三部分代码各司其责的,也就是各自控制各自所负责的部分。主要需要注意以下几点:
- 避免不必要的由JS直接操作CSS
- 使用class来切换样式而不是修改style
- 能单独使用CSS实现的样式,尽量使用CSS,追求纯展示性内容0JS
比如在下面的一个例子中:
我们来实现一个深色模式切换的功能,通常会按照下面这种形式实现 这样当我们点击切换按钮的时候,页面就会切换到深色模式显示。 但是上述代码还存在很强的优化空间,首先,我们可以通过class来优化这一过程,减少DOM的操作次数。此外,我们还能使用纯CSS的方法来实现这一功能。借助label标签和:checked伪类的特性,我们在不借助JS代码的情况下,实现了切换界面深浅主题的功能。
组件封装
组件设计的基本原则:封装性、正确性、扩展性、复用性
下面我们来封装一个轮播图组件
- HTML结构:
- CSS样式:
alt="image.png" />
- JS代码:
首先,构建轮播图组件的基本结构、展现效果和行为。
下一步,我们开始构建轮播图的控件,轮播图控件我们通过自定义事件的方式来控制原点控制的状态切换,以此来与轮播图组件解耦。
这里,我们在Silder的构造函数里,定义控件的方法。并且新增了start和stop方法,用来实现具体的控件行为。
class Slider {
constructor(id, delay=3000) {
this.container = document.querySelector(`#${id}`);
this.sliders = document.querySelectorAll('.slider__item, .slider__item--selected');
this.delay = delay;
const controlContainer = document.querySelector('.slider__control');
if(controlContainer) {
const controls = document.querySelectorAll('.slider__control-item, .slider__control-item--selected');
controlContainer.addEventListener('mouseover', evt=> {
const idx = Array.from(controls).indexOf(evt.target);
if(idx >= 0) {
this.toslider(idx);
this.stop();
}
});
controlContainer.addEventListener('mouseout', evt=> {
this.start();
})
this.container.addEventListener('silde', evt => {
const idx = evt.detail.index;
const selected = document.querySelector('.slider__control-item--selected');
if(selected) {
selected.className = 'slider__control-item';
}
controls[idx].className && (controls[idx].className = 'slider__control-item--selected');
})
}
const pre = document.querySelector('.slider__control--previouse');
if(pre) {
pre.addEventListener('click', evt => {
this.stop();
this.preslider();
this.start();
evt.preventDefault();
})
}
const next = document.querySelector('.slider__control--next');
if(next) {
next.addEventListener('click', evt => {
this.stop();
this.nexslider();
this.start();
evt.preventDefault();
})
}
}
getCurrent() {
const current = document.querySelector('.slider__item--selected');
return current;
}
getCurrentIndex() {
return Array.from(this.sliders).indexOf(this.getCurrent());
}
toslider(idx) {
const current = this.getCurrent();
if(current) {
current.className = 'slider__item';
}
this.sliders[idx] && (this.sliders[idx].className = 'slider__item--selected');
const detail = {
index: idx
};
const event = new CustomEvent('silde', {bubbles: true, detail});
this.container.dispatchEvent(event);
}
preslider() {
const idx = this.getCurrentIndex();
this.toslider((this.sliders.length + idx - 1) % this.sliders.length);
}
nexslider() {
const idx = this.getCurrentIndex();
this.toslider((idx + 1) % this.sliders.length);
}
start() {
this.stop();
this.timer = setInterval(()=>this.nexslider(), this.delay);
}
stop() {
clearInterval(this.timer);
}
}
至此一个基本的轮播图组件就封装完毕了。
在上面的实现过程中,我们在Slider类的构造函数中,定义了各个控件的所有行为,因此各控件的行为和Silder组件是高度耦合的。对此,我们需要将各个控件的行为单独封装为插件,然后通过安装插件的方式,将插件安装在组件上,以此来实现解耦。同时,若日后我们需要增加控件时,只需要添加相应的控件插件就行了。
在此基础上,我们还可以进一步对模板进行封装,即将控件对应的HTML代码也封装进插件中。
这样封装好之后,我们只需要一组HTML标签,就能展示整个轮播图组件了。
过程抽象
过程抽象就是利用函数式编程的思想来处理局部细节控制的一些方法。
-
高阶函数
- 以函数作为参数
- 以函数作为返回值
- 常用于作为函数装饰器
-
常用高阶函数
- Once
- Throttle
- Consumber
- Iterative