-
在存储数据时,不同类型的数据(如汉字、英文单词、字母)占用的空间大小不同,主要取决于它们的编码方式。以下是基于常见编码(如 UTF-8)的详细计算:1. 存储汉字(UTF-8 编码)UTF-8 编码规则:1 个汉字通常占用 3 字节(少数生僻字可能占用 4 字节,但绝大多数常用汉字是 3 字节)。计算:5MB = 5 × 1024 × 1024 = 5,242,880 字节。可存储汉字数量 = 5,242,880 ÷ 3 ≈ 1,747,626 个汉字(约 174 万汉字)。2. 存储英文单词(UTF-8 编码)UTF-8 编码规则:1 个英文字母(A-Z/a-z)占用 1 字节。1 个英文单词的平均长度约为 5~8 个字母(假设取中间值 6 个字母)。计算:每个单词占用字节 = 6 × 1 = 6 字节。可存储单词数量 = 5,242,880 ÷ 6 ≈ 873,813 个单词(约 87 万单词)。3. 存储字母(UTF-8 编码)UTF-8 编码规则:1 个字母(A-Z/a-z)占用 1 字节。1 个数字(0-9)或符号(如 !, @)也占用 1 字节。计算:可存储字母数量 = 5,242,880 ÷ 1 = 5,242,880 个字母(约 524 万字母)。4. 关键注意事项编码方式的影响:如果使用 UTF-16 编码,汉字可能占用 2 字节(但部分生僻字会占用 4 字节),而英文字母固定占用 2 字节。此时计算结果会不同:UTF-16 汉字:5,242,880 ÷ 2 = 2,621,440 个汉字(约 262 万汉字)。UTF-16 字母:5,242,880 ÷ 2 = 2,621,440 个字母(约 262 万字母)。但现代浏览器和系统默认使用 UTF-8,因此优先按 UTF-8 计算。实际存储开销:localStorage 和 IndexedDB 存储的是字符串,而字符串在 JavaScript 中会隐含一些额外开销(如引号、转义字符等),但通常可以忽略不计。如果存储 JSON 格式的数据(如 {"key": "value"}),会因格式符号({}, ", :)占用少量额外空间。存储限制:localStorage 的 5MB 限制是大多数浏览器的标准,但不同浏览器可能略有差异(如移动端可能更低)。IndexedDB 的存储上限通常更高(如剩余磁盘空间的百分比)。5. 总结表数据类型编码方式每个单位占用字节5MB 可存储数量汉字UTF-83 字节/汉字约 174 万汉字英文单词UTF-86 字节/单词(6字母)约 87 万单词字母/数字UTF-81 字节/字符约 524 万字母/数字汉字UTF-162 字节/汉字约 262 万汉字字母/数字UTF-162 字节/字符约 262 万字母/数字6. 实际建议存储汉字:直接按 3 字节/汉字 计算,保守估计。存储英文文本:如果单词长度差异大,可按平均 5~8 字母/单词 调整计算。优化存储:若需存储大量数据,考虑压缩(如 lz-string 库)或使用 IndexedDB 替代 localStorage。
-
在JavaScript中,IndexedDB和localStorage的存储空间上限及超出限制时的行为存在显著差异,具体如下:1. localStorage的存储空间上限统一配额:所有浏览器均限制同一源(域名)下localStorage的存储上限为5MB。这一限制包含localStorage和sessionStorage的总和(合计约10MB)。超出限制的行为:当存储数据超过5MB时,浏览器会直接抛出QuotaExceededError异常,导致写入操作失败。例如:try { localStorage.setItem('largeData', new Array(10 * 1024 * 1024).join('x')); // 尝试存储10MB数据 } catch (e) { console.error('存储失败:', e.name); // 输出: QuotaExceededError } 2. IndexedDB的存储空间上限浏览器差异:IE:固定上限为250MB。Chrome/Opera:基于剩余磁盘空间的百分比(通常为剩余空间的20%,但具体比例可能因浏览器版本而异)。Firefox:无硬性上限,但受浏览器全局存储配额限制(通常为硬盘可用空间的50%,且每个主域名组最多占用20%)。移动端:部分浏览器可能限制IndexedDB的存储上限为5MB(与localStorage相同)。全局与组配额:全局限制:浏览器总存储空间通常为硬盘可用空间的50%(如500GB硬盘最多存储250GB)。组限制:每个主域名(如example.com)及其子域名(如www.example.com)共享一个存储组,最多占用全局限制的20%(如250GB的20%为50GB),但最少不低于10MB、最多不超过2GB。超出限制的行为:若存储操作超出源的配额,浏览器会抛出QuotaExceededError异常。若浏览器全局存储空间已满,会自动删除部分网站的数据(整个网站的数据会被清空,而非部分数据)以腾出空间。3. 关键对比与建议特性localStorageIndexedDB存储上限统一5MB(同一源)浏览器差异大(IE 250MB,Chrome/剩余空间百分比,Firefox无硬上限)数据类型仅支持字符串(需手动序列化复杂数据)支持JavaScript对象、二进制数据(ArrayBuffer、Blob)超出限制的行为直接抛出QuotaExceededError抛出QuotaExceededError或自动清理数据适用场景简单键值对存储(如用户偏好设置)大型应用状态、离线数据、媒体资源存储4. 开发建议检测存储空间:使用navigator.storage.estimate()方法获取当前源的预估已用空间和可用空间,避免盲目写入导致异常。navigator.storage.estimate().then(estimate => { console.log(`已用空间: ${estimate.usage} bytes, 可用空间: ${estimate.quota - estimate.usage} bytes`); }); 异常处理:用try...catch包裹存储操作代码,捕获QuotaExceededError异常并提示用户清理缓存。try { const request = indexedDB.open('myDB', 1); request.onsuccess = () => { const db = request.result; // 执行存储操作... }; } catch (e) { if (e.name === 'QuotaExceededError') { alert('本地空间不足,请清理浏览器缓存后重试。'); } } 选择存储方案:若需存储少量简单数据(如Token、用户设置),优先使用localStorage。若需存储大量结构化数据或二进制资源(如图片、视频),选择IndexedDB。
-
在JavaScript中,localStorage 和 IndexedDB 是两种常用的客户端存储方案,分别适用于不同的场景。以下是它们的详细用法和对比:1. localStorage 用法localStorage 是一个简单的键值对存储,数据以字符串形式保存,适合存储少量简单数据(如用户偏好、Token等)。基本操作存储数据// 存储字符串 localStorage.setItem('username', 'JohnDoe'); // 存储对象(需序列化为JSON字符串) const user = { name: 'Alice', age: 25 }; localStorage.setItem('user', JSON.stringify(user)); 读取数据const username = localStorage.getItem('username'); // "JohnDoe" const userData = JSON.parse(localStorage.getItem('user')); // { name: 'Alice', age: 25 } 删除数据localStorage.removeItem('username'); // 删除指定键 localStorage.clear(); // 清空所有数据 遍历所有键for (let i = 0; i < localStorage.length; i++) { const key = localStorage.key(i); console.log(key, localStorage.getItem(key)); } 注意事项仅支持字符串:存储对象需用 JSON.stringify(),读取时用 JSON.parse()。同步操作:所有操作会阻塞主线程,不适合存储大量数据。存储上限:通常为 5MB(不同浏览器可能略有差异)。2. IndexedDB 用法IndexedDB 是一个事务型数据库,支持结构化数据存储(如对象、二进制数据),适合存储大量复杂数据(如应用状态、离线数据)。基本操作1. 打开数据库const request = indexedDB.open('MyDatabase', 1); // 数据库名和版本号 request.onerror = (event) => { console.error('数据库打开失败:', event.target.error); }; request.onsuccess = (event) => { const db = event.target.result; console.log('数据库打开成功'); }; // 首次创建或升级数据库时触发 request.onupgradeneeded = (event) => { const db = event.target.result; // 创建对象存储空间(类似表) if (!db.objectStoreNames.contains('users')) { const store = db.createObjectStore('users', { keyPath: 'id' }); // 可选:创建索引 store.createIndex('name', 'name', { unique: false }); } }; 2. 增删改查(CRUD)(1)添加数据function addUser(user) { const transaction = db.transaction(['users'], 'readwrite'); const store = transaction.objectStore('users'); const request = store.add(user); request.onsuccess = () => console.log('用户添加成功'); request.onerror = (e) => console.error('添加失败:', e.target.error); } addUser({ id: 1, name: 'Alice', age: 25 }); (2)查询数据function getUser(id) { const transaction = db.transaction(['users'], 'readonly'); const store = transaction.objectStore('users'); const request = store.get(id); request.onsuccess = (e) => console.log('查询结果:', e.target.result); request.onerror = (e) => console.error('查询失败:', e.target.error); } getUser(1); (3)更新数据function updateUser(user) { const transaction = db.transaction(['users'], 'readwrite'); const store = transaction.objectStore('users'); const request = store.put(user); // put 会覆盖同名键的数据 request.onsuccess = () => console.log('更新成功'); } updateUser({ id: 1, name: 'Alice Updated', age: 26 }); (4)删除数据function deleteUser(id) { const transaction = db.transaction(['users'], 'readwrite'); const store = transaction.objectStore('users'); const request = store.delete(id); request.onsuccess = () => console.log('删除成功'); } deleteUser(1); (5)遍历所有数据function getAllUsers() { const transaction = db.transaction(['users'], 'readonly'); const store = transaction.objectStore('users'); const request = store.getAll(); request.onsuccess = (e) => { console.log('所有用户:', e.target.result); }; } 3. 使用游标遍历数据function cursorExample() { const transaction = db.transaction(['users'], 'readonly'); const store = transaction.objectStore('users'); const request = store.openCursor(); request.onsuccess = (e) => { const cursor = e.target.result; if (cursor) { console.log('当前记录:', cursor.value); cursor.continue(); // 移动到下一条记录 } }; } 4. 使用索引查询function getUsersByName(name) { const transaction = db.transaction(['users'], 'readonly'); const store = transaction.objectStore('users'); const index = store.index('name'); const request = index.getAll(name); request.onsuccess = (e) => { console.log('按姓名查询结果:', e.target.result); }; } 注意事项异步操作:IndexedDB 的所有操作都是异步的,需通过回调或 Promise 处理。事务(Transaction):所有读写操作必须在事务内进行。存储上限:通常为 剩余磁盘空间的百分比(Chrome/Firefox)或 250MB(IE)。复杂查询:支持索引和游标,但不如 SQL 直观。3. localStorage vs IndexedDB 对比特性localStorageIndexedDB数据类型仅字符串支持对象、二进制数据(Blob、ArrayBuffer)存储上限5MB浏览器差异大(通常数百MB到磁盘剩余空间)操作方式同步异步(基于事件或 Promise)适用场景简单键值对(如用户设置)大型结构化数据(如应用状态、离线数据)查询能力仅按键查询支持索引、游标、范围查询4. 封装 IndexedDB 为 Promise由于 IndexedDB 是事件驱动的,可以封装为 async/await 风格:class IDBWrapper { constructor(dbName, version) { this.dbName = dbName; this.version = version; this.db = null; } async init() { return new Promise((resolve, reject) => { const request = indexedDB.open(this.dbName, this.version); request.onerror = (e) => reject(e.target.error); request.onsuccess = (e) => { this.db = e.target.result; resolve(this.db); }; request.onupgradeneeded = (e) => { const db = e.target.result; if (!db.objectStoreNames.contains('users')) { db.createObjectStore('users', { keyPath: 'id' }); } }; }); } async add(storeName, data) { return new Promise((resolve, reject) => { const transaction = this.db.transaction(storeName, 'readwrite'); const store = transaction.objectStore(storeName); const request = store.add(data); request.onsuccess = () => resolve(); request.onerror = (e) => reject(e.target.error); }); } // 其他方法(get、put、delete等)类似... } // 使用示例 (async () => { const idb = new IDBWrapper('MyDB', 1); await idb.init(); await idb.add('users', { id: 1, name: 'Bob' }); })(); 总结localStorage:简单、同步、适合小数据。IndexedDB:强大、异步、适合大数据和复杂查询。推荐库:localForage(封装 IndexedDB/WebSQL/localStorage,提供类似 localStorage 的 API)。Dexie.js(简化 IndexedDB 操作的轻量级库)。根据需求选择合适的存储方案!
-
可以使用--legacy-peer-deps来忽略版本冲突
-
JavaScript原型链终极解析:彻底搞懂prototype和__proto__的区别你被JavaScript的prototype和__proto__搞得头晕脑胀吗?这两个概念确实让很多开发者困惑不已。今天我们用最直白的方式,彻底搞清楚它们的区别和关系,让你再也不会在面试中栽跟头。先记住一个核心区别在深入之前,先记住这个最重要的区别:prototype - 只有函数才有,是人为设定的属性proto - 所有对象都有,用来实现继承关系这个区别是理解整个原型链的关键。很多人混淆这两个概念,就是因为没有搞清楚这个基本点。JavaScript的"创世神话"为了更好理解原型链,我们可以把JavaScript的对象体系想象成一个"神话世界"。第一神:Object.prototype在JavaScript的世界里,有一个万物起源,就是Object.prototype。它是所有对象的最终祖先。// Object.prototype是万物的尽头console.log(Object.prototype.__proto__); // null这个null就代表虚无,再往上就没有了。Object.prototype就是继承链的终点。第二神:Function.prototype接下来诞生了第二个重要角色:Function.prototype。它继承自Object.prototype:console.log(Function.prototype.__proto__ === Object.prototype); // true有个容易混淆的点:Function.prototype本身也是个函数,但它是个特殊的函数。它不管你传什么参数,都返回undefined,而且不能用new调用。函数是"一等公民"的真正含义经常听到"函数在JavaScript中是一等公民",这到底什么意思?其实就是说,所有的函数(包括Function构造函数本身)都继承自Function.prototype:// 所有函数的__proto__都指向Function.prototypeconsole.log(Object.__proto__ === Function.prototype); // trueconsole.log(Function.__proto__ === Function.prototype); // trueconsole.log(String.__proto__ === Function.prototype); // trueconsole.log(Number.__proto__ === Function.prototype); // true连Function自己都继承自Function.prototype,这看起来有点奇怪,但确实是这样设计的。用实例来验证理解让我们通过几个具体例子来验证我们的理解:例子1:Object instanceof Object这个表达式为什么是true?console.log(Object instanceof Object); // true分析过程:Object是个函数,所以Object.__proto__ === Function.prototypeFunction.prototype.__proto__ === Object.prototypeinstanceof会沿着__proto__链查找,最终找到了Object.prototype所以结果是true例子2:Function instanceof Functionconsole.log(Function instanceof Function); // true分析过程:Function是个函数,所以Function.__proto__ === Function.prototypeinstanceof在第一步就找到了Function.prototype所以结果是true例子3:自定义函数function MyFunction() {}console.log(MyFunction instanceof Function); // trueconsole.log(MyFunction instanceof Object); // true分析过程:MyFunction是函数,MyFunction.__proto__ === Function.prototypeFunction.prototype.__proto__ === Object.prototype所以MyFunction既是Function的实例,也是Object的实例构造函数的prototype属性当我们创建函数时,JavaScript会自动给它添加一个prototype属性:function Person(name) { this.name = name;}// Person.prototype是人为设定的Person.prototype.sayHello = function() { console.log('Hello, I am ' + this.name);};const person1 = new Person('张三');// person1的__proto__指向Person.prototypeconsole.log(person1.__proto__ === Person.prototype); // true这里的关键理解:Person.prototype是我们人为设定的,用来给Person的实例添加共享方法person1.__proto__是自动设置的,指向构造函数的prototype原型链查找机制当我们访问对象的属性时,JavaScript会按照这个顺序查找:function Person(name) { this.name = name;}Person.prototype.species = 'human';Object.prototype.planet = 'earth';const person = new Person('李四');// 查找顺序演示console.log(person.name); // 直接在person对象上找到console.log(person.species); // 在Person.prototype上找到 console.log(person.planet); // 在Object.prototype上找到console.log(person.nothing); // 都找不到,返回undefined查找路径:person自身属性person.proto (即Person.prototype)person.proto.proto (即Object.prototype)person.proto.proto.proto (即null)常见误区和陷阱误区1:混淆prototype和__proto__function Person() {}const person = new Person();// 错误理解console.log(person.prototype); // undefined,实例没有prototype属性// 正确理解 console.log(person.__proto__ === Person.prototype); // true误区2:直接修改__proto__// 不推荐的做法const obj = {};obj.__proto__ = Person.prototype;// 推荐的做法const obj = Object.create(Person.prototype);// 或者Object.setPrototypeOf(obj, Person.prototype);AI写代码误区3:认为所有对象都有prototype属性const obj = {};console.log(obj.prototype); // undefined,普通对象没有prototypefunction func() {}console.log(func.prototype); // {},只有函数才有prototype实际应用场景继承的实现function Animal(name) { this.name = name;}Animal.prototype.speak = function() { console.log(this.name + ' makes a sound');};function Dog(name) { Animal.call(this, name);}// 实现继承Dog.prototype = Object.create(Animal.prototype);Dog.prototype.constructor = Dog;Dog.prototype.bark = function() { console.log(this.name + ' barks');};const dog = new Dog('旺财');dog.speak(); // 旺财 makes a sounddog.bark(); // 旺财 barks判断对象类型function isArray(obj) { return Object.prototype.toString.call(obj) === '[object Array]';}function isFunction(obj) { return typeof obj === 'function';}// 更现代的方法console.log(Array.isArray([])); // true扩展内置对象(谨慎使用)// 给所有数组添加自定义方法Array.prototype.last = function() { return this[this.length - 1];};const arr = [1, 2, 3, 4];console.log(arr.last()); // 4// 注意:修改内置对象原型在生产环境中要谨慎现代JavaScript的替代方案使用Class语法(ES6+)class Animal { constructor(name) { this.name = name; } speak() { console.log(`${this.name} makes a sound`); }}class Dog extends Animal { bark() { console.log(`${this.name} barks`); }}const dog = new Dog('旺财');dog.speak(); // 旺财 makes a sound虽然class语法看起来更清爽,但底层实现还是基于原型链。使用Object.create()const animalMethods = { speak() { console.log(`${this.name} makes a sound`); }};function createAnimal(name) { const animal = Object.create(animalMethods); animal.name = name; return animal;}const animal = createAnimal('小猫');animal.speak(); // 小猫 makes a sound面试常考问题问题1:解释原型链答案要点:每个对象都有__proto__属性,指向其构造函数的prototype原型链是通过__proto__连接起来的链条属性查找会沿着原型链向上查找,直到找到或到达null问题2:new操作符做了什么function myNew(Constructor, ...args) { // 1. 创建新对象 const obj = {}; // 2. 设置原型链 Object.setPrototypeOf(obj, Constructor.prototype); // 3. 绑定this并执行构造函数 const result = Constructor.apply(obj, args); // 4. 返回对象 return (typeof result === 'object' && result !== null) ? result : obj;}问题3:instanceof的实现原理function myInstanceof(left, right) { let leftProto = Object.getPrototypeOf(left); const rightPrototype = right.prototype; while (leftProto !== null) { if (leftProto === rightPrototype) { return true; } leftProto = Object.getPrototypeOf(leftProto); } return false;}性能和最佳实践性能考虑避免深层原型链 - 查找属性时会影响性能缓存属性访问 - 频繁访问的属性可以缓存到局部变量使用hasOwnProperty - 避免查找原型链上的属性const obj = { name: '张三' };// 好的做法if (obj.hasOwnProperty('name')) { console.log(obj.name);}// 更安全的做法if (Object.prototype.hasOwnProperty.call(obj, 'name')) { console.log(obj.name);}最佳实践不要修改内置对象的原型 - 可能与其他代码冲突使用Object.create(null)创建纯净对象 - 没有原型链的对象优先使用组合而非继承 - 现代JavaScript推荐的模式// 纯净对象,没有原型链const pureObj = Object.create(null);pureObj.name = '张三';console.log(pureObj.toString); // undefined// 组合模式示例function createLogger(config) { return { log(message) { console.log(`[${config.level}] ${message}`); } };}调试技巧当你需要调试原型链相关问题时,这些方法很有用:function debugPrototypeChain(obj) { let current = obj; let depth = 0; while (current !== null) { console.log(`Level ${depth}:`, current.constructor.name); current = Object.getPrototypeOf(current); depth++; if (depth > 10) { // 防止无限循环 console.log('Chain too deep, stopping...'); break; } }}function Person() {}const person = new Person();debugPrototypeChain(person);// Level 0: Person// Level 1: Function // Level 2: Object理解prototype和__proto__的关系是掌握JavaScript面向对象编程的关键。虽然现在有了class语法和其他现代特性,但原型链仍然是JavaScript的核心机制。掌握了这些概念,你就能更好地理解JavaScript的工作原理,写出更优雅的代码。你在学习原型链的过程中遇到过什么困惑?或者有什么好的记忆方法?欢迎在评论区分享。觉得这篇文章对你有帮助的话,记得点赞收藏,我会继续分享更多JavaScript深度技术内容。———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/2301_80934913/article/details/151872599
-
一、路径中 / 的含义1、 / 所扮演的角色 在浏览器、Node、Vue CLI 中,/ 都表示一种层级关系,常用来分隔目录结构或路由片段:/src/components/Button.vue → 组件文件路径/api/user/info → RESTful API 路径/about → 前端路由路径2、根据 URL 中的 / 判断是目录还是资源 浏览器会自动根据 URL 最后是否包含 / 来区分目录或文件资源,关键就在于是不是以 / 结尾,如果是,就代表最后一个路径名是目录名(文件夹名称),如果不是以 / 结尾,就是文件资源。URL 推断/about/目录/about文件资源(如 html、json)/images/logo.png文件资源 /about/ → 被认为是目录,会尝试寻找 /about/index.html(vue中是寻找 /about/index.vue)3、相对路径 vs 绝对路径 一个表格讲清楚:路径形式 示例 含义说明绝对路径 /assets/logo.png从网站根目录出发寻找资源相对路径 ./img/logo.png当前文件夹下寻找资源相对路径 ../img/logo.png当前文件夹的上一级目录下寻找资源 vue 项目使用绝对路径的时候,/ 一般是从 public 文件夹开始往下,无法通过绝对路径访问src文件夹中的资源(一般用@,但是要配置),因为src下的资源在打包后会重新分配结构,使用绝对路径在生产环境就会失效,所以毫无意义。4、相对路径中的 . 与 ...:当前路径(Current Directory)..:上一级目录(Parent Directory)<!-- 当前文件在 /pages/about/index.html --><img src="../../images/banner.jpg"> <!-- 实际路径为 /images/banner.jpg --><!-- pages与iamges在同一目录下 -->AI生成项目javascript运行二、Vue中 / 的特殊作用1、Vue Router 中的 / 在Vue Router中,/ 代表根路由,也就是说实际路径为:协议+域名(ip+端口)+ baseUrl + 路由。最后的路由部分就是Vue Router配置的内容,根路由就是路由为 / 。 此外/about/ 与 /about 默认被视为等价(除非手动设置)const routes = [ { path: '/', component: Home }, { path: '/about', component: About },]AI生成项目javascript运行2、Vue 项目构建时的 base 配置 这个其实是要根据生产环境下的路由决定的,生产环境下的路由是什么,这里base就设置什么,以此来保证打包部署后的资源能被正确访问。// vite.config.jsexport default defineConfig({ base: '/my-app/', // 所有资源前缀会带上这个路径})AI生成项目javascript运行三、SEO 对 / 的敏感性 搜索引擎(如 Google、Baidu)会把下面两个路径视为两个不同的页面:/blog/blog/ 所以需要路由统一末尾加 /,或者通过 Nginx 重定向处理一致性,避免 /about 和 /about.html 指向同一页面而无重定向,容易造成 SEO 评分下降。四、Nginx 中 / 的配置技巧 proxy_pass 后的 / 会影响转发路径拼接方式,建议保持一致,否则可能造成路径错乱,此时 /api/user 实际会被转发至 http://localhost:3000/user。 个人建议在nginx中永远在路径和路由后加上 / ,基本不会错。location /api/ { proxy_pass http://localhost:3000/;}AI生成项目javascript运行五、fetch 和 API 请求中的 / 影响fetch('/api/user') // 相对根路径fetch('./api/user') // 相对当前路径(可能出错)fetch('https://example.com/api/user') // 绝对路径AI生成项目javascript运行 Vue 中推荐使用 axios 统一配置:const instance = axios.create({ baseURL: '/api/',})AI生成项目javascript运行六、正则表达式和字符串中的 / 与转义 在 JavaScript 正则表达式中,/ 是定界符,若路径中包含 /,需使用 \/ 进行转义。:const reg = /\/api\/user/; // 匹配 "/api/user"AI生成项目javascript运行 字符串中的 / 则不需要转义const url = "https://example.com/api/user";AI生成项目javascript运行七、结语 一个小小的 / 有这么多细节可以深挖, 是不是很有意思?如果你是前端开发者,理解 / 的这些细节能让你在写路径、调试接口、配置服务器、优化 SEO 时更游刃有余。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~————————————————原文链接:https://blog.csdn.net/RenGJ010617/article/details/147519939
-
JavaScript 中 throw error 与 throw new Error(error) 的用法及区别在 JavaScript 中,throw 关键字用于抛出异常。当代码遇到某些错误或异常情况时,可以通过抛出错误来通知程序,方便后续的错误处理。尽管 throw 的使用看似简单,但在实际开发中,许多人可能会对 throw error 和 throw new Error(error) 产生疑惑。这篇文章将详细讲解它们的用法与区别,并分析它们各自适合的场景。文章目录JavaScript 中 `throw error` 与 `throw new Error(error)` 的用法及区别作者简介猫头虎是谁?作者名片 加入我们AI共创团队 加入猫头虎的AI共创变现圈,一起探索编程世界的无限可能! 正文一、`throw error` 与 `throw new Error(error)` 的语法1. `throw error`示例:2. `throw new Error(error)`示例:二、`throw error` 和 `throw new Error(error)` 的区别1. 抛出的对象类型不同2. 错误信息和调试信息3. 适用场景4. 异常捕获和类型判断三、总结适用场景建议文末粉丝专属福利联系我与版权声明 作者简介猫头虎是谁?大家好,我是 猫头虎,AI全栈工程师,某科技公司CEO,猫头虎技术团队创始人,也被大家称为虎哥。我目前是COC北京城市开发者社区主理人、COC西安城市开发者社区主理人,以及云原生开发者社区主理人,在多个技术领域如云原生、前端、后端、运维和AI都有超多内容更新。感谢全网三十多万粉丝的持续支持,我希望通过我的分享,帮助大家更好地掌握和使用各种技术产品,提升开发效率与体验。作者名片 博主:猫头虎全网全平台搜索关键词 猫头虎 即可与我建联作者微信号:Libin9iOak作者公众号:猫头虎技术团队更新日期:2025年04月24日欢迎来到猫头虎的博客 — 探索技术的无限可能!加入我们AI共创团队 猫头虎AI共创社群矩阵列表:点我进入AI共创变现社群入口专区:https://bbs.csdn.net/topics/617720781点我进入CSDNWF万粉博主变现入口专区:https://bbs.csdn.net/topics/617717169加入猫头虎的AI共创变现圈,一起探索编程世界的无限可能! 正文一、throw error 与 throw new Error(error) 的语法1. throw errorthrow error;AI生成项目javascript运行1在这个语法中,error 可以是任何类型的值,通常是一个对象、字符串、数字、或其他类型。最常见的是 Error 对象。示例:let error = 'Something went wrong';throw error;AI生成项目javascript运行2. throw new Error(error)throw new Error(error);AI生成项目javascript运行1在这个语法中,我们通过 new Error() 创建了一个新的 Error 对象。Error 对象是 JavaScript 内置的一个类,通常用于表示程序中的错误。通过构造函数 Error 可以将一个错误消息传递进去,并生成一个包含错误信息的对象。示例:throw new Error('Something went wrong');AI生成项目javascript运行1二、throw error 和 throw new Error(error) 的区别尽管它们都可以用来抛出异常,但 throw error 和 throw new Error(error) 有一些细微的区别,了解这些区别能帮助我们选择合适的用法。1. 抛出的对象类型不同throw error:error 可以是任意类型的值,不一定是 Error 对象。比如,你可以抛出一个字符串、数字、数组等。let error = "This is a string error";throw error; // 可以抛出字符串AI生成项目javascript运行throw new Error(error):new Error(error) 总是会抛出一个 Error 对象,通常会包含堆栈跟踪、错误信息等,这对调试非常有帮助。throw new Error("This is an Error object"); // 抛出一个 Error 对象AI生成项目javascript运行12. 错误信息和调试信息throw error:如果你抛出的是一个非 Error 对象(比如一个字符串或者数字),这意味着你失去了 Error 对象提供的额外调试信息(如堆栈跟踪)。let error = "An error occurred";try { throw error;} catch (e) { console.log(e.stack); // 在这种情况下,e.stack 是 undefined}AI生成项目javascript运行throw new Error(error):Error 对象自带堆栈信息,可以帮助开发者快速定位错误发生的地点。因此,它在调试时要比直接抛出其他类型的错误(如字符串)更有优势。try { throw new Error("Something went wrong");} catch (e) { console.log(e.stack); // 打印出错误堆栈信息,帮助调试}AI生成项目javascript运行3. 适用场景throw error:适合在某些情况下抛出自定义的错误信息,尤其是当你想要抛出特定的非 Error 对象时。例如,某些场景可能会用到一个简单的字符串错误消息来表示某种异常情况,但它缺少 Error 对象的附加调试信息。let error = "Invalid input!";throw error;AI生成项目javascript运行然而,使用 throw error 时你必须自己处理堆栈跟踪信息,或者明确知道错误不会影响调试。throw new Error(error):适合用于处理异常时,你需要明确知道发生了什么错误,并且希望程序能够包含更多的错误上下文信息,便于后期调试和错误追踪。尤其在开发过程中,推荐使用 throw new Error(error),因为它能提供更多的错误信息。try { throw new Error("File not found");} catch (e) { console.log(e.message); // File not found console.log(e.stack); // Stack trace, helpful for debugging}AI生成项目javascript运行4. 异常捕获和类型判断throw error:抛出的 error 可能是任意类型,因此在捕获异常时需要确保类型判断。例如,如果你抛出的是字符串,捕获后就无法像 Error 对象那样访问 stack 属性。try { throw "Something went wrong!";} catch (e) { if (typeof e === "string") { console.log("Caught a string error:", e); }}AI生成项目javascript运行throw new Error(error):抛出的始终是一个 Error 对象,因此你总是可以通过访问 message 和 stack 属性来处理错误。try { throw new Error("Something went wrong!");} catch (e) { console.log(e.message); // Something went wrong! console.log(e.stack); // Stack trace}AI生成项目javascript运行三、总结throw error 适合抛出任意类型的值,例如字符串、数字等,但这种方式会失去 Error 对象带来的堆栈跟踪和调试信息,不适合用在复杂的错误处理场景中。throw new Error(error) 推荐在大多数情况下使用,尤其是需要更多的错误信息和调试信息时。它提供了完整的 Error 对象,包含错误消息和堆栈信息,对于排查问题和调试非常有用。适用场景建议使用 throw error:当你只需要传递简单的错误信息,且不依赖堆栈跟踪时。使用 throw new Error(error):当你需要抛出一个包含详细信息的错误对象,尤其在进行复杂的错误处理或调试时。结论:为了保证代码的健壮性和可维护性,尤其是在复杂应用中,建议优先使用 throw new Error(error)。————————————————原文链接:https://blog.csdn.net/qq_44866828/article/details/147464763
-
找一个固定版本的SDK,安装好后把WEBVIEW2的文件解压到:109.0.1518.140目录就行我这里固定了这个版本,你放进去其他版本的文件也可以,里面要有:msedgewebview2.exe下载SDK:https://gitcode.com/open-source-toolkit/d7091/全解压,然后找到含(X32)这个BAT安装 不可直接双击exe文件安装,双击exe文件会安装edge浏览器而不是WebView2WebView2X32V109.0.1518.140安装脚本.bat再到C盘搜索109.0.1518.140目录,复到到软件下面就可以了================https://api.github.com/repos/xiaoyaocode163/Webview2_win7_109/zipball/main项目:https://github.com/xiaoyaocode163/Webview2_win7_109Microsoft Edge WebView2 | Microsoft Edge Developerhttps://developer.microsoft.com/zh-cn/microsoft-edge/webview2/这里下载右下角的:常青或固定版本,解压就能用了(要选X86架构)
-
已设置保存自动格式化 报错信息如下: Error: Could not warm up worker. Formatting a file for the first time may take longer than usual.Message: Cannot find module 'prettier-eslint' in paths '/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules.asar,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/node_modules,/data/storage/el1/bundle/pc_entry/resources/node_modules,/data/storage/el1/bundle/pc_entry/node_modules,/data/storage/el1/bundle/node_modules,/data/storage/el1/node_modules,/data/storage/node_modules,/data/node_modules,/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules.asar'Require stack:- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-amd.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-fork.js-Stacktrace: Error: Cannot find module 'prettier-eslint' in paths '/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules.asar,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/node_modules,/data/storage/el1/bundle/pc_entry/resources/node_modules,/data/storage/el1/bundle/pc_entry/node_modules,/data/storage/el1/bundle/node_modules,/data/storage/el1/node_modules,/data/storage/node_modules,/data/node_modules,/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules.asar'Require stack:- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-amd.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-fork.js-at Module._resolveFilename (node:internal/modules/cjs/loader:1128:15)at o._resolveFilename (node:electron/js2c/utility_init:2:3040)at Function.resolve (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js:776:20)at Ve (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:1:12766)at Zt (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:2:487)at /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:2:718 版本: 3.3.0提交: 04a931fff44505b3a0167976f2568755b9729a68日期: 2025-05-28T04:47:55.690ZOS: ohos arm64 HongMeng Kernel 1.9.5ICP备案: 黔ICP备20004760号-236A
-
报错信息如下: Error: Could not warm up worker. Formatting a file for the first time may take longer than usual.Message: Cannot find module 'prettier-eslint' in paths '/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules.asar,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/node_modules,/data/storage/el1/bundle/pc_entry/resources/node_modules,/data/storage/el1/bundle/pc_entry/node_modules,/data/storage/el1/bundle/node_modules,/data/storage/el1/node_modules,/data/storage/node_modules,/data/node_modules,/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules.asar'Require stack:- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-amd.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-fork.js-Stacktrace: Error: Cannot find module 'prettier-eslint' in paths '/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules.asar,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/node_modules,/data/storage/el1/bundle/pc_entry/resources/node_modules,/data/storage/el1/bundle/pc_entry/node_modules,/data/storage/el1/bundle/node_modules,/data/storage/el1/node_modules,/data/storage/node_modules,/data/node_modules,/node_modules,/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/node_modules.asar'Require stack:- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-amd.js- /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/bootstrap-fork.js-at Module._resolveFilename (node:internal/modules/cjs/loader:1128:15)at o._resolveFilename (node:electron/js2c/utility_init:2:3040)at Function.resolve (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/out/vs/loader.js:776:20)at Ve (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:1:12766)at Zt (/data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:2:487)at /data/storage/el1/bundle/pc_entry/resources/resfile/resources/app/extensions/rvest.vs-code-prettier-eslint/dist/extension.js:2:718 版本: 3.3.0提交: 04a931fff44505b3a0167976f2568755b9729a68日期: 2025-05-28T04:47:55.690ZOS: ohos arm64 HongMeng Kernel 1.9.5ICP备案: 黔ICP备20004760号-236A
-
我使用vue直接前端调用华为云obs上传文件服务传参,在文件管理里面我们需要用到版本控制的功能,需要拿到当前文件的versionId参数,但是我看到了BrowserJS语法没有返回这个参数,其他的都有,这是怎么回事,什么时候能更新一下返回值,或者有什么其他解决办法?
-
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Document</title></head><body> <button type="button" onclick="addRow()">添加</button> <button type="button" onclick="delRow()">删除</button> <div style="height: 50vh;"> <table> <thead><tr><td>表头</td></tr></thead> <tbody id="tb"></tbody> </table> </div> </body><script> function addRow(){ var html = '' for (let i = 0; i < 100000; i++) { html += '<tr><td>'+i+'</td></tr>' } document.getElementById('tb').innerHTML = html } function delRow(){ document.getElementById('tb').innerHTML = '' }</script></html>一段简单的表格添加行代码,为什么刚开始我在谷歌浏览器的任务管理器上看到的标签页内存占用是30M,然后点击添加后内存变成510M,点击删除后内存占用还有500M,而且刷新页面内存还是占用500M,想问下有没有解决方法(不使用虚拟滚动)。下图为内存占用情况
-
前言欢迎来到我们 JavaScript 学习之旅的第 24 天!今天,我们将踏入 JavaScript 世界中一个极其核心且强大的领域——对象(Object)。在 JavaScript 中,流传着一句“万物皆对象”的说法,虽然不完全精确,但足以说明对象的重要性。从简单的数据集合到复杂的程序模块,对象无处不在。理解对象,是掌握 JavaScript 精髓的关键一步。本文将带您系统地学习 JavaScript 对象的基础知识,包括它的概念、创建方式、属性访问与操作方法,并通过丰富的示例,助您打下坚实的面向对象编程基础。一、对象的概念:不止是“键值对”在现实世界中,一个“对象”通常指一个具体的事物,比如一辆车、一个人或一台电脑。这些事物都有其属性(如车的颜色、品牌;人的姓名、年龄)和行为(如车能跑;人能走、能说)。JavaScript 中的对象正是对这种现实概念的映射。1.1 什么是 JavaScript 对象?在 JavaScript 中,对象(Object)是一种复合数据类型,它允许我们将多个**属性(Property)和方法(Method)**封装在一个独立的实体中。属性(Property):是对象所拥有的特征或数据。它由一个键(Key)(也称为属性名,通常是字符串或 Symbol)和一个**值(Value)**组成。值可以是任何 JavaScript 数据类型,包括数字、字符串、布尔值、数组,甚至可以是另一个对象或函数。方法(Method):是对象能够执行的行为或操作。它本质上是一个值为函数的属性。可以将其想象成一个无序的**键值对(Key-Value Pair)**集合。// 示例:描述一个 'person' 对象let person = { name: "张三", // 属性:姓名 age: 30, // 属性:年龄 isStudent: false, // 属性:是否是学生 address: { // 属性:值是另一个对象 city: "北京", street: "中关村大街" }, greet: function() { // 方法:打招呼 console.log("你好,我是 " + this.name + "!"); }};AI写代码javascript1.2 为什么对象如此重要?组织性:对象允许我们将相关的数据和功能组织在一起,使代码结构更清晰、更易于管理。封装性:将内部细节隐藏起来,只暴露必要的接口(属性和方法),提高了代码的安全性和可维护性。灵活性:JavaScript 对象是动态的,可以在运行时添加、修改或删除属性和方法。表达力:能够非常自然地模拟现实世界中的实体和概念。二、创建对象的“魔法”JavaScript 提供了多种创建对象的方式,其中最常用的是对象字面量和 new Object() 构造函数。2.1 对象字面量 {}:最常用的方式对象字面量是创建对象最简单、最直观,也是最推荐的方式。它使用花括号 {} 来定义对象,并在其中包含零个或多个键值对。2.1.1 基本语法let objectName = { key1: value1, key2: value2, // ... methodName: function() { // 方法体 }};AI写代码javascript2.1.2 示例:创建一个 car 对象// 使用对象字面量创建一个 car 对象let car = { brand: "Tesla", // 品牌属性 model: "Model S", // 型号属性 color: "红色", // 颜色属性 year: 2024, // 年份属性 isRunning: false, // 运行状态属性 // 启动方法 start: function() { this.isRunning = true; console.log(this.brand + " " + this.model + " 已启动!"); }, // 停止方法 stop: function() { this.isRunning = false; console.log(this.brand + " " + this.model + " 已停止。"); }};console.log(car); // 输出整个 car 对象car.start(); // 调用 start 方法console.log("车辆运行状态:", car.isRunning); // 输出 trueAI写代码javascript优点:语法简洁、可读性高、性能较好。2.2 new Object() 构造函数虽然不如对象字面量常用,但你也可以使用内置的 Object 构造函数来创建对象,然后动态地为其添加属性和方法。2.2.1 基本语法let objectName = new Object(); // 创建一个空对象// 动态添加属性和方法objectName.key1 = value1;objectName.key2 = value2;objectName.methodName = function() { // 方法体};AI写代码javascript2.2.2 示例:使用 new Object() 创建 book 对象// 使用 new Object() 创建一个 book 对象let book = new Object();// 添加属性book.title = "JavaScript 权威指南";book.author = "David Flanagan";book.pages = 1096;book.isPublished = true;// 添加方法book.displayInfo = function() { console.log("书名: " + this.title + ", 作者: " + this.author);};console.log(book);book.displayInfo(); // 调用 displayInfo 方法AI写代码javascript比较:通常情况下,推荐使用对象字面量,因为它更简洁、更高效。new Object() 的方式在某些特定场景下可能有用,但日常开发中较少直接使用。三、访问、修改和删除属性/方法创建对象后,我们需要能够与其进行交互,包括读取、设置和移除它的成员。3.1 访问属性和方法JavaScript 提供了两种主要的方式来访问对象的属性和方法:3.1.1 点表示法(.)这是最常用、最直观的方式,只要属性名是有效的 JavaScript 标识符(不含特殊字符、不以数字开头),就可以使用点表示法。(1) 语法objectName.propertyNameobjectName.methodName() // 调用方法时需要加括号AI写代码javascript(2) 示例console.log(car.brand); // 输出: Teslaconsole.log(car.color); // 输出: 红色car.start(); // 输出: Tesla Model S 已启动!AI写代码javascript3.1.2 方括号表示法([])方括号表示法更灵活,它允许使用字符串(甚至是变量)作为属性名。(1) 语法objectName["propertyName"]objectName[variableContainingPropertyName]objectName["methodName"]() // 调用方法AI写代码javascript(2) 为什么需要方括号表示法?属性名是变量:当你需要通过一个变量来动态决定访问哪个属性时。属性名包含特殊字符:如果属性名包含空格、连字符 -,或者不是有效的标识符。属性名是数字(虽然不推荐,但有时会遇到)。(3) 示例let car = { brand: "BMW", "model-X": "X5", // 包含连字符的属性名 "engine type": "Petrol", // 包含空格的属性名 1: "First Gear" // 数字属性名};let propToAccess = "brand";// 使用方括号访问console.log(car["brand"]); // 输出: BMWconsole.log(car[propToAccess]); // 输出: BMW (使用变量)console.log(car["model-X"]); // 输出: X5 (访问含特殊字符的属性)console.log(car["engine type"]); // 输出: Petrolconsole.log(car[1]); // 输出: First Gear// 尝试使用点表示法访问特殊属性名会报错// console.log(car.model-X); // 这会被解释为 car.model 减去 X,导致错误或非预期结果// console.log(car.engine type); // 语法错误AI写代码javascript选择建议:如果属性名是有效的标识符且已知,优先使用点表示法,因为它更简洁。否则,使用方括号表示法。3.2 添加和修改属性/方法JavaScript 对象是动态的,你可以随时向现有对象添加新属性/方法,或修改已有属性/方法的值,只需使用赋值操作符 = 即可。let myComputer = { brand: "Apple", type: "MacBook Pro"};// 添加新属性myComputer.year = 2023;myComputer["screen-size"] = 16; // 使用方括号添加// 添加新方法myComputer.boot = function() { console.log(this.brand + " 正在启动...");};// 修改现有属性myComputer.type = "MacBook Air";console.log(myComputer);myComputer.boot();AI写代码javascript3.3 删除属性如果你需要从对象中移除某个属性,可以使用 delete 操作符。let user = { id: 101, name: "Alice", email: "alice@example.com", isAdmin: false};console.log("删除前:", user);// 删除 isAdmin 属性delete user.isAdmin;console.log("删除后:", user); // isAdmin 属性已不存在// 注意:delete 操作符只能删除对象的自有属性,不能删除原型链上的属性。// 它返回 true 表示删除成功(或属性不存在),返回 false 通常意味着删除失败(如删除不可配置的属性)。AI写代码javascript运行四、对象作为复杂数据结构对象的强大之处在于其值的灵活性。一个对象可以包含各种数据类型,包括其他对象和数组,这使得我们能够构建非常复杂和层次化的数据结构,以精确地模拟现实世界或应用程序的数据模型。let project = { projectName: "在线商城", startDate: "2024-01-01", teamMembers: [ // 属性值是数组 { name: "张三", role: "项目经理" }, // 数组元素是对象 { name: "李四", role: "前端开发" }, { name: "王五", role: "后端开发" } ], status: { // 属性值是对象 code: 1, description: "进行中" }, launch: function() { console.log(this.projectName + " 项目启动!"); }};console.log(project.teamMembers[1].name); // 输出: 李四console.log(project.status.description); // 输出: 进行中project.launch(); // 调用方法AI写代码javascript运行五、总结恭喜你!今天我们深入探讨了 JavaScript 对象的基础知识。通过本文,我们学习了:对象的概念:对象是键值对的无序集合,用于封装属性和方法,是 JavaScript 中组织数据和功能的核心机制。创建对象的方式:我们掌握了最常用的对象字面量 {} 和 new Object() 构造函数两种方法,并了解到前者通常是首选。访问属性/方法:学习了点表示法 . 和方括号表示法 [],并理解了它们各自的适用场景。操作对象:我们学会了如何动态地添加、修改和删除对象的属性和方法,体现了 JavaScript 的灵活性。对象的复杂性:认识到对象可以包含其他对象和数组,从而构建复杂的数据结构。对象是 JavaScript 编程的基石。在接下来的学习中,我们将继续探索对象的更多高级特性,如 for...in 循环遍历、构造函数、原型、ES6 Class 等。扎实掌握对象的基础,将为你的 JavaScript 之旅扫清障碍。———————————————— 版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。 原文链接:https://blog.csdn.net/Kiradzy/article/details/148240605
-
现在的情况是后端说桶里有视频,但没有返回回调 请问怎么解决呢?文档中也只说明了格式还有一些是否必填,没有具体例子。请问怎么解决呢 前端使用的是临时安全凭证的方法
-
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 的重要性日益凸显,掌握它的使用方法对于前端开发者来说是一项必备技能。
推荐直播
-
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步轻松管理成本,帮助提升日常管理效率!
回顾中
热门标签