JavaScript|笔记

65 阅读8分钟

JavaScript

七个基本类型

  • String

  • Number

  • Boolean

  • Null

  • Undefined

  • Symbol

  • Object

    • Array
    • Function

基本语法特点

let a = 7 + "2";

let:关键字

a:定义的变量名

=:操作符

对象

var user = {
    name:"张三";
    yearOfBirth:1998;
    calculateAge:function(){
    
    }
}

name:key

"张三":value

function(){}:方法

如何写好JavaScript

写好JS的原则

各司其职:HTML,CSS,JS职能分离
  • HTML/CSS/JS各司其责

  • 应当避免不必要的由JS直接操作样式

  • 可以用class来表示状态

  • 纯展示类交互寻求零 JS方案

    • 版本一:JS直接修改了CSS代码

      const btn = document.getElementById('modeBtn');
      btn.addEventListener('click', (e) => {
          const body = document.body;
          if(e.target.innerHTML==='太阳'){
              body.style.backgroundColor = 'black';
              body.style.color = 'white';
              e.target.innerHTML = '月亮';
          } else {
              body.style.backgroundColor = 'white';
              body.style.color = 'black';
              e.target.innerHTML = '太阳';
          }
      });
      
    • 版本二:各司其职且代码变简短

      const btn = document.getElementById('modeBtn');
      btn.addEventListener('click', (e) => {
          const body = document.body;
          if(body. className != 'night') {
              body.className = 'night';
          } else {
              body. className = '';
          }
      });
      
    • 版本三:CSS高级用法 只是样式需求不用JS

      <body>
          <input id="modeCheckBox" type="checkbox">
          <div class="content">
              <header>
                  <label id="modeBtn" for="modeCheckBox"></label>//for一个元素
                  <h1>深夜食堂</h1>
              </header>
              <main>
              ......
              </main>
          </div>
      </body>
      
      #modeCheckBox : checked + .content{
          background-color: black;
          color: white;
          transition: all 1s;
      }
      
组件封装:正确性,扩展性,复用性
基本方法
  • 结构设计:HTML

  • 展现效果:CSS

  • 行为设计

    • API(功能)
    • Event(控制流):解耦
改进
  • 重构:组件插件化

    • 解耦:

      • 将控制元素抽取成插件
      • 插件与组件之间通过依赖注入方式建立联系
  • 重构:HTML模板化

    • 解耦:

      • 将HTML模板化,更易于扩展
  • 抽象化(组件框架 )

    • 将组件通用模型抽象出来
