这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天
1.javaScript
1.1 如何写好javaScript?
- 各司其职: 让HTML,css和javaScirpt职能分离
- 组件封装: 好的UI组件具备正确性,扩展性,复用性
- 过程抽象:应用函数式编程思想
各司其职
我们在编写代码的时候,应当避免不必要的由js直接操作样式,可以用css的伪类来表示状态,纯展示类交互寻求零基础的js方案
组件封装
我们在编写页面的时候可以将页面上某一个功能单独抽离出来,进行封装(创建一个类,将该组件的行为方法都定义在类中, 之后我们就可以直接用该类绑定指定元素就可以实现该功能),这样不仅仅可以提高代码复用率,也易于维护
-
在组件封装时API设计应该保持原子操作,职责单一,满足灵活性
-
组件封装的基本流程:
- 设计结构
- 设计css
- 设计行为(API功能)Event(控制流)
-
组件优化
- 将控制元素抽取成插件,插件与组件之间通过依赖注入建立联系
- 将HTML模板化
过程抽象
过程抽象就像一个对象,除了有某些属性,它可以抽象成一个固定数据表示,它所拥有的动作(过程)也可以抽象一个对象, 就是我想让这个一个动作, 能让不同对象也能拥有,就可以将其单独抽离出来
例:高阶函数Once, 为了能让”只执行一次“的需求覆盖不同的事件处理,我们就可以将这个过程单独的抽离出来
function once(fn) {
return function (...args) {
if (fn) {
const ret = fn.apply(this, args)
fn = null
return ret
}
}
}
const foo = once(() => {
console.log('bar')
})
// 只打印一次bar
foo()
foo()
foo()
1.2 高阶函数
- 以函数作为参数
- 以函数作为返回值
- 常用作函数装饰器
常用的高阶函数
- 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
为什么使用高阶函数
在我们编写函数时, 输入输出数据全是显式的(函数与外界交互数据的唯一渠道是参数和返回值)我们称它为纯函数, 这样的函数易于维护,非纯函数即为参数的值不用传入,他也会自动变更,这样的函数不易于维护,而使用高阶函数, 可以将非纯函数转变成为一个纯函数,在编写代码时,我们应该尽量减少非纯函数的使用
1.3 编程范式
- 命令式
- 声明式
命令式就像式面向过程编程, 声明式就像是面向对象
例子:
// 命令式
switcher.onclick = function (evt) {
if (evt.target.className === 'on') {
evt.target.className = 'off'
} else {
evt.target.className = 'on'
}
}
// 声明式
function toggle(...actions){
return function(...args){
let action = actions.shift()
actions.push(action)
return action.apply(this, args)
}
}
switcher.onclick = toggle(
evt => evt.target.className = 'off',
evt=>evt.target.className='on'
)
扩展
依赖注入
依赖注入(dependency injection,缩写为 DI)是一种软件设计模式,这种模式能让一个物件接收它所依赖的其他物件