编码原则 —— 各司其责
让HTML、CSS、和JS职能分离
示例 —— 深夜食堂
要求:点击按钮切换文字、和背景至黑夜模式
版本一:
const btn = document.getElementById('modeBtn')
btn.addEventListener('click', (e) => {
const body = document.body
if(e.target.innerHTML === 'sun.jpg') {
body.style.backgroundColor = 'black';
body.style.color = 'white';
e.target.innerHTML = 'moon.jpg';
} else {
body.style.backgroundColor = 'white';
body.style.color = 'black';
e.target.innerHTML = 'sun.jpg';
}
});
/* 用JS做了一些CSS的工作 */
版本二:
const btn = document.getElementById('modeBtn')
btn.addEventListener('click', (e) => {
const body = document.body
if(body.className !== 'night') {
body.className = 'night';
} else {
body.className = '';
}
});
版本三:
#modeCheckBox {
display: none;
}
#modeCheckBox:checked + .content {
background-color: black;
color: white;
transition: all 1s;
}
/* 这里几乎是只有样式更改,可以只使用CSS实现 */
结论
- HTML/CSS/JS各司其责
- 应当避免不必要的由JS直接操作样式
- 可以用class来表示状态
- 纯展示类交互寻求零JS方案
编码原则 —— 组件封装
好的UI组件具备正确性、拓展性、复用性
实现轮播图
结构:HTML
轮播图是一个典型的列表结构,可以使用无序列表<ul></ul>来实现
表现:CSS
- 使用CSS绝对定位将图片重叠在同一个位置
- 轮播图切换的状态使用修饰符(modifier)
- 轮播图的切换动画使用CSS transition
行为:JS
API
- Slider
- +getSelectedItem( )
- +getSelectedItemIndex( )
- +slideTo( )
- +slideNext( )
- +slidePrevious( )
控制流
- 使用自定义事件来解耦
基本方法
- 结构设计
- 展现效果
- 行为设计
- API (功能)
- Event (控制流)
重构:插件化
- 将控制元素抽取成插件
- 插件与组件之间通过依赖注入方式建立联系
registerPlugins(...plugins) {
plugins.forEach(plugin => plugin(this));
}
重构:模板化
将HTML模板化,更加易于拓展
抽象化(组件框架)
- 将组件通用模型抽象出来
总结
- 组件设计的原则:封装性、正确性、扩展性、复用性
- 实现组件的步骤:结构设计、展现效果、行为设计
- 三次重构
- 插件化
- 模板化
- 抽象化 (组件框架)
编码原则 —— 过程抽象
应用函数式编程思想
过程抽象:
- 用来处理局部细节控制的一些方法
- 函数式编程思想的基础应用
高阶函数
为了能够让只执行一次的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象。
高阶函数(HOF)可以实现我们过程抽象的目标:
- 以函数为参数
- 以函数为返回值
- 常用于作为函数装饰器
function once(fn) {
return function(...args) {
if(fn) {
const ret = fn.apply(this, args);
fn = null;
return ret;
}
}
}
// 一个用于实现让某函数只执行一次的高阶函数
function HOF0(fn) {
return fn.apply(this, args);
}
// 一个等价高阶函数
常用高阶函数
HOF
- Once
- Throttle // 节流函数
function throttle(fn, time = 500) { let timer; return function(...args) { if (timer == null) { fn.apply(this, args); timer = setTimeout(() => { timer = null }, time) } } } // 实现五百毫秒才能调用一次 - Debounce
function debounce(fn,dur){ dur = dur || 100; var timer; return function() { clearTimeout(timer); timer = setTimeout(() => { fn.apply(this, arguments): }, dur); } } - Consumer / 2
- Iterative
function iterative(fn) { return function(subject, ...rest) { if(isIterable(subject)) { const ret = []; for(let obj of subject) { ret.push(fn.apply(this, [obj, ...rest])); } return ret; } return fn.apply(this, [subject, ...rest]); } }
编程范式
命令式与声明式
命令式:怎么做
声明式:做什么
总结
- 过程抽象 / HOF / 装饰器
- 命令式 / 声明式
质量优化
- 根据实际情况来评估代码
- 用算法思维来优化代码
总结
今天的内容是如何写好JavaScript,主要介绍了前端项目中需要注意的三个原则——各司其责、组件封装、过程抽象等三个原则和如何提高代码的质量。