过滤抽象:函数式编程
  • 用来处理局部细节控制的一些方法

  • 函数式编程思想的基础应用

  • 高阶函数(HFO)

    • 以函数作为参数

    • 以函数作为返回值

    • 常用于作为函数装饰器

      function HOFO(fn) {
          return function( ... args) {
              return fn.apply(this, args);
          }
      }
      
    • 常用高阶函数:

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

        function once(fn) {
            return function( ... args) {
                if(fn) {
                    const ret = fn.apply(this, args);
                    fn = null;
                    return ret;
                }
            }
        }
        
      • Throttle:节流函数

        function throttle(fn, time=500) {
            let timer;
            return function( ... args) {
                if(timer == null) {
                    fn.apply(this, args);
                    timer = setTimeout(()=>{
                        timer = null;
                    },time)
                }
            }
        }
        
      • 防抖函数

        function debounce(fn, dur) {
            dur = dur || 100;
            let timer;
            return function() {
                clearTimeout(timer);
                //永远只会被调用最后一次
                timer = setTimeout(()=>{
                    fn.apply(this, args);
                },dur)
            }
        }
        
      • consumer:把同步的function变成异步的 延时调用

        function consumer(fn, time) {
            let tasks = [];
            let timer; 
            return function(...args) {
                tasks.push(fn.bind(this, ...args));
                if (timer == null) { 
                    timer = setInterval(() => { 
                        tasks.shift().call(this);
                        if(tasks.length<=0){
                            clearInterval(timer);
                            timer = null;
                        }
                    },time);
                }
            }
        }
        
      • iterative:同时操作多个元素 批量操作

        const isIterative = obj => obj != null && typeof obj[Symbol.iterator] === 'function';
        ​
        function iterative(fn) {
            return function(subject, ...rest) {
                if (isIterative(subject)) { 
                    const ret= [];
                    for(let obj of subject){
                         ret.push(fn.apply(this, [obj, ...rest]));
                    }
                    return ret;
                }
                return fn.apply(this, [subject, ...rest]);
            }
        }
        
    • 为什么要使用高阶函数

      • 抽象和复用:高阶函数允许你抽象出更通用的操作,这些操作可以在不同的上下文中复用。例如,mapfilterreduce 这样的函数都是高阶函数,它们在处理集合或数组时非常有用
      • 代码简洁:高阶函数可以帮助你写出更简洁的代码。你不需要为每个特定的操作编写完整的循环或条件逻辑,而是可以依赖高阶函数来处理这些细节
      • 模块化:高阶函数促进了代码的模块化。你可以将特定的行为封装在函数中,然后在需要时通过高阶函数来组合这些行为
      • 延迟执行:高阶函数可以延迟函数的执行,直到真正需要结果时才调用它们。这在处理异步操作或者需要懒加载的场景中非常有用
      • 参数化行为:高阶函数允许你参数化函数的行为。这意味着你可以根据传入的函数参数来改变函数的行为,从而提供更大的灵活性
    • 是纯函数

      • 什么是纯函数

        • 纯函数是指其返回值仅依赖于其输入参数,且不产生副作用的函数。换句话说,给定相同的输入,纯函数总是返回相同的输出,并且不会对外部状态产生任何影响。

        • 特点:

          1. 确定性:纯函数的输出完全由输入决定,不会受到外部状态或随机因素的影响。
          2. 无副作用:纯函数不会改变外部状态,不会执行任何 I/O 操作(如读取文件、数据库操作、网络请求等),也不会抛出异常。
          3. 可预测性:由于纯函数的输出完全由输入决定,因此它们的行为是可预测的,这使得调试和测试变得更加容易。
          4. 可缓存性:纯函数的输出可以被缓存,因为相同的输入总是产生相同的输出。这意味着如果你多次调用同一个纯函数,你可以存储第一次调用的结果,并在后续调用中返回缓存的结果,从而提高性能。
          5. 并行性:纯函数可以安全地并行执行,因为它们不会相互干扰。这使得它们在多核处理器和分布式系统中非常有用。
      • 多使用纯函数可以增加代码的可维护性

JavaScript拥有命令式和声明式两种编程方式
  • 命令式

    • 面向过程
    • 面向对象
    • 强调怎么做
    • let list = [1, 2, 3, 4];
      let mapl = [];
      for(let i = 0; i < list.length; i++) {
          mapl.push(list[i] * 2);
      }
      
  • 声明式

    • 逻辑式
    • 函数式
    • 强调做什么
    • 具有更强的可拓展性
    • let list = [1, 2, 3, 4];
      const double = x => x * 2;
      list.map(double);
      

代码质量优化

eg.交通灯状态切换:实现多个交通灯状态切换的功能

<!DOCTYPE html>
<html>
<head>
    <link rel="stylesheet" type="text/css" href="./01.css">
</head>
<body>
    <ul id="traffic" class="light">
        <li></li>
        <li></li>
        <li></li>
    </ul>
    <script type="module" src="./01.js"></script>
