Javascript·深入学习基础知识

代码源码

javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadline = document.getElementById(inputId).value;
    console.log('saveDeadlineFromInput', phone, deadline);
    
    // 更新该客户最新订单的截止日期
    customerMarkers.forEach(marker => {
        const customer = marker.customerData;
        if (customer && customer.customer_phone === phone && customer.orders.length > 0) {
            const latestOrder = customer.orders[0];
            updateOrderDeadline(latestOrder.id, deadline || null)
                .then(() => {
                    latestOrder.followup_deadline = deadline || null;
                    showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
                    // 刷新标记点
                    addCustomerMarkers();
                })
                .catch(e => {
                    showToast('设置失败: ' + e.message, '❌');
                });
        }
    });
}

这段代码的逻辑很清晰,是一个典型的**"前端交互 -> 本地数据更新 -> 后端同步 -> UI 刷新"**的流程。

不过,我在代码里发现了一个潜在的逻辑隐患 ,特别是在处理 customerMarkers 遍历的时候。

🔍 代码分析与优化建议

1. 潜在的 Bug:遍历中修改集合

你正在使用 forEach 遍历 customerMarkers 数组。如果在 addCustomerMarkers() 函数内部(或者它调用的逻辑中)会先清空 customerMarkers 再重新添加,虽然 forEach 通常能跑完,但这是一种不安全的模式。

更安全的做法:

找到目标客户后,直接 break 跳出循环(因为手机号通常是唯一的),或者改用 find 方法。

2. 优化建议:使用 find 代替 forEach

既然你是通过 phone 查找唯一的客户,使用 Array.find() 语义更清晰,且找到后直接操作,避免了不必要的遍历。

3. 优化后的代码
javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadlineInput = document.getElementById(inputId);
    const deadline = deadlineInput ? deadlineInput.value : ''; // 增加空值检查
    console.log('saveDeadlineFromInput', phone, deadline);

    // 1. 查找目标客户标记
    const targetMarker = customerMarkers.find(marker => {
        const customer = marker.customerData;
        return customer && customer.customer_phone === phone && customer.orders.length > 0;
    });

    if (!targetMarker) {
        showToast('未找到该客户或无订单数据', '⚠️');
        return;
    }

    const customer = targetMarker.customerData;
    const latestOrder = customer.orders[0]; // 假设 orders 已按时间排序

    // 2. 乐观更新 UI (可选:为了让界面反应更快,可以先改本地数据)
    // 注意:如果后端更新失败,这里需要回滚,或者等成功后再改
    // 这里我们保持你的逻辑:等后端成功后再更新本地数据

    // 3. 调用后端更新
    updateOrderDeadline(latestOrder.id, deadline || null)
        .then(() => {
            // 4. 更新本地缓存数据
            latestOrder.followup_deadline = deadline || null;
            
            // 5. 提示用户
            showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
            
            // 6. 刷新地图标记
            // 建议:如果 addCustomerMarkers 会清空数组,确保逻辑安全
            addCustomerMarkers(); 
        })
        .catch(e => {
            console.error(e);
            showToast('设置失败: ' + e.message, '❌');
        });
}

💡 关键点解释

  1. Array.find() vs forEach:

    • find 会在找到第一个匹配项后立即停止遍历,性能稍好,且代码意图更明确(我们在找一个特定的客户)。
    • 避免了在遍历过程中如果发生数组变动可能产生的副作用。
  2. latestOrder 的索引:

    • 代码中使用了 customer.orders[0]。这隐含了一个前提:orders 数组必须是已经按时间倒序排列的(最新的在最前面)。如果后端返回的数据未排序,这里可能会更新错误的订单。
  3. 空值处理:

    • 增加了 deadlineInput 的存在性检查,防止因 ID 错误导致 getElementById 返回 null 从而报错。
  4. UX 体验:

    • 目前的逻辑是**"先请求后端,成功后再刷新 UI"** 。这是一种稳健的做法,保证了数据一致性。如果网络很慢,用户点击后可能感觉没反应,可以考虑在 updateOrderDeadline 调用前加一个"加载中"的状态。

作为 JavaScript 新手,理解这段代码的逻辑非常重要。这段代码主要是在处理**"用户输入 -> 数据更新 -> 界面反馈"**这一整套流程。

为了让你更清楚地理解,我把代码拆解成 5 个关键步骤,逐行详细解析。

📦 1. 函数定义与获取输入

