跟着月影学 JavaScript | 青训营笔记

59 阅读3分钟

这是我参与「第五届青训营 」伴学笔记创作活动的第 3 天

一、本堂课重点内容:

  • 如何写好JavaScript
    • 各司其责
    • 组件封装
    • 过程抽象
  • 写代码应该关注的要点

二、详细知识点介绍:

2.1 各司其责

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

例子:

  • HTML/CSS/JS各司其责

  • 可以用class 来表示状态

  • 这个例子体现了纯展示类交互寻求零JS方案

2.2 组件封装

组件是指Web页面上抽出来一个个包含模版((HTML)、功能(JS)和样式(CSS)的单元。好的组件具备封装性、正确性、扩展性、复用性。

总结:

  • 组件设计的原则:封装性、正确性、扩展性、复用性
  • 实现组件的步骤:结构设计、展现效果、行为设计
  • 三次重构
    • 插件化
    • 模板化
    • 抽象化(组件框架)

实现的代码

2.3 过程抽象

  • 用来处理局部细节控制的一些方法
  • 函数式编程思想的基础应用

once

  • 为了能够让“只执行一次“的需求覆盖不同的事件处理,我们可以将这个需求剥离出来。这个过程我们称为过程抽象
// 实现once

function once(fn) {
  return function () {
    if (fn) {
      const ret = fn.apply(this, arguments);
      fn = null;
      return ret;
    }
  };
}

button.addEventListener('click', once((evt) => {
  const target = evt.target;
  target.parentNode.className = 'completed';
  setTimeout(() => {
    list.removeChild(target.parentNode);
  }, 2000);
}));


2.4 高阶函数

  • 以函数作为参数
  • 以函数作为返回值
  • 常用于作为函数装饰器

2.5 编程范式

命令式与声明式

  • 命令式
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'
);
  • 三态
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 = 'warn',
  evt => evt.target.className = 'off',
  evt => evt.target.className = 'on'
);

总结

  • 过程抽象/HOF/装饰器
  • 命令式/声明式

三、实践练习例子:

  • 实现交通灯

  • 判断是否是4的幂

  • 洗牌
const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

function shuffle(cards) {
  const c = [...cards];
  for(let i = c.length; i > 0; i--) {
    const pIdx = Math.floor(Math.random() * i);
    [c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
  }
  return c;
}

const result = Array(10).fill(0);

for(let i = 0; i < 10000; i++) {
  const c = shuffle(cards);
  for(let j = 0; j < 10; j++) {
    result[j] += c[j];
  }
}

console.log(shuffle(cards));
console.log(result);

image.png

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];

function * draw(cards){
    const c = [...cards];

  for(let i = c.length; i > 0; i--) {
    const pIdx = Math.floor(Math.random() * i);
    [c[pIdx], c[i - 1]] = [c[i - 1], c[pIdx]];
    yield c[i - 1];
  }
}

const result = draw(cards);
console.log([...result]);
  • 红包生成器

四、课后个人总结:

各司其责指的是HTML/CSS/JS各自负责自己的工作,避免不必要的由JS直接操作样式,可以用class来表示状态,寻求零JS方案来实现纯展示类交互。

组件封装是指将Web页面上的模板(HTML)、功能(JS)和样式(CSS)抽出来作为一个单元来处理。好的组件具备封装性、正确性、扩展性和复用性。

过程抽象是指用来处理局部细节控制的一些方法。这是函数式编程思想的基础应用,可以实现“只执行一次”等需求。