-
现在的情况是后端说桶里有视频,但没有返回回调 请问怎么解决呢?文档中也只说明了格式还有一些是否必填,没有具体例子。请问怎么解决呢 前端使用的是临时安全凭证的方法
-
MutationObserver 是 JavaScript 中一个强大的 API,用于监视 DOM 树的变化。它允许开发者以高效的方式监听和响应 DOM 结构的修改,是传统 Mutation Events 的现代替代方案。本文将详细介绍 MutationObserver 的工作原理、使用方法和实际应用场景。一、MutationObserver 简介MutationObserver 是一个内置对象,它提供了一种异步监视 DOM 树变化的方式。与已废弃的 Mutation Events 相比,MutationObserver 具有以下优势:性能更好:将多个 DOM 变化批量处理,而不是单独触发事件更精细的控制:可以指定要观察的变化类型异步触发:回调在微任务队列中执行,不会阻塞主线程二、基本用法1. 创建观察器实例// 创建观察器实例 const observer = new MutationObserver((mutationsList, observer) => { // 处理变化的回调函数 for(const mutation of mutationsList) { if (mutation.type === 'childList') { console.log('子节点发生了变化'); } else if (mutation.type === 'attributes') { console.log(`属性 ${mutation.attributeName} 发生了变化`); } } }); 2. 配置观察选项const config = { attributes: true, // 观察属性变化 childList: true, // 观察子节点变化 subtree: true, // 观察所有后代节点 attributeOldValue: true, // 记录属性旧值 characterData: true // 观察文本内容变化 }; 3. 开始观察// 开始观察目标节点 const targetNode = document.getElementById('target-element'); observer.observe(targetNode, config); 4. 停止观察// 停止观察 observer.disconnect(); 三、MutationRecord 对象回调函数接收的 mutationsList 是一个 MutationRecord 对象数组,每个对象包含以下属性:type: 变化类型(‘attributes’、‘childList’ 或 ‘characterData’)target: 发生变化的节点addedNodes/removedNodes: 添加/删除的节点列表previousSibling/nextSibling: 兄弟节点attributeName: 变化的属性名(仅属性变化时)oldValue: 旧值(如果配置了记录旧值)四、实际应用场景1. 动态内容跟踪// 监听评论区的动态加载 const commentObserver = new MutationObserver((mutations) => { mutations.forEach(mutation => { if (mutation.addedNodes.length) { const newComments = Array.from(mutation.addedNodes) .filter(node => node.classList.contains('comment')); if (newComments.length) { console.log('新评论加载:', newComments); } } }); }); commentObserver.observe( document.querySelector('.comments-container'), { childList: true, subtree: true } ); 2. 表单验证// 监听表单字段变化 const formObserver = new MutationObserver(() => { validateForm(); }); document.querySelectorAll('input, select, textarea').forEach(field => { formObserver.observe(field, { attributes: true, attributeFilter: ['value'] }); }); 3. 第三方脚本分析// 检测页面中添加的脚本标签 const scriptObserver = new MutationObserver(mutations => { mutations.forEach(mutation => { Array.from(mutation.addedNodes).forEach(node => { if (node.tagName === 'SCRIPT') { console.log('新脚本加载:', node.src); } }); }); }); scriptObserver.observe(document.documentElement, { childList: true, subtree: true }); 五、性能考虑虽然 MutationObserver 比 Mutation Events 更高效,但仍需注意:限制观察范围:尽量缩小观察的 DOM 范围精简回调逻辑:保持回调函数简洁高效及时断开连接:不再需要时调用 disconnect()避免过度观察:只观察真正需要的变化类型六、与其它技术的比较特性Mutation EventsMutationObserver性能低(同步触发)高(异步批量处理)精细控制有限高内存泄漏风险高低旧值记录不支持支持(可选)后代节点观察不支持支持七、总结MutationObserver 是现代 Web 开发中监视 DOM 变化的强大工具,特别适合需要响应动态内容加载、实时表单验证或分析第三方脚本的场景。通过合理配置和使用,可以显著提升 Web 应用的响应性和用户体验,同时保持代码的高效运行。随着 Web 应用越来越动态化,MutationObserver 的重要性日益凸显,掌握它的使用方法对于前端开发者来说是一项必备技能。
-
JavaScript(简称 JS)是一种轻量级、解释型(或即时编译型)的编程语言,主要用于为网页添加动态交互功能。它是现代 Web 开发的三大核心技术之一(另外两个是 HTML 和 CSS)。1. JavaScript 的特点✅ 客户端脚本语言:主要在浏览器中运行,无需服务器即可执行。✅ 动态类型:变量类型在运行时确定(如 let x = 10; 可以是数字,也可以是字符串)。✅ 事件驱动:可以响应用户操作(如点击、滚动、键盘输入等)。✅ 跨平台:支持所有主流浏览器(Chrome、Firefox、Safari、Edge)和服务器环境(Node.js)。✅ 单线程但支持异步:通过 回调(Callbacks)、Promise 和 Async/Await 处理异步任务。2. JavaScript 的用途(1)前端开发(浏览器端)DOM 操作:动态修改网页内容(如 document.getElementById())。事件处理:监听用户交互(如 button.addEventListener('click', ...))。AJAX/Fetch:异步加载数据(如调用 API)。前端框架:React、Vue、Angular 等均基于 JS。(2)后端开发(Node.js)服务器开发(Express、Koa、NestJS)。数据库操作(MongoDB、MySQL)。API 开发(RESTful、GraphQL)。(3)其他领域移动开发(React Native、Ionic)。桌面应用(Electron,如 VS Code)。游戏开发(Three.js、Phaser)。3. 基本语法示例(1)变量声明let name = "Alice"; // 可变变量const age = 25; // 常量(不可重新赋值)var oldWay = "Deprecated"; // 旧方式(不推荐)(2)函数定义function greet(name) { return `Hello, ${name}!`;}console.log(greet("Bob")); // 输出: "Hello, Bob!"// 箭头函数(ES6+)const greet = (name) => `Hi, ${name}!`;(3)事件监听document.querySelector("button").addEventListener("click", () => { alert("Button clicked!");});(4)异步操作(Promise + Async/Await)// Promise 示例fetch("https://api.example.com/data") .then(response => response.json()) .then(data => console.log(data));// Async/Await 更简洁async function fetchData() { const response = await fetch("https://api.example.com/data"); const data = await response.json(); console.log(data);}4. JavaScript 版本(ECMAScript)ES5 (2009):广泛支持的基础语法(如 var、function)。ES6 (2015):重大更新,引入 let/const、箭头函数、Promise、Class 等。ES2020+:可选链(?.)、空值合并(??)、BigInt 等新特性。总结JavaScript 是一门灵活且强大的语言,适用于前端、后端甚至全栈开发。随着 ES6+ 和现代框架(如 React、Vue)的普及,它已成为开发者必备技能之一。
-
一、技术定位与核心优势JupyterLab 是下一代交互式计算开发环境,2025年发布的4.0版本新增以下特性:多语言内核支持:Python/R/Julia/JavaScript一键切换实时协作功能:类似Google Docs的多人协同编码AI辅助编程:集成GPT-5代码补全与错误诊断可视化调试器:支持变量追踪与执行流可视化二、跨平台安装方案1. 系统兼容性矩阵平台最低要求推荐环境Windows10 21H2WSL2 + Ubuntu 22.04macOSMonterey 12.3+M2芯片+16GB内存LinuxKernel 5.15+Docker容器化部署2. 前置依赖管理Python环境:建议使用pyenv管理多版本# 安装Python 3.12(当前LTS版本) pyenv install 3.12.4 pyenv global 3.12.4虚拟环境:创建独立沙盒避免依赖冲突python -m venv ~/.jupyterenv source ~/.jupyterenv/bin/activate三、安装流程详解(以Windows为例)步骤1:通过pip安装核心组件pip install jupyterlab==4.0.0 \ jupyterlab-lsp \ # 语言服务器协议支持 jupyterlab-git \ # 版本控制集成 jupyterlab-ai \ # AI辅助扩展 jupyterlab-vim \ # Vim键位绑定 jupyterlab-drawio # 流程图绘制工具步骤2:配置优化(修改~/.jupyter/jupyter_lab_config.py )c.ServerApp.root_dir = '/mnt/d/JupyterProjects' # 项目存储路径 c.LabApp.collaborative = True # 启用实时协作 c.AICodeCompletion.model = 'gpt-5-turbo' # 指定AI模型步骤3:启动服务并访问jupyter lab --port 8888 --no-browser 浏览器打开 http://localhost:8888 并输入token认证四、高阶功能配置1. GPU加速支持(需NVIDIA显卡)pip install cupy-cuda12x jupyterlab-cuda-dashboard nvidia-smi --jupyter-integration2. 数据库直连扩展安装PostgreSQL内核并配置连接池:# 在notebook中执行 !pip install jupyterlab-sql %load_ext sql %sql postgresql://user:password@localhost/mydb3. 三维可视化集成import ipyvolume as ipv ipv.quickvolshow(np.random.rand(128,128,128))五、典型应用场景案例1:机器学习全流程开发# 数据加载 -> 特征工程 -> 模型训练 -> 可视化评估 import polars as pl from sklearn.inspection import DecisionBoundaryDisplay df = pl.read_parquet("data.parquet") display(DecisionBoundaryDisplay.from_estimator(model, X, alpha=0.5))案例2:交互式地理数据分析import geemap Map = geemap.Map(center=(40, -100), zoom=4) Map.add_basemap('SATELLITE') Map六、故障排查指南Q1:内核启动失败检查虚拟环境激活状态重装ipykernel:pip install --force-reinstall ipykernelQ2:AI辅助无响应确认API密钥设置:jupyter lab --AIToken=sk-xxxx切换备用模型:c.AICodeCompletion.fallback_model = 'claude-3'Q3:扩展安装冲突使用conda/mamba解决依赖:mamba install -c conda-forge jupyterlab=4.0.0七、效能提升技巧快捷键自定义:通过Settings > Keyboard Shortcuts绑定常用操作主题优化:安装jupyterlab-material-night提升暗色模式体验预加载内核:在配置中启用c.KernelManager.autorestart = True八、延伸学习路径Jupyter官方文档声明:本教程使用JupyterLab 4.0版本制作,原创内容转载请注明来源。
-
在 JavaScript 中,Object.create() 是一个静态方法,它创建一个新对象,使用现有的对象来提供新创建的对象的 __proto__。换句话说,它允许你创建一个对象,该对象继承自另一个对象的属性和方法。Object.create 详解语法Object.create(proto[, propertiesObject])proto:新创建对象的原型对象。propertiesObject(可选):可选属性描述符,这些属性描述符将被添加到新创建的对象中。返回值一个新对象,其原型(即内部 [[Prototype]] 属性)由参数 proto 提供。如果参数 proto 不是对象或者为 null,则新创建的对象将不会有原型(即它将不会继承任何属性和方法)。在 ES5 规范中,如果参数 proto 是 undefined 或 null,则新对象的原型会被设置为 Object.prototype 的原型,但这是一个已废弃的行为,并且在 ES6 及以后的版本中,如果 proto 是 null 或 undefined,将会抛出一个 TypeError。特性原型继承:Object.create() 允许你创建一个对象,该对象继承自指定的原型对象。属性定义:通过第二个参数,你可以在新对象上定义属性,并指定这些属性的特性(如可枚举性、可配置性、可写性等)。减少全局命名空间污染:使用 Object.create() 而不是直接通过字面量创建对象,可以减少全局命名空间中的对象数量,因为你可以创建一个具有特定原型的对象,而不需要将属性添加到全局对象(如 Object.prototype)上。示例// 创建一个原型对象 const person = { isHuman: false, printIntroduction: function() { console.log(`My name is ${this.name}. Am I human? ${this.isHuman}`); } }; // 创建一个新对象,其原型是 person const me = Object.create(person); // "name" 和 "isHuman" 是 me 的属性 me.name = 'John'; // "name" 是 me 的属性,而不是 person 的属性 me.isHuman = true; // 改变 me 的 isHuman 属性,不会影响到 person me.printIntroduction(); // 输出: "My name is John. Am I human? true" // 由于 person 没有 "name" 属性,所以访问 person.name 会返回 undefined console.log(person.name); // 输出: undefined在这个例子中,me 是通过 Object.create(person) 创建的,它继承了 person 的属性和方法。但是,me 有自己的 name 和 isHuman 属性,这些属性与 person 的属性是分开的。使用属性描述符你还可以使用属性描述符来定义新对象的属性:const newPerson = Object.create(person, { name: { value: 'Jane', writable: false, enumerable: true, configurable: true } }); console.log(newPerson.name); // 输出: Jane newPerson.name = 'Doe'; // 尝试修改 name 属性,但由于 writable: false,所以这里会静默失败(严格模式下会抛出错误) console.log(newPerson.name); // 仍然输出: Jane在这个例子中,newPerson 的 name 属性被设置为不可写(writable: false),因此尝试修改它的值会失败。注意事项使用 Object.create() 时,请确保提供的原型对象(proto)是有效的对象,否则将会抛出 TypeError。在 ES5 及以后的版本中,Object.create() 是创建具有指定原型的新对象的标准方法。在 ES5 之前,你需要使用其他方法(如构造函数或 __proto__ 属性)来实现类似的功能。当你使用 Object.create() 创建对象时,请考虑属性的可枚举性、可配置性和可写性,以确保你的对象符合预期的行为。
-
在 JavaScript 中,同样没有直接名为 Object.call 的方法。你可能是在提到 Function.prototype.call,这是一个函数对象的方法,允许你调用一个函数,同时设置函数体内 this 的值和在函数体开始执行之前提供初始的参数。Function.prototype.call 详解语法func.call([thisArg[, arg1, arg2, ...]])thisArg(可选):在 func 函数运行时使用的 this 值。注意,在非严格模式下,如果指定的值为 null 或 undefined,则会自动替换为全局对象(在浏览器中通常是 window),而原始值会被包装。arg1, arg2, ...(可选):调用 func 函数时传入的参数。返回值调用函数 func 的返回值。特性改变 this 指向:call 方法允许你显式地设置调用函数时 this 的值。立即执行:与 bind 不同,call 会立即执行函数。参数传递:你可以通过 call 方法传递任意数量的参数给被调用的函数。示例function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'Alice' }; greet.call(person, 'Hello', '!'); // 输出: Hello, Alice!在这个例子中,greet 函数通过 call 方法被调用,this 在 greet 函数内部被设置为 person 对象,并且 'Hello' 和 '!' 分别作为参数传递给 greet 函数。与 apply 的比较Function.prototype.apply 方法与 call 非常相似,不同之处在于 apply 接受参数的方式:call 方法接受若干个参数,第一个参数是 this 的值,后面的参数是传递给函数的参数。apply 方法接受两个参数,第一个参数是 this 的值,第二个参数是一个数组或类数组对象,表示传递给函数的参数。greet.apply(person, ['Hello', '!']); // 输出: Hello, Alice!在这个例子中,greet 函数通过 apply 方法被调用,this 被设置为 person 对象,并且参数 ['Hello', '!'] 被展开并传递给 greet 函数。注意事项使用 call 或 apply 时,要确保第一个参数(thisArg)是一个对象,或者 null 或 undefined(在非严格模式下会被替换为全局对象)。call 和 apply 是非常强大的方法,允许你动态地改变函数的 this 值和参数,但它们也可能导致代码难以理解和维护,特别是在复杂的代码库中。在类(class)的方法中,通常不需要使用 call 或 apply,因为类的方法在调用时会自动绑定到类的实例上。然而,在函数式编程或需要动态改变 this 指向的场景中,call 和 apply 非常有用。
-
在 JavaScript 中,实际上并没有一个名为 Object.bind 的方法。你可能是在提到 Function.prototype.bind,这是一个非常重要的函数方法,用于创建一个新的函数,这个新函数的 this 值会被设置为指定的值,并且在调用新函数时,其前几个参数会被预设为指定的值。Function.prototype.bind 详解语法fun.bind(thisArg[, arg1[, arg2[, ...]]])thisArg:在 fun 函数运行时使用的 this 值。注意,thisArg 在非严格模式下指定为 null 或 undefined 时会自动替换为全局对象(浏览器中通常是 window),而原始值会被包装。arg1, arg2, ...(可选):当调用新函数时,这些参数将置于实参之前提供给 fun 函数。返回值返回一个新的函数,这个函数的 this 永远被绑定到 thisArg 上,并且在其运行时,前置参数将排在提供的实参之前。特性改变 this 指向:bind 方法允许你显式地设置一个函数的 this 值,无论你如何调用这个函数,其 this 值都保持不变。参数预设:除了改变 this 指向,bind 还可以预设函数的前几个参数,这些参数在函数调用时会被放置在实参之前。不会立即执行:与 call 和 apply 不同,bind 不会立即执行函数,而是返回一个新的函数,这个新函数在被调用时会执行原函数。示例function greet(greeting, punctuation) { console.log(greeting + ', ' + this.name + punctuation); } const person = { name: 'Alice' }; const greetAlice = greet.bind(person, 'Hello'); greetAlice('!'); // 输出: Hello, Alice!在这个例子中,greet 函数被绑定到 person 对象上,并且 'Hello' 被预设为第一个参数。因此,当调用 greetAlice('!') 时,this 在 greet 函数内部被设置为 person 对象,并且 'Hello' 和 '!' 分别作为 greeting 和 punctuation 参数传递给 greet 函数。注意事项使用 bind 创建的新函数与原函数在功能上完全相同,只是 this 值和预设参数有所不同。由于 bind 返回的是一个新函数,因此它不会立即执行原函数。在类(class)的构造函数中,通常不会使用 bind,因为类的方法在调用时会自动绑定到类的实例上(除非你在类的方法中显式地使用了箭头函数,这会导致 this 绑定到定义该方法的上下文中,而不是类的实例)。希望这个详解能帮助你更好地理解 Function.prototype.bind 的用法!
-
在 JavaScript 中,实际上并不存在 Object.apply 这个方法。你可能是在寻找 Object.assign()、Function.prototype.apply() 或者其他某个方法,但是 Object.apply 确实不是一个标准的 JavaScript 方法。不过,我可以为你解释 Function.prototype.apply() 的用法,因为这是一个非常常见且重要的 JavaScript 方法。Function.prototype.apply()apply() 方法调用一个具有给定 this 值的函数,以及以一个数组(或类数组对象)的形式提供的参数。语法func.apply(thisArg, [argsArray])thisArg:在 func 函数运行时使用的 this 值。注意,null 和 undefined 会被自动替换为全局对象(在浏览器中是 window),而原始值会被包装。[argsArray]:一个数组或者类数组对象,其中的数组元素将作为单独的参数传给 func 函数。如果该参数的值为 null 或 undefined,则表示不需要传入任何参数。返回值函数调用的结果。示例function sum(a, b) { return a + b; } // 使用 apply 调用 sum 函数,并传入参数 const numbers = [1, 2]; const result = sum.apply(null, numbers); console.log(result); // 输出: 3在这个例子中,sum.apply(null, numbers) 相当于调用 sum(1, 2),因为 numbers 数组中的元素被作为单独的参数传给了 sum 函数。与 call() 的区别apply() 和 call() 方法的作用相似,区别在于 apply() 接受的是参数数组,而 call() 需要逐个列举参数。// 使用 call 调用 sum 函数,并传入参数 const resultWithCall = sum.call(null, 1, 2); console.log(resultWithCall); // 输出: 3在这个例子中,sum.call(null, 1, 2) 和 sum.apply(null, [1, 2]) 的效果是相同的。使用场景当你有一个数组(或类数组对象),并且想将其元素作为参数传递给一个函数时,可以使用 apply()。在编写通用函数时,如果你不确定会接收到多少个参数,或者参数是以数组形式给出的,那么 apply() 会非常有用。在一些情况下,你可能需要改变 this 的指向,这时 apply() 和 call() 都是很有用的工具。
-
Object.assign() 是 JavaScript ES6 (ECMAScript 2015) 引入的一个静态方法,用于将所有可枚举属性的值从一个或多个源对象复制到目标对象。它返回目标对象。语法Object.assign(target, ...sources)target:目标对象——将要接收新属性的对象。sources:源对象——一个或多个对象,其可枚举属性将被复制到目标对象。返回值返回目标对象(修改后的对象)。特性浅拷贝:Object.assign() 只会拷贝源对象自身的和可枚举的属性到目标对象,而不会拷贝其原型链上的属性。并且,它是浅拷贝,即如果源对象的属性值是对象,那么目标对象对应的属性值将引用同一个对象。同名属性覆盖:如果源对象中有多个同名属性,后面的属性会覆盖前面的属性。不可枚举属性:Object.assign() 不会拷贝源对象的不可枚举属性(例如使用 Object.defineProperty() 定义的属性,且 enumerable 属性设为 false)。原始数据类型:如果目标对象不是对象(例如,原始数据类型),Object.assign() 会将其转换为对象,然后返回这个新对象。示例基本用法const target = { a: 1 }; const source1 = { b: 2 }; const source2 = { c: 3 }; const returnedTarget = Object.assign(target, source1, source2); console.log(target); // 输出: { a: 1, b: 2, c: 3 } console.log(returnedTarget); // 输出: { a: 1, b: 2, c: 3 } // 注意:目标对象被修改,并且返回的也是目标对象浅拷贝const obj1 = { a: { b: 1 } }; const obj2 = Object.assign({}, obj1); obj2.a.b = 2; console.log(obj1.a.b); // 输出: 2 // 由于是浅拷贝,obj1 和 obj2 中的 a 属性指向同一个对象合并对象const defaults = { a: 1, b: 2 }; const options = { b: 3, c: 4 }; const finalOptions = Object.assign({}, defaults, options); console.log(finalOptions); // 输出: { a: 1, b: 3, c: 4 } // 注意到 b 属性被 options 中的值覆盖了处理原始数据类型const target = 'abc'; const result = Object.assign(target, { a: 1 }); console.log(result); // 输出: { 0: 'a', 1: 'b', 2: 'c', a: 1 } // 注意:目标字符串被转换为对象,并且属性被添加不可枚举属性const source = Object.create(Object.prototype, { foo: { value: 1, enumerable: false, writable: true, configurable: true }, bar: { value: 2, enumerable: true, writable: true, configurable: true } }); const target = {}; Object.assign(target, source); console.log(target); // 输出: { bar: 2 } // 不可枚举属性 foo 不会被拷贝注意事项使用 Object.assign() 时,要确保目标对象是可以被修改的对象,否则会出现不可预期的行为。浅拷贝的特性可能导致数据污染或意外的数据共享,特别是在处理嵌套对象时。实际应用Object.assign() 在实际应用中非常广泛,可以用于对象合并、配置选项的默认值和覆盖、对象属性的复制等场景。
-
在JavaScript中,深拷贝和浅拷贝是用于复制对象的两种不同方式,它们各自有着独特的原理和应用场景。一、深拷贝的原理及应用原理: 深拷贝是指创建一个完全独立于原始对象的副本,包括对象的所有嵌套属性和数组元素。深拷贝会递归地遍历原始对象,将其所有属性和元素复制到新的对象中,确保新对象与原始对象完全分离。这意味着对深拷贝创建的对象进行修改不会影响原始对象。应用: 深拷贝适用于需要完全独立的副本,并保持与原始对象的分离的情况。当需要在两个独立的对象之间共享或传递数据时,使用深拷贝可以确保数据的独立性,避免意外的共享和修改。当需要对对象进行修改或转换,但不希望影响原始对象时,可以使用深拷贝创建一个可安全操作的副本。二、浅拷贝的原理及应用原理: 浅拷贝是指创建一个新的对象,新对象的内容是原始对象的引用。如果原始对象中有引用类型的属性,那么浅拷贝后的新对象中的这些属性仍然会指向原始对象中的相应属性。换句话说,浅拷贝只复制了对象的引用,而不复制引用指向的内容。应用: 浅拷贝适用于需要共享数据、降低内存占用和提高性能的情况。当需要在两个对象之间共享数据,且希望对其中一个对象进行修改时,可以使用浅拷贝。这样做可以减少内存占用和提高性能,因为不需要创建完全独立的副本。当只需要访问对象的一部分属性或元素时,浅拷贝可以提供便利,避免复制整个对象的开销。三、深拷贝与浅拷贝的对比及选择对比:深拷贝会递归地复制对象的所有属性和元素,确保新对象与原始对象完全分离。而浅拷贝只复制了对象的引用,不复制引用指向的内容。对深拷贝后的对象进行修改不会影响原始对象,而对浅拷贝后的对象进行修改(如果修改了引用类型的属性),则可能会影响原始对象。选择:如果需要保持数据的独立性,避免意外的共享和修改,应选择深拷贝。如果需要共享数据、降低内存占用和提高性能,且不需要完全独立的副本,可以选择浅拷贝。四、实现深拷贝和浅拷贝的方法深拷贝的实现方法:使用 JSON.parse(JSON.stringify()) 方法:这是目前最常用的深拷贝方法之一,但它无法拷贝函数、正则表达式等特殊对象,也无法处理循环引用的情况。手动递归复制对象及其属性:通过递归地复制对象的每个属性(包括嵌套对象和数组)来实现深拷贝。浅拷贝的实现方法:使用对象展开运算符(...):可以快速简洁地进行对象和数组的浅拷贝。使用 Object.assign() 方法:可以将一个或多个源对象的属性复制到目标对象中,并返回目标对象。对于数组,可以使用 Array.prototype.concat() 或 Array.prototype.slice() 方法进行浅拷贝。
-
Object.entries() 定义Object.entries() 是 JavaScript 的一个内置方法,它返回一个给定对象自身可枚举属性的键值对数组,其排列与通过手动遍历对象属性返回的顺序一致(区别在于 for...in 循环枚举原型链中的属性)。数组中每个元素都是一个包含两个元素的数组,第一个元素是键名,第二个元素是键值。用法详解语法:Object.entries(obj)obj:要返回其键值对的对象。返回值:一个数组,其元素是键值对数组,每个键值对数组的第一个元素是键名(字符串类型),第二个元素是键值(可以是任何类型)。示例代码:const obj = { foo: 'bar', baz: 42 }; console.log(Object.entries(obj)); // 输出: [['foo', 'bar'], ['baz', 42]] // 转换对象到 Map const map = new Map(Object.entries(obj)); console.log(map); // 输出: Map(2) { 'foo' => 'bar', 'baz' => 42 } // 遍历对象的键值对 for (const [key, value] of Object.entries(obj)) { console.log(`${key}: ${value}`); } // 输出: // foo: bar // baz: 42 // 使用 Object.entries() 转换对象并过滤键值对 const filteredEntries = Object.entries(obj).filter(([key, value]) => typeof value === 'string'); console.log(filteredEntries); // 输出: [['foo', 'bar']] // 将键值对数组转换回对象 const newObj = Object.fromEntries(filteredEntries); console.log(newObj); // 输出: { foo: 'bar' }注意事项:Object.entries() 只返回对象自身的可枚举属性,不包括从原型链上继承的属性。返回的数组中的键值对顺序与通过手动遍历对象属性时的顺序一致。可以使用 for...of 循环来遍历 Object.entries() 返回的数组。Object.entries() 方法可以与 Object.fromEntries() 方法结合使用,以实现对象与键值对数组之间的转换。使用场景:当需要将对象的键值对转换为数组进行处理时,可以使用 Object.entries()。在需要遍历对象的键值对时,Object.entries() 提供了一种更直观、更易于理解的方式。在处理对象时,如果需要过滤、映射或转换键值对,可以先使用 Object.entries() 将对象转换为数组,然后进行相应的操作,最后使用 Object.fromEntries() 将数组转换回对象(如果需要的话)。
-
Object.is() 定义Object.is() 是 JavaScript 中的一个内置方法,用于比较两个值是否严格相等(即 === 比较的结果),但在处理某些特殊情况时,它提供了与 === 不同的行为。具体来说,Object.is() 在以下两个方面与 === 存在差异:+0 和 -0 被认为是不相等的。NaN 与 NaN 被认为是相等的。Object.is() 方法提供了一种更精确的方式来比较两个值是否相等,特别是在处理数字的特殊值时。用法详解语法:Object.is(value1, value2)value1:要比较的第一个值。value2:要比较的第二个值。返回值:如果两个值严格相等(考虑到了 +0 和 -0 的区别以及 NaN 的特殊情况),则返回 true。否则,返回 false。示例代码:console.log(Object.is('foo', 'foo')); // true console.log(Object.is({}, {})); // false,对象比较的是引用 console.log(Object.is(+0, -0)); // false,+0 和 -0 被视为不相等 console.log(Object.is(-0, -0)); // true console.log(Object.is(NaN, 0/0)); // true,NaN 与 NaN 被视为相等 console.log(Object.is(NaN, NaN)); // true console.log(Object.is(42, 42)); // true console.log(Object.is(true, true)); // true console.log(Object.is(false, false)); // true console.log(Object.is(null, null)); // true console.log(Object.is(undefined, undefined)); // true console.log(Object.is([], [])); // false,数组比较的是引用 console.log(Object.is([], [])); // false,同上 console.log(Object.is(function() {}, function() {})); // false,函数比较的是引用特殊情况说明:Object.is(+0, -0) 返回 false,因为 +0 和 -0 虽然被认为是相等的(使用 ===),但在 Object.is() 中它们被视为不相等。Object.is(NaN, NaN) 返回 true,因为 NaN 与 NaN 在 Object.is() 中被认为是相等的,这与 === 不同,因为在 === 中 NaN !== NaN。使用场景:当需要精确比较两个值是否相等时,特别是在处理数字的特殊值(如 +0、-0 和 NaN)时,可以使用 Object.is()。在编写需要精确判断相等性的算法或逻辑时,Object.is() 可以提供比 === 更准确的结果。总的来说,Object.is() 提供了一种更严格、更精确的相等性比较方法,特别适用于处理 JavaScript 中的一些特殊情况。
-
Object.keys()定义: Object.keys() 是一个JavaScript内置函数,用于返回一个由对象自身的(不包括原型链上的)所有可枚举属性组成的数组。数组中属性名的排列顺序与通过手动循环对象属性时的顺序一致。使用场景:当需要遍历对象的可枚举属性时,可以使用 Object.keys() 获取属性名数组,然后进行遍历。在处理对象时,如果需要获取对象的所有键(属性名),可以使用 Object.keys()。在需要判断对象是否包含某个属性时,可以先使用 Object.keys() 获取属性名数组,然后检查数组中是否包含该属性名。用法详解:// 示例对象 const person = { name: "张三", age: 25, sex: "男", getName: function() {} }; // 使用 Object.keys() 获取对象的所有可枚举属性名 const keys = Object.keys(person); console.log(keys); // 输出: ["name", "age", "sex", "getName"] // 遍历对象的所有可枚举属性 keys.forEach(key => { console.log(`${key}: ${person[key]}`); });对于数组和字符串,Object.keys() 会返回其索引值组成的数组。// 示例数组 const arr = [1, 2, 3, 4, 5]; console.log(Object.keys(arr)); // 输出: ["0", "1", "2", "3", "4"] // 示例字符串 const str = "javascript"; console.log(Object.keys(str)); // 输出: ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"]Object.values()定义: Object.values() 方法返回一个给定对象自身的所有可枚举属性值的数组,值的顺序与使用 for…in 循环的顺序相同(区别在于 for-in 循环枚举原型链中的属性,而 Object.values() 不包括原型链上的属性)。使用场景:当需要获取对象的所有值时,可以使用 Object.values()。在处理对象时,如果需要遍历对象的所有值,可以先使用 Object.values() 获取值数组,然后进行遍历。在需要将对象的值转换为数组进行进一步处理时,可以使用 Object.values()。用法详解:// 示例对象 const obj = { passport: '护照', mobile: '手机号', phone: '固定电话', email: '电子邮箱' }; // 使用 Object.values() 获取对象的所有可枚举属性值 const values = Object.values(obj); console.log(values); // 输出: ["护照", "手机号", "固定电话", "电子邮箱"] // 遍历对象的所有可枚举属性值 values.forEach(value => { console.log(value); });对于数组,Object.values() 会返回其顺序成员组成的数组。// 示例数组 const arr = ['x', 'y', 'z']; console.log(Object.values(arr)); // 输出: ["x", "y", "z"]总结Object.keys() 用于获取对象的所有可枚举属性名组成的数组。Object.values() 用于获取对象的所有可枚举属性值组成的数组。两者都不包括原型链上的属性。在处理对象、数组和字符串时,这两个方法都非常有用。
-
在JavaScript中,有多种方法可以用来遍历数组或对象的属性。以下是三种常见的循环方法:forEach、for-in 和 for-of。每种方法都有其特定的用途和适用场景。1. forEachforEach 方法用于遍历数组中的每一个元素,并为每个元素执行一次提供的回调函数。语法:array.forEach(function(currentValue, index, array) { // 你的迭代逻辑 });示例:const numbers = [1, 2, 3, 4, 5]; numbers.forEach((number, index) => { console.log(`Index: ${index}, Value: ${number}`); });特点:forEach 不会改变原数组。没有返回值(返回 undefined)。不能使用 break 或 continue 语句来中断循环。2. for-infor-in 循环用于遍历对象的可枚举属性(包括原型链上的属性,除非使用 hasOwnProperty 方法进行过滤)。语法:for (let key in object) { // 你的迭代逻辑 }示例:const person = { name: 'Alice', age: 25, city: 'New York' }; for (let key in person) { if (person.hasOwnProperty(key)) { console.log(`${key}: ${person[key]}`); } }特点:遍历对象的可枚举属性。枚举顺序不是按照属性在对象中出现的顺序。可以遍历到对象原型链上的属性。3. for-offor-of 循环用于遍历可迭代对象(包括数组、字符串、Map、Set 等)的值。语法:for (let value of iterable) { // 你的迭代逻辑 }示例:const numbers = [1, 2, 3, 4, 5]; for (let number of numbers) { console.log(number); } // 字符串 const str = 'Hello'; for (let char of str) { console.log(char); }特点:直接遍历可迭代对象的值。适用于数组、字符串、Map、Set 等。可以使用 break、continue 和 return 语句来中断循环。总结**forEach**:适用于遍历数组,不能中断循环,没有返回值。**for-in**:适用于遍历对象的可枚举属性,包括原型链上的属性(需要过滤)。**for-of**:适用于遍历可迭代对象的值,可以中断循环,适用于数组、字符串、Map、Set 等。选择哪种循环方法取决于你的具体需求和数据类型。
-
节流(Throttling)和防抖(Debouncing)是两种常用的优化函数执行频率的技术。节流(Throttling): 控制一定时间内函数的执行次数。function throttle(fn, wait) { let timeout = null; return function() { let context = this; let args = arguments; if (!timeout) { timeout = setTimeout(() => { fn.apply(context, args); timeout = null; }, wait); } }; }// 使用示例 window.addEventListener('resize', throttle(function() { console.log(window.innerWidth, window.innerHeight); }, 200));防抖(Debouncing): 当持续触发事件时,一定时间内只执行最后一次。function debounce(fn, wait) { let timeout = null; return function() { let context = this; let args = arguments; if (timeout) clearTimeout(timeout); let callNow = !timeout; timeout = setTimeout(() => { timeout = null; }, wait); if (callNow) fn.apply(context, args); }; }// 使用示例 window.addEventListener('resize', debounce(function() { console.log(window.innerWidth, window.innerHeight); }, 200));节流通过设置一个timeout控制函数执行的频率,防抖通过清除已经设置的timeout再次执行函数。
上滑加载中
推荐直播
-
HDC深度解读系列 - Serverless与MCP融合创新,构建AI应用全新智能中枢2025/08/20 周三 16:30-18:00
张昆鹏 HCDG北京核心组代表
HDC2025期间,华为云展示了Serverless与MCP融合创新的解决方案,本期访谈直播,由华为云开发者专家(HCDE)兼华为云开发者社区组织HCDG北京核心组代表张鹏先生主持,华为云PaaS服务产品部 Serverless总监Ewen为大家深度解读华为云Serverless与MCP如何融合构建AI应用全新智能中枢
回顾中 -
关于RISC-V生态发展的思考2025/09/02 周二 17:00-18:00
中国科学院计算技术研究所副所长包云岗教授
中科院包云岗老师将在本次直播中,探讨处理器生态的关键要素及其联系,分享过去几年推动RISC-V生态建设实践过程中的经验与教训。
回顾中 -
一键搞定华为云万级资源,3步轻松管理企业成本2025/09/09 周二 15:00-16:00
阿言 华为云交易产品经理
本直播重点介绍如何一键续费万级资源,3步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签