写好JS的三个原则
- 各司其责
- 组件封装
- 过程抽象
各司其责
不是说要写在三个文件里,而是说负责不同的功能
举例:夜间模式的切换
使用class
将样式的编写放到CSS中,js里只切换类名
零JS方案
也可以只通过html和CSS做到(checkbox + 伪类选择器, 再将checkbox隐藏 display : none;)
组件封装
组件的定义
包含HTML JS CSS 的单元
好的组件具备封装性、正确性、扩展性、复用性
举例:轮播图
实现思路
- 通过绝对定位将图片重叠在一个位置
position: absolute; - 定义不同的CSS选择器,通过改变类名改变样式
- 封装一个selector类,实现切换功能
- 自定义事件实现状态绑定(小圆点和图片对应起来)
const event = new CustomEvent('slide', {bubbles:true, detail})
总结方法
- 结构设计 html
- 展现效果 css
- 行为设计
- API (功能:通过接口操作)
- Event (控制流:自定义事件解耦)
优化
插件化 JS
解耦
- 将控制元素抽取成插件
- 插件和组件之间通过依赖注入方式建立联系
将轮播图下面的小圆点和左边右边的按钮分别写成插件(方法)
模板化 html
每个插件分为render 和action 方法,render负责生成html
再抽象成通用组件
包含constructor register render 方法
过程抽象
概念
不同的事件有同样的执行过程,将这个过程抽象出来
举例:只触发一次的函数(是一个高阶函数)
高阶函数 一个函数return另一个函数,常用作函数装饰器
这里形成了闭包,fn = null 之后,第二次调用会记住 fn 的值
常见应用
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 延时调用
Iterative 可迭代
用一个可迭代对象依次操作多个元素
当函数不是纯函数时,至少可以保证Iterative是纯函数,方便测试
纯函数 输入相同,结果相同 没有副作用,即不改变外部元素的状态
function iterative (fn) {
return function (subject, ...rest) {
if (iteratable(subject)) {
const ret = [];
for (let obj of subject) {
ret.push(fn.apply(this, [obj, ...rest]))
}
return ret;
}
return fn.apply(this, [subject, ...rest]);
}
}
编程范式
命令式与声明式(js兼具两者特点)
- 命令式写法 (强调动作,怎么做)
- 声明式写法 (强调做什么)