</body>
</html>
#traffic {
    display: flex;
    flex-direction: column; 
}
​
#traffic li {
    display: inline-block;
    width: 50px;
    height: 50px;
    margin: 10px;
    background-color: gray; 
    border-radius: 50%; 
}
​
/* 等待状态 - 黄色 */
#traffic.wait li:nth-child(1) {
    background-color: yellow;
}
​
/* 停止状态 - 红色 */
#traffic.stop li:nth-child(2) {
    background-color: red;
}
​
/* 通过状态 - 绿色 */
#traffic.pass li:nth-child(3) {
    background-color: green;
}
  • 代码一

    const traffic = document.getElementById('traffic');
    ​
    (function reset() {
        traffic.className = 'wait';
        setTimeout(function() {
            traffic.className = 'stop';
            setTimeout(function() {
                traffic.className = 'pass';
                setTimeout(function() {
                    traffic.className = 'light';
                    setTimeout(reset, 1000);
                }, 3000); 
            }, 3000); 
        }, 1000); 
    })();
    
  • 代码二 数据抽象

    const traffic = document.getElementById('traffic');
    ​
    //将数据抽象出来写成一个状态列表
    const stateList = [    {state: 'wait', last: 1000},    {state: 'stop', last: 3000},    {state: 'pass', last: 3000},//可以在列表里直接添加新的数据];
    ​
    function start(traffic, stateList){
        //递归调用
        function applyState(stateIdx){
            const {state, last} = stateList[stateIdx];
            //设置成当前状态
            traffic.className = state;
            setTimeout(() => {
                applyState((stateIdx +1)% stateList.length);
            }, last)
        }
        applyState(0);
    }
    ​
    start(traffic, stateList);
    
  • 代码三 过程抽象 代码过于复杂 过度抽象

    const traffic = document.getElementById('traffic');
    ​
    //wait方法表示等待时间
    function wait(time){
        return new Promise(resolve => setTimeout(resolve, time));
    }
    ​
    //poll方法表示轮循
    function poll( ... fnList){
        let stateIndex = 0;
    ​
        return async function( ... args){
            let fn = fnList[stateIndex++ % fnList.length];
            return await fn.apply(this, args);
        }
    }
    ​
    //状态方法
    async function setState(state, time){
        traffic.className = state;
        await wait(time);
    }
    ​
    let trafficStatePoll = poll(
        setState.bind(null, 'wait', 1000),
        setState.bind(null, 'stop', 3000),
        setState.bind(null, 'pass', 3000)
    );
    ​
    (async function(){
        while(1){
            await trafficStatePoll();
        }
    })();
    
  • 代码四 异步+函数式

    const traffic = document.getElementById('traffic');
    ​
    function wait(time){
        return new Promise(resolve => setTimeout(resolve, time));
    }
    ​
    function setState(state){
        traffic.className = state;
    }
    ​
    async function start(){
        while(1){
            setState('wait');
            await wait(1000);
            setState('stop');
            await wait(3000);
            setState('pass' );
            await wait(3000);
        }
    }
    ​
    start();
    

洗牌-生成器

const cards = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
​
function draw() {
    const c = [...cards];
    for (let i = c.length; i > 0; i--) {
        const cardIndex = Math.floor(Math.random() * i);
        [c[cardIndex], c[i - 1] = c[i - 1], c[cardIndex]];
        yield c[i - 1]; 
    }
}
​
const result = draw(cards);
console.log([...result]);
console.log(result.next().value);//只取一张牌

HTML in JavaScript

JSX

是一种JavaScript的语法扩展,它允许你在JavaScript代码中编写类似HTML的标记。JSX实际上是React.createElement()函数的语法糖,它使得在React中编写组件更加直观和方便。

基本语法

JSX的基本语法非常接近HTML,但它有一些特殊的规则:

  • JSX必须严格闭合,就像HTML标签一样。
  • 你可以把JSX标签当作变量,在任何地方使用它们,甚至可以将它们赋值给变量或将它们放入数组中。
  • 自定义组件的首字母必须大写,而内置的HTML标签则不需要。

为什么要使用JSX?

使用JSX的理由包括:

  1. UI与JavaScript逻辑的融合:JSX允许你将UI(用户界面)与JavaScript逻辑结合在一起,这使得开发体验更好,尤其是在React中。
  2. 错误和提示:使用JSX可以让React显示更多有用的错误和警告消息,帮助你更有效地调试代码。
  3. 动态内容展示:JSX支持在JSX中嵌入JavaScript表达式,通过大括号{}包裹,这对于动态内容展示非常有用。
  4. 条件渲染:你可以在JSX中使用JavaScript表达式实现条件渲染,例如使用三元运算符或逻辑与&&

在JSX中嵌入表达式

在JSX中,你可以这样嵌入JavaScript表达式:

const name = 'Josh Perez';
const element = <h1>Hello, {name}</h1>;

属性传递

在JSX中传递属性非常简单,支持JavaScript表达式:

const element = <img src="logo.png" alt="Logo" />;
const greeting = <h1>Hello, {user.name}!</h1>;

事件处理

JSX支持直接绑定事件,通过onClickonChange等属性传递事件处理函数:

function handleClick() {
  alert("Button clicked!");
}
const button = <button onClick={handleClick}>Click me</button>;

样式和类名

在JSX中,className用于代替HTML中的class属性。内联样式则使用对象的形式,属性名遵循camelCase规则:

const element = <div className="container">Content</div>;
const style = { color: "blue", fontSize: "20px" };
const element = <h1 style={style}>Styled Text</h1>;

数组渲染

可以通过map()方法遍历数组生成JSX元素列表。在渲染列表时,为每个元素添加key属性,以提高渲染效率:

const items = ["Apple", "Banana", "Cherry"];
const list = (
  <ul>
    {items.map((item, index) => (
      <li key={index}>{item}</li>
    ))}
  </ul>
);

JSX是一种强大的工具,它使得在React中构建用户界面变得更加直观和高效。通过上述信息,你可以了解到JSX的基本用法和一些关键特性。