js深入学习

1.for和forEach遍历

在真实的开发中,for 循环和 forEach 各有优缺点,选择哪一种取决于具体的使用场景。以下是两者的比较:

1. forEach:简洁、适合不可中断的遍历

  • 优点

    1. 简洁易读:代码更简洁,特别适合对数组、NodeList 等可迭代对象的遍历。

    2. 避免手动处理索引:forEach 直接传递当前元素和索引,省去了手动处理计数器的麻烦。

  • 缺点

    • 无法中途退出:forEach 无法通过 breakreturn 来中途退出循环,除非抛出异常。

    • 可能不适合性能关键的代码:forEach 虽然易读,但在某些性能要求非常高的场景中,for 可能更高效。

适用场景

  • 遍历时不需要中途退出。

  • 不关心性能上的微小差异。

  • 代码可读性高于性能优先的场景。

2. for:灵活、适合复杂场景

  • 优点

    • 更灵活:可以完全控制循环的条件、步长等,支持 breakcontinue 等控制流操作。

    • 更适合性能要求高的场景:在处理大量数据时,for 循环可能比 forEach 更高效,特别是在需要频繁操作数组索引的场景。

    • 可以根据需求从某个索引开始、倒序循环等,控制力更强。

  • 缺点

    • 相对繁琐:相比 forEach,需要手动维护循环变量、步进操作,增加了代码的复杂性。

适用场景

  • 需要中途退出循环的场景(例如找到一个匹配的值后停止)。

  • 性能关键的场景,或对性能优化有更高要求时。

  • 需要对数组的索引进行更多控制或使用复杂逻辑。

总结

  • 日常开发中forEach 更加简洁和易读,适合绝大多数场景。

  • 特殊需求或性能关键场景:如果需要控制循环的中断、倒序或复杂的条件判断,for 循环会更合适。

2.currentTargettarget

1. target

  • 定义: target 是触发事件的元素,也就是用户实际点击或触发事件的那个元素。

  • 特性: 即使事件在冒泡过程中被父级元素捕获,target 依然指向最初触发事件的子元素

2. currentTarget

  • 定义: currentTarget 是事件处理程序绑定的元素,指的是当前处理事件的那个元素。

  • 特性: 无论事件是在哪里触发的,currentTarget 都指向绑定了当前事件处理程序的元素。

<div id="parent">
  <button id="child">点击我</button>
</div>

<script>
  const parent = document.querySelector('#parent');
  
  parent.addEventListener('click', (event) => {
    console.log('target:', event.target);           // 输出:<button id="child">
    console.log('currentTarget:', event.currentTarget); // 输出:<div id="parent">
  });
</script>

3.Axios

1. 安装 Axios

如果你在项目中使用 npm,可以通过以下命令安装 Axios:

npm install axios

2. 导入 Axios

在你的 JavaScript 文件中导入 Axios:

import axios from 'axios';

3. 发送 GET 请求

发送 GET 请求来获取数据:

axios.get('https://api.example.com/data')
  .then(response => {
    console.log(response.data); // 处理成功的响应数据
  })
  .catch(error => {
    console.error('Error fetching data:', error); // 处理错误
  });

4. 发送 POST 请求

发送 POST 请求来提交数据:

axios.post('https://api.example.com/data', {
    name: 'John Doe',
    age: 30
  })
  .then(response => {
    console.log('Data submitted successfully:', response.data);
  })
  .catch(error => {
    console.error('Error submitting data:', error);
  });

5. 设置请求头

可以设置自定义请求头,例如发送 JSON 数据:

axios.post('https://api.example.com/data', {
    name: 'John Doe',
    age: 30
  }, {
    headers: {
      'Content-Type': 'application/json'
    }
  })
  .then(response => {
    console.log('Data submitted successfully:', response.data);
  })
  .catch(error => {
    console.error('Error submitting data:', error);
  });

6. 使用 async/await

使用 async/await 使代码更简洁:

async function fetchData() {
  try {
    const response = await axios.get('https://api.example.com/data');
    console.log(response.data);
  } catch (error) {
    console.error('Error fetching data:', error);
  }
}

fetchData();

7. 处理请求和响应拦截器

可以在请求发送之前或响应到达之前进行拦截处理:

axios.interceptors.request.use(config => {
  // 在请求发送之前做些什么
  console.log('Request sent:', config);
  return config;
}, error => {
  // 处理请求错误
  return Promise.reject(error);
});

axios.interceptors.response.use(response => {
  // 处理响应数据
  console.log('Response received:', response);
  return response;
}, error => {
  // 处理响应错误
  return Promise.reject(error);
});

8. 取消请求

可以使用 Axios 的取消令牌来取消请求:

const CancelToken = axios.CancelToken;
let cancel;

axios.get('https://api.example.com/data', {
    cancelToken: new CancelToken(function executor(c) {
      cancel = c;
    })
  })
  .then(response => {
    console.log(response.data);
  })
  .catch(error => {
    if (axios.isCancel(error)) {
      console.log('Request canceled:', error.message);
    } else {
      console.error('Error fetching data:', error);
    }
  });

// 取消请求
cancel('Operation canceled by the user.');