javascript 复制代码
// 保存截止日期(从输入框)
function saveDeadlineFromInput(phone, inputId) {
    const deadline = document.getElementById(inputId).value;
    console.log('saveDeadlineFromInput', phone, deadline);
  • function saveDeadlineFromInput(phone, inputId) :
    • 定义了一个函数,名字叫做 saveDeadlineFromInput。
    • 它接收两个参数 (相当于函数的"食材"):
      • phone: 客户的电话号码,用来查找是谁的订单。
      • inputId: 网页上那个输入框的 ID,用来获取用户输入的时间。
  • document.getElementById(inputId).value :
    • document.getElementById(...): 这是浏览器提供的"魔法",用来在网页上抓取一个元素。
    • .value: 获取那个输入框里用户填写的文字。
  • console.log(...) :
    • 这是一个调试工具。它会在浏览器的"控制台"里打印信息。如果代码没按预期运行,程序员通常会先看这里,确认拿到的数据对不对。

🔍 2. 查找目标客户

javascript 复制代码
    // 更新该客户最新订单的截止日期
    customerMarkers.forEach(marker => {
        const customer = marker.customerData;
        if (customer && customer.customer_phone === phone && customer.orders.length > 0) {
  • customerMarkers :
    • 这是一个数组(列表),里面存了地图上所有客户标记点的数据。
  • .forEach(marker => { ... }) :
    • 这是一个循环指令。意思是:"把 customerMarkers 里的东西一个接一个 拿出来,每个东西都叫 marker,然后对每个 marker 执行大括号里的代码"。
  • if (customer && ...) :
    • 这是一个过滤器 。我们在循环中必须确认三件事,只有全对才执行后续操作:
      1. customer: 这个标记点确实有客户数据(防止报错)。
      2. customer.customer_phone === phone: 这个客户的电话 等于 我们传入的 phone 参数(确认没找错人)。
      3. customer.orders.length > 0: 这个客户必须有订单(数组长度大于 0),不然没法更新订单。

📝 3. 准备数据

javascript 复制代码
            const latestOrder = customer.orders[0];
  • customer.orders[0] :
    • orders 是一个订单列表(数组)。
    • [0] 表示取第一个。
    • 隐含逻辑 :这里假设订单列表已经是按时间排序 的,最新的订单排在第一位。所以 orders[0] 就是"最新订单"。

🌐 4. 发送请求与异步处理

javascript 复制代码
            updateOrderDeadline(latestOrder.id, deadline || null)
                .then(() => {
                    // ...成功后的代码...
                })
                .catch(e => {
                    // ...失败后的代码...
                });

这是新手最难理解的部分,叫做异步编程。

  • updateOrderDeadline(...) :
    • 这是一个函数,它的工作是联系服务器(后端数据库),告诉服务器:"把这个订单的截止日期改掉"。
    • 因为联系服务器需要时间(比如 1 秒钟),JavaScript 不会傻等,而是继续往下跑。
  • .then(() => { ... }) :
    • 意思是:"如果 联系服务器成功了,就执行这里的代码"。
  • .catch(e => { ... }) :
    • 意思是:"如果 联系服务器失败了(比如断网了),就执行这里的代码"。
  • deadline || null :
    • 这是一个简写技巧。意思是:如果 deadline 有值,就用它;如果 deadline 是空的,就传 null(空值)给服务器,表示"清除日期"。

🔄 5. 成功后的回调(更新界面)

javascript 复制代码
                .then(() => {
                    latestOrder.followup_deadline = deadline || null;
                    showToast(deadline ? '截止日期已设置!' : '截止日期已清除!', '📅');
                    // 刷新标记点
                    addCustomerMarkers();
                })
  • latestOrder.followup_deadline = ... :
    • 服务器说"改好了",我们再把本地内存里的数据也改一下,保持同步。
  • showToast(...) :
    • 这是一个自定义函数,用来在屏幕上弹出一个像"吐司面包"一样的小提示框,告诉用户操作成功了。
    • deadline ? 'A' : 'B':这是三元表达式。意思是:如果有截止日期,显示"已设置";否则显示"已清除"。
  • addCustomerMarkers() :
    • 重新运行一遍绘制地图的函数。这通常会把地图上的标记点清除,然后根据新数据重新画一遍,这样用户就能立刻看到地图上的日期变了。

📌 总结:这段代码在做什么?

想象你在餐厅当服务员:

  1. 获取输入 :你听到客人(phone)说要把某个菜的忌口改掉(deadline)。
  2. 查找 :你跑到后厨,在一堆订单纸(customerMarkers)里翻找,找到那个客人的单子。
  3. 联系服务器 :你拿着单子去告诉厨师长(updateOrderDeadline,即服务器)。
  4. .then (成功) :厨师长说"改好了"。于是你在你的小本本上也把忌口改了(更新本地数据),然后大声告诉客人"改好了!"(showToast),并把桌上的菜单更新一下(addCustomerMarkers)。
  5. .catch (失败):如果厨师长说"单子丢了",你就告诉客人"不好意思改不了"(报错提示)

基础学习

1 对象抓取

document.getElementById

document.getElementById(inputId).value: document.getElementById(...): 这是浏览器提供的"魔法",用来在网页上抓取一个元素。

请说明一下 这个魔法 是如何在网页上抓取这个元素的 这个元素是 javascript的一个对象吗?

这真是一个直击灵魂的好问题!很多新手(甚至老手)只是机械地敲代码,却很少停下来思考这背后的原理。

简单直接的回答是:是的,它绝对是一个 JavaScript 对象。

为了让你彻底理解这个"魔法"是如何运作的,我们需要把浏览器想象成一个巨大的**"图书馆"** ,而网页代码(HTML)就是书架上的**"书"**。


🪄 魔法第一步:浏览器是如何"抓取"元素的?

当你打开一个网页时,浏览器并不是像看一张图片那样看网页的。它会做一件非常重要的事情:解析(Parsing)。

1. 构建"族谱"(DOM 树)

浏览器读取你的 HTML 代码(那些 <div>, <input>, <body> 标签),然后在内存中把它们整理成一棵家族树 。这棵树在技术上被称为 DOM。

想象一下,你的网页结构是这样的:

javascript 复制代码
<body>
  <div id="app">
    <input id="username" value="Alice">
  </div>
</body>

浏览器会在内存里画出一张这样的关系图(树状结构):

  • 根节点 : document (整个文档)
    • 子节点 : <body>
      • 子节点 : <div id="app">
        • 子节点 : <input id="username">
2. 建立"索引"(哈希表)

为了让你能通过 ID 瞬间找到元素,浏览器非常聪明。它在内部维护了一个类似字典 或索引的东西。

当你调用 document.getElementById('username') 时,浏览器并没有从树的根部开始一个一个数("是它吗?不是。是它吗?不是..."),那样太慢了。

相反,它直接查字典:

"我要找 ID 为 username 的家伙?哦,查表得知,它在内存地址 0x12345。"

这就是为什么这个"魔法"速度非常快,它是O(1) 的查找复杂度(瞬间找到)。


📦 魔法第二步:抓到的东西是对象吗?

绝对是。

当你执行 const element = document.getElementById('username') 时,变量 element 里装的不是那个 HTML 标签的字符串(比如 "<input ...>"),而是一个复杂的 JavaScript 对象。

这个对象里装满了各种属性、方法和状态。你可以把它想象成一个**"遥控器"**,通过这个遥控器,你可以控制网页上那个真实的显示画面。

这个对象长什么样?(揭秘)

如果你在控制台打印这个对象,你会发现它极其庞大。它大致长这样(简化版):

javascript 复制代码
HTMLInputElement {
  // --- 核心属性 ---
  id: "username",
  tagName: "INPUT",
  className: "",
  
  // --- 你刚才用到的属性 ---
  value: "Alice",        // 获取或设置输入框里的文字
  
  // --- 样式控制 ---
  style: CSSStyleDeclaration { ... }, // 用来控制颜色、大小等
  
  // --- 事件监听 ---
  onclick: null,
  addEventListener: function(...), // 用来绑定点击事件
  
  // --- 位置信息 ---
  offsetLeft: 100,
  offsetTop: 50,
  
  // --- 内部指针 (浏览器内部使用) ---
  // [Native Pointer to the underlying C++ implementation]
}

关键点来了:

这个对象是**"活"**的。

  • 当你修改 element.value = "Bob" 时,浏览器会立刻检测到这个对象的属性变了,然后自动去更新屏幕上的画面,让你看到输入框里的字变成了 "Bob"。
  • 当你在输入框里打字时,浏览器会自动更新这个对象的 value 属性。

🧩 为什么理解它是"对象"很重要?

理解了这一点,你就明白了为什么你可以这样写代码:

  1. 点语法访问 :因为它是对象,所以你可以用 .value、.id、.style 来访问它的内部数据。
  2. 函数调用 :因为它是对象,所以它身上挂载了函数(方法),比如 element.focus()(让输入框获得光标)。
  3. 引用传递 :当你把这个对象传给另一个函数时,你传的是它的引用(遥控器)。如果在那个函数里修改了对象,原来的元素也会跟着变。

📌 总结

document.getElementById 这个"魔法"的本质是:

  1. 浏览器把 HTML 代码翻译成了内存中的树状对象结构(DOM)。
  2. 浏览器维护了一张ID 索引表。
  3. 当你调用该方法时,浏览器查表,把对应的DOM 对象(那个遥控器)交到了你手里。

所以,你操作的不是"网页上的画面",而是画面背后的数据模型(对象),浏览器负责帮你把对象的变化同步到画面上。

还有哪些获取元素的方法?

除了 getElementById,JavaScript 还提供了多种获取 DOM 元素的方法,它们各有侧重,适用于不同的场景。

总的来说,可以分为两大类:

  1. 传统方法 :按标签名、类名或 name 属性来获取。
  2. 现代方法:使用 CSS 选择器来获取,功能最强大、最灵活。

下面是这些方法的详细介绍和对比。

🎯 按标签名获取:getElementsByTagName

这个方法用于获取网页中所有指定标签的元素,比如获取所有的 <p> 段落或 <div> 容器。

  • 语法 :document.getElementsByTagName('标签名')
  • 返回值 :一个实时 的 HTMLCollection(类似数组的集合)。
    • "实时"是什么意思? 这意味着如果之后网页中增加或删除了符合条件的元素,这个集合会自动更新,你不需要重新调用该方法。
  • 示例:
javascript 复制代码
// 获取网页中所有的段落 <p>
const paragraphs = document.getElementsByTagName('p');
console.log(`共有 ${paragraphs.length} 个段落`);
// 修改第一个段落的内容
paragraphs[0].textContent = '这是修改后的第一个段落。';

🏷️ 按类名获取:getElementsByClassName

这个方法用于获取所有具有指定 class 属性的元素。

  • 语法 :document.getElementsByClassName('类名')
  • 返回值 :同样是一个实时 的 HTMLCollection。
  • 示例:
javascript 复制代码
// 获取所有 class 为 "item" 的元素
const items = document.getElementsByClassName('item');
// 遍历并给每个元素添加一个边框
for (let i = 0; i < items.length; i++) {
    items[i].style.border = '1px solid red';
}

📝 按 name 属性获取:getElementsByName

这个方法主要用于获取表单元素,因为 name 属性在表单数据提交时非常重要。

  • 语法 :document.getElementsByName('name属性值')
  • 返回值 :一个实时 的 NodeList(节点列表)。
  • 示例:
html 复制代码
<input type="radio" name="gender" value="male"> 男
<input type="radio" name="gender" value="female"> 女
javascript 复制代码
// 获取所有 name 为 "gender" 的单选按钮
const genders = document.getElementsByName('gender');

✨ 现代选择器:querySelector 和 querySelectorAll

这是目前最推荐、最灵活的方法,因为它允许你使用任何 CSS 选择器来查找元素,功能极其强大。

querySelector
  • 作用 :返回第一个匹配指定 CSS 选择器的元素。
  • 语法 :document.querySelector('CSS选择器')
  • 返回值 :如果找到,返回一个 DOM 元素对象;如果没找到,返回 null。
  • 示例:
javascript 复制代码
// 获取 ID 为 "header" 的元素 (等同于 getElementById)
const header = document.querySelector('#header');

// 获取第一个 class 为 "btn" 的元素
const firstBtn = document.querySelector('.btn');

// 获取 div 容器内的第一个 p 标签 (复杂选择器)
const specialP = document.querySelector('div.container > p:first-child');
querySelectorAll
  • 作用 :返回所有匹配指定 CSS 选择器的元素。
  • 语法 :document.querySelectorAll('CSS选择器')
  • 返回值 :一个静态 的 NodeList。
    • "静态"是什么意思? 这意味着它就像是当时那一刻的"快照"。如果之后网页结构发生变化,这个列表不会自动更新。
  • 示例:
javascript 复制代码
// 获取所有 class 为 "highlight" 的元素
const highlights = document.querySelectorAll('.highlight');

// 获取所有 input 标签
const inputs = document.querySelectorAll('input');

📊 方法总结与对比

为了让你更清晰地选择,这里有一个总结表格:

表格

方法名 返回值类型 是否实时 适用场景
getElementById 单个元素或 null 否 通过唯一的 ID 获取单个元素,速度最快。
getElementsByTagName HTMLCollection 是 批量获取同一种标签的元素。
getElementsByClassName HTMLCollection 是 批量获取同一类样式的元素。
getElementsByName NodeList 是 主要用来获取表单元素(如 radio, checkbox)。
querySelector 单个元素或 null 否 使用 CSS 选择器获取第一个匹配元素,最灵活。
querySelectorAll NodeList 否 使用 CSS 选择器获取所有匹配元素,最灵活。

给新手的建议:

  • 如果要获取唯一的元素,优先使用 getElementById 或 querySelector。
  • 如果要获取一组元素,querySelectorAll 是最通用和强大的选择,因为它可以使用任何复杂的 CSS 规则来查找。

元素 是对象的意思吗

是的,完全正确!

你通过 getElementById 或其他方法获取到的"元素",在 JavaScript 眼里,就是一个标准的对象(Object)。

为了让你彻底明白,我们可以从以下三个角度来理解:

1. 它是"复杂数据类型"

在 JavaScript 中,数据分为"简单数据类型"(如数字、字符串)和"复杂数据类型"(即对象)。

  • DOM 元素属于复杂数据类型。
  • 当你把它赋值给一个变量时,变量里存的不是元素本身,而是内存地址(就像你手里拿着一把"遥控器",指向电视那个"对象")。

2. 它是一个"特殊的对象"

虽然它是个对象,但它不是我们平时用 {} 创建的那种普通对象,而是一个内置的、功能非常强大的对象。

  • 它的类名 :如果你打印它,你会发现它有具体的"型号"。比如 <div> 对应的是 HTMLDivElement,<input> 对应的是 HTMLInputElement。
  • 它的继承链 :它继承了一系列的"超能力"。
    • EventTarget:让它能听懂"点击"、"鼠标移动"等事件。
    • Node:让它有"父节点"、"子节点"等树形结构关系。
    • Element:让它有标签名、ID、类名等属性。

3. 你可以把它当成"遥控器"

既然它是对象,你就可以像操作普通对象一样操作它:

  • 点出属性 :你可以用 .value 获取输入框的值,用 .id 获取它的 ID。
  • 点出方法 :你可以用 .focus() 让它获得焦点,用 .click() 模拟点击。
  • 修改属性 :你修改这个对象的属性(比如 style.color = 'red'),浏览器就会立刻把网页上的画面变红。

总结

网页上的标签(HTML)是"尸体"(静态的结构),而 JavaScript 获取到的元素对象是"灵魂"(可以操作、有交互能力的实体)。

你通过 getElementById 拿到的,就是这个**"灵魂对象"**。

操作对象属性和修改HTML有什么区别?

这是一个非常深刻的问题,触及了前端开发中最容易让人困惑的核心概念:DOM 属性(Property)与 HTML 特性(Attribute)的区别。

简单来说:操作对象属性是"控制现在的状态",而修改 HTML 特性往往是"设定初始的状态"。

虽然它们看起来很像,但在浏览器眼里,它们其实是两个平行世界的东西。

1. 核心区别:Property vs Attribute

为了让你一目了然,我为你整理了一个对比表:

表格

特性 HTML 特性 (Attribute) DOM 属性 (Property)
定义 写在 HTML 标签上的字符串 浏览器解析后生成的 JavaScript 对象
作用 定义元素的初始状态(出厂设置) 反映元素的实时状态(当前状态)
操作方式 getAttribute(), setAttribute() 直接访问:element.value, element.checked
数据类型 永远是字符串 可以是任意类型(布尔值、对象、数字等)
同步性 修改后不会自动更新 Property 修改后通常不会自动更新 Attribute

2. 最经典的例子:输入框的 value

这是新手最容易踩的坑。假设你有一个输入框:

javascript 复制代码
<!-- HTML 代码 -->
<input type="text" id="myInput" value="初始值">

此时,浏览器做了两件事:

  1. HTML 特性 :记录了 value="初始值"(这是出厂设置)。
  2. DOM 属性 :生成了一个对象,myInput.value 也是 "初始值"(这是当前状态)。

接下来,神奇的事情发生了:

  • 场景一:用户在输入框里打字

    • 用户把 "初始值" 改成了 "用户输入"。
    • DOM 属性 (myInput.value) :变成了 "用户输入"(实时更新)。
    • HTML 特性 (getAttribute('value')) :依然是 "初始值"(因为它代表初始状态,不会随用户操作改变)。
  • 场景二:你用 setAttribute 修改

    • 代码:myInput.setAttribute('value', '新出厂设置')
    • HTML 特性 :变成了 "新出厂设置"。
    • DOM 属性 :可能不会变! (如果用户刚才已经输入了内容,setAttribute 往往无法覆盖用户当前的输入)。
  • 场景三:你用 element.value 修改(推荐做法)

    • 代码:myInput.value = '直接修改'
    • DOM 属性 :立刻变成 "直接修改"。
    • 屏幕显示:输入框里的字立刻变了。

结论 :如果你想改变输入框里显示的字,必须操作 DOM 属性 (element.value),而不是 HTML 特性。


3. 另一个例子:复选框的 checked

假设有一个复选框:

javascript 复制代码
<input type="checkbox" id="cb" checked>
  • HTML 特性 (checked):代表"默认被选中"。
  • DOM 属性 (checked):代表"现在是否被选中"。

如果你用鼠标取消勾选:

  • DOM 属性 :cb.checked 变为 false。
  • HTML 特性 :cb.getAttribute('checked') 依然是 "checked"(因为它只负责记录初始状态)。

如果你想通过代码让它选中,必须写 cb.checked = true 。如果你写 cb.setAttribute('checked', 'true'),虽然 HTML 标签上多了个属性,但界面上的勾可能并不会出现。


4. 什么时候该用哪个?

✅ 90% 的情况:操作 DOM 属性 (Property)

这是我们在日常开发(尤其是操作表单、样式、内容)时最常用的方式。

  • 表单状态 :input.value, checkbox.checked, button.disabled。
  • 修改内容 :element.innerHTML, element.textContent。
  • 修改样式 :element.style.color = 'red'。
  • 修改类名 :element.className 或 element.classList。
🛠️ 10% 的情况:操作 HTML 特性 (Attribute)

主要用于自定义数据 或特殊语义。

  • 自定义数据 :比如 <div data-user-id="123">,你需要用 getAttribute('data-user-id') 来读取。
  • 无障碍访问 :比如 aria-hidden="true",通常用 setAttribute 设置。
  • 强制重置:有些框架在重置表单时,可能会用到移除 Attribute 的操作。

总结

  • 操作对象属性(Property) = 操作"现在的状态"。这是你在 JavaScript 中应该主要做的事情。
  • 修改 HTML 特性(Attribute) = 修改"出厂设置"或"元数据"。这通常用于配置或存储额外信息。

记住一句话:在 JavaScript 中,想改变页面上的显示或状态,永远优先直接操作 DOM 属性(比如 element.value = ...),而不是去改 HTML 字符串。

相关推荐
Jmyd01233 小时前
Web端3D营销展厅技术实现路径:从素材上云到线索回流的数据链路
前端·3d·性能优化·三维数字化
半个落月3 小时前
LangChain Agent 中间件实战(上):生命周期、状态、短路与工具包
javascript·langchain
砚凝霜3 小时前
【软考信息安全】第二十二章 Web服务器安全分析与增强——Apache与IIS
服务器·前端·安全
2603_965148113 小时前
社区与学习资源:从入门到精通的API选品学习路径
数据库·人工智能·python·学习·数据挖掘
半个落月3 小时前
LangChain Agent 中间件实战(下):DeepAgents文件权限、长期记忆与对话摘要
javascript·langchain
u0111026755 小时前
JPG、PNG、WebP 怎么选?按透明度、体积和使用场景做判断
前端·javascript·vue.js·图像处理·ai作画
kaixin_啊啊5 小时前
【用于更准确 G×E 基因组预测的大规模作物数据集与基于深度学习的多模态融合框架】论文学习
人工智能·深度学习·学习
xier_ran6 小时前
【infra之路】AI 编译器学习笔记(六):重拾 C++——lambda 与 MLIR 中的回调
c++·笔记·学习
jerrywus6 小时前
让 AI 写完代码后交一份报告:我改造了 answer-me-with-html
前端·claude·cursor
派小心.6 小时前
小程序分享链路中来源参数的传递校验
大数据·前端·数据库·人工智能·小程序·数据分析