9. 并发请求

可以使用 axios.allaxios.spread 来处理并发请求:

axios.all([
    axios.get('https://api.example.com/data1'),
    axios.get('https://api.example.com/data2')
  ])
  .then(axios.spread((response1, response2) => {
    console.log('Data from first request:', response1.data);
    console.log('Data from second request:', response2.data);
  }))
  .catch(error => {
    console.error('Error with concurrent requests:', error);
  });

4.异步编程

1. 回调函数(Callback)

回调函数是将一个函数作为参数传递给另一个函数,当任务完成后调用这个回调函数。

例子

function fetchData(callback) {
    setTimeout(() => {
        console.log("数据已获取");
        callback("这是数据");
    }, 1000);  // 模拟1秒后获取数据
}

fetchData((data) => {
    console.log("回调函数处理数据: " + data);
});

解释

  • setTimeout 模拟一个异步操作(如获取数据)。

  • 当数据获取完成后,回调函数被调用,传递数据并执行。

2. Promises

Promise 对象表示异步操作的最终完成(或失败)及其结果的值。它可以链式处理,避免 "回调地狱"。

例子

function fetchData() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const success = true;  // 模拟成功或失败
            if (success) {
                resolve("成功获取数据");
            } else {
                reject("数据获取失败");
            }
        }, 1000);
    });
}

fetchData()
    .then(data => console.log("Promise 成功: " + data))
    .catch(error => console.log("Promise 失败: " + error));

解释

  • resolve 表示操作成功并返回数据,reject 表示操作失败。

  • 使用 .then() 处理成功,.catch() 处理失败。

3. async/await

async/await 是基于 Promise 的语法糖,使异步代码更像同步代码,易于阅读和理解。

例子

function fetchData() {
    return new Promise((resolve) => {
        setTimeout(() => {
            resolve("成功获取数据");
        }, 1000);
    });
}

async function getData() {
    try {
        const data = await fetchData();
        console.log("Async/Await 获取数据: " + data);
    } catch (error) {
        console.log("Async/Await 出错: " + error);
    }
}

getData();

解释

  • async 函数返回一个 Promise

  • await 会暂停代码执行,直到 Promise 完成后继续,简化了 .then() 的链式调用。

5.express框架

Express 和 Node.js 的对比与优点:

  1. 更简化的路由管理

    • 在纯 Node.js 中,你需要手动处理路由,并解析请求 URL 和 HTTP 方法。而 Express 通过简单的路由定义方法,如 app.get()app.post() 等,让路由更加直观易读。

    Node.js 原生路由

    const http = require('http');
    
    http.createServer((req, res) => {
        if (req.url === '/' && req.method === 'GET') {
            res.writeHead(200, { 'Content-Type': 'text/plain' });
            res.end('Home Page');
        } else if (req.url === '/about' && req.method === 'GET') {
            res.writeHead(200, { 'Content-Type': 'text/plain' });
            res.end('About Page');
        }
    }).listen(3000);
    

    Express 路由

    const express = require('express');
    const app = express();
    
    app.get('/', (req, res) => {
        res.send('Home Page');
    });
    
    app.get('/about', (req, res) => {
        res.send('About Page');
    });
    
    app.listen(3000);
    

    优点:Express 路由更简洁、结构化,易于维护。

  2. 内置中间件支持

    • Express 提供丰富的中间件支持,用于处理请求体(如 express.json())、静态文件、日志记录等。

    • 在 Node.js 中,处理这些任务需要手动编写代码或依赖多个库,而 Express 提供了现成的中间件,减少重复工作。

    Express 中处理 JSON 请求

    app.use(express.json());
    
    app.post('/data', (req, res) => {
        console.log(req.body);  // 自动解析 JSON
        res.send('Data received');
    });
    

    优点:Express 中间件让处理常见任务变得非常简单。

  3. 简化的错误处理

    • 在 Node.js 中,处理错误通常需要在每个请求和响应处理程序中编写额外的逻辑。而 Express 提供了一个统一的错误处理中间件,使处理和捕获错误更加高效。

    Express 错误处理中间件

    app.use((err, req, res, next) => {
        console.error(err.stack);
        res.status(500).send('Something broke!');
    });
    

    优点:集中式的错误处理让代码更整洁。

  4. 模块化开发

    • Express 强调模块化开发,可以轻松地将路由和中间件拆分为独立的模块。这使得代码结构更清晰,适合构建大型应用。

    Node.js 模块管理较为原始,需要自己构建架构,Express 提供的 Router 模块可以让你轻松拆分路由逻辑:

    const router = express.Router();
    
    router.get('/users', (req, res) => {
        res.send('User list');
    });
    
    module.exports = router;
  • Express 提供了基于 Node.js 的开发框架,让你更加专注于应用的业务逻辑,而不用处理底层的繁琐任务。其优点包括简化路由管理、内置中间件支持、集中的错误处理以及更模块化的开发模式。相比之下,使用纯 Node.js 开发会更加繁琐,尤其是在处理复杂的 HTTP 服务器或 API 时。


js深入学习
http://localhost:8090//archives/jsxue-xi
作者
潘显镇
发布于
2024年10月21日
许可协议