使用GDI对象绘制UI时需要注意的若干细节问题总结
目录
1、一个bitmap不能同时被选进两个dc中
2、CreateCompatibleDC和CreateCompatibleBitmap要使用同一个dc作为参数
3、不能删除已经被选入DC中的GDI对象
4、使用完的GDI对象,要将之释放掉,否则会导致GDI对象泄漏
5、CreateCompatibleBitmap返回错误码8的原因及解决办法(用CreateDIBSection替换CreateCompatibleBitmap)
6、Windows开发人员必须要学会到微软MSDN上查看函数的详细说明
7、最后
C++软件异常排查从入门到精通系列教程(核心精品专栏,欢迎订阅,持续更新...)
https://blog.csdn.net/chenlycly/article/details/125529931C/C++实战专栏(重点专栏,专栏文章已更新480多篇,持续更新中...)
https://blog.csdn.net/chenlycly/article/details/140824370C++ 软件开发从入门到精通(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/category_12695902.htmlVC++常用功能开发汇总(专栏文章列表,欢迎订阅,持续更新...)
https://blog.csdn.net/chenlycly/article/details/124272585C++软件分析工具从入门到精通案例集锦(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/article/details/131405795开源组件及数据库技术(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/category_12458859.html网络编程与网络问题分享(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/category_2276111.html 我们在自绘窗口、给控件贴图、绘制文字时会使用到Pen画笔、Brush画刷、Bitmap位图、Font字体、Region区域、DC设备上下文等GDI对象,在使用这些GDI对象要注意一些细节问题,否则会出现一些绘制异常。本文结合多年的项目实践,给大家分享几个使用GDI对象的细节,以供大家借鉴或参考。
1、一个bitmap不能同时被选进两个dc中
我们在使用Pen画笔、Brush画刷、Bitmap位图、Font字体、Region区域等GDI对象绘制之前,需要将它们选进DC设备上下文中,然后通过DC去操作使用。
对于bitmap对象,使用示例如下:
// 先创建位图,然后将位图选进DC中,然后操作DC去完成绘图
HDC hMemDC = ::CreateCompatibleDC( hdc );
HBITMAP hMemBitmap = ::CreateCompatibleBitmap( hdc, rect.GetWidth(), rect.GetHeight() );
::SelectObject( hMemDC, hMemBitmap );
使用bitmap对象时,不能将一个bitmap同时选进两个dc中。
系统API函数SelectObject在MSDN上有明确的说明:

即一个bitmap不能同时被选进两个dc。这个问题我们之前遇到过,因为新手在编写GDI绘制的代码时代码不规范,创建的GDI资源没有释放,导致一个bitmap被选进了两个dc中,导致绘制有问题,始终达不到预期的效果。
2、CreateCompatibleDC和CreateCompatibleBitmap要使用同一个dc作为参数
我们在使用双缓冲绘图时会先创建一个内存DC和内存bitmap,如下:
// CreateCompatibleDC和CreateCompatibleBitmap使用的是同一个参数hdc
HDC hMemDC = ::CreateCompatibleDC( hdc );
HBITMAP hMemBitmap = ::CreateCompatibleBitmap( hdc, rect.GetWidth(), rect.GetHeight() );
但要注意,CreateCompatibleDC和CreateCompatibleBitmap两函数传入的dc对象必须是同一个。
有些人可能会将CreateCompatibleDC返回的dc对象,直接放到CreateCompatibleBitmap参数中,如下:
// 错误:CreateCompatibleBitmap使用CreateCompatibleDC返回的dc句柄
HDC hMemDC = ::CreateCompatibleDC( hdc );
HBITMAP hMemBitmap = ::CreateCompatibleBitmap( hMemDC, rect.GetWidth(), rect.GetHeight() );
这样会导致调用CreateCompatibleBitmap创建的位图是单色位图,只能绘制黑白颜色的效果。
MSDN上CreateCompatibleBitmap API函数说明页面,有下面一段说明:

大体意思是,当一个内存dc被创建时,初始拥有一个尺寸为1x1的单色的位图被选进去。如果这个新创建的内存dc(CreateCompatibleDC函数返回的dc),被用到CreateCompatibleBitmap的参数中用来创建bitmap,那么这个位图将是单色的位图,只能绘制黑白颜色的效果。
之前在开发截图功能时就遇到过,当时截图的背景始终是灰白色的,后来看到上述MSDN上说明才知道原因。
在这里,给大家重点推荐一下我的几个热门畅销专栏,欢迎订阅:(博客主页还有其他专栏,可以去查看)
专栏1:(该精品技术专栏的订阅量已达到570多个,专栏中包含大量项目实战分析案例,有很强的实战参考价值,广受好评!专栏文章持续更新中,预计更新到200篇以上!欢迎订阅!)
C++软件调试与异常排查从入门到精通系列文章汇总
https://blog.csdn.net/chenlycly/article/details/125529931
本专栏根据多年C++软件异常排查的项目实践,系统地总结了引发C++软件异常的常见原因以及排查C++软件异常的常用思路与方法,详细讲述了C++软件的调试方法与手段,以图文并茂的方式给出具体的项目问题实战分析实例(很有实战参考价值),带领大家逐步掌握C++软件调试与异常排查的相关技术,适合基础进阶和想做技术提升的相关C++开发人员!
考察一个开发人员的水平,一是看其编码及设计能力,二是要看其软件调试能力!所以软件调试能力(排查软件异常的能力)很重要,必须重视起来!能解决一般人解决不了的问题,既能提升个人能力及价值,也能体现对团队及公司的贡献!
专栏中的文章都是通过项目实战总结出来的,包含大量项目问题实战分析案例,有很强的实战参考价值!专栏文章还在持续更新中,预计文章篇数能更新到200篇以上!
专栏2:(本专栏涵盖了C++多方面的内容,是当前重点打造的专栏,订阅量已达220多个,专栏文章已经更新到480多篇,持续更新中...)
C/C++实战进阶(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/category_11931267.html
以多年的开发实战为基础,总结并讲解一些的C/C++基础与项目实战进阶内容,以图文并茂的方式对相关知识点进行详细地展开与阐述!专栏涉及了C/C++领域多个方面的内容,包括C++基础及编程要点(模版泛型编程、STL容器及算法函数的使用等)、数据结构与算法、C++11及以上新特性(不仅看开源代码会用到,日常编码中也会用到部分新特性,面试时也会涉及到)、常用C++开源库的介绍与使用、代码分享(调用系统API、使用开源库)、常用编程技术(动态库、多线程、多进程、数据库及网络编程等)、软件UI编程(Win32/duilib/QT/MFC)、C++软件调试技术(排查软件异常的手段与方法、分析C++软件异常的基础知识、常用软件分析工具使用、实战问题分析案例等)、设计模式、网络基础知识与网络问题分析进阶内容等。
专栏3:
C++常用软件分析工具从入门到精通案例集锦汇总(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/article/details/131405795
常用的C++软件辅助分析工具有SPY++、PE工具、Dependency Walker、GDIView、Process Explorer、Process Monitor、API Monitor、Clumsy、Windbg、IDA Pro等,本专栏详细介绍如何使用这些工具去巧妙地分析和解决日常工作中遇到的问题,很有实战参考价值!
专栏4:
VC++常用功能开发汇总(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/article/details/124272585
将10多年C++开发实践中常用的功能,以高质量的代码展现出来。这些常用的高质量规范代码,可以直接拿到项目中使用,能有效地解决软件开发过程中遇到的问题。
专栏5:
C++ 软件开发从入门到精通(专栏文章,持续更新中...)
https://blog.csdn.net/chenlycly/category_12695902.html
根据多年C++软件开发实践,详细地总结了C/C++软件开发相关技术实现细节,分享了大量的实战案例,很有实战参考价值。
3、不能删除已经被选入DC中的GDI对象
DeleteObject API函数中,有如下的说明:

即不能删除还在被选入dc中的GDI对象,需要选出后再删除,否则会导致绘制异常。
4、使用完的GDI对象,要将之释放掉,否则会导致GDI对象泄漏
在GDI对象使用完成后要将之删除或释放掉,如果不删除或释放,则会导致GDI泄漏。如果有GDI对象泄漏的代码被频繁地执行,会导致GDI对象在持续的泄漏,当GDI对象总数接近或达到1万个时,就会导致GDI绘图函数调用出现异常,出现窗口绘制不出来等问题,紧接着程序就可能会出现崩溃。很多Windows老程序员可能都遇到过类似的问题。
关于Windows进程的GDI对象数目上限的详细说明,可以查看我的文章:
从注册表看Windows系统进程GDI句柄及进程句柄数上限
https://blog.csdn.net/chenlycly/article/details/139565038 创建GDI对象的接口比较多,要用对应的接口去释放,比如使用CreateXXXXXX创建的GDI对象,使用完后,要用DeleteObject释放;调用LoadXXXXXX函数去加载图片资源,使用完后,也要用DeleteObject释放;调用CreateXXXDC创建的DC对象,使用完后,要用DeleteDC去释放;调用GetDC获取到的DC对象,使用完后,要用ReleaseDC释放。
调用不同的接口去创建或获取GDI对象,释放时也要调用对应的释放接口,不能混淆!在这里给大家大概地罗列一下:
| 创建或获取GDI对象 | 删除或释放GDI对象 |
| CreatePen/CreatePenIndirect(pen画笔对象)、CreateSolidBrush/CreateBrushIndirect(brush画刷对象)、CreateFont/CreateFontIndirect(Font字体对象)、CreateCompatibleBitmap(BItmap位图对象) | 对于Create出来的对象,要调用DeleteObject释放 |
| CreateDC/CreateCompatibleDC(创建DC对象) | 调用DeleteDC释放 |
| GetDC(获取DC对象) | 调用ReleaseDC释放 |
| LoadBitmap(加载Bitmap位图) | 调用DeleteObject释放 |
| LoadImage(加载图片资源) | 如果加载的是Bitmap位图,则调用DeleteObject释放; 如果加载的是Cursor光标,则调用DestroyCursor释放; 如果加载的是Icon图标,则调用DestroyIcon释放。 |
对于上面提到的创建GDI对象的API函数,在释放时该调用哪个接口,可以直接到MSDN上查看API接口的Remarks部分就会找到对应的说明。比如创建兼容位图的API函数CreateCompatibleBItmap,在Remaks部分的说明如下:

再比如加载图片的API函数LoadImage,其在Remarks部分的说明如下:

在调用Windows系统API函数遇到问题时,需要到微软MSDN帮助页面中查看API函数的详细说明(可能会给出调用函数时的注意事项,或者调用函数的示例代码等),在说明中可能会找到相关的原因!会使用MSDN,是一个Windows开发人员最基本的要求!
对于GDI对象泄漏问题的排查,首先到Windows任务管理器中看目标程序进程的GDI总数是否有异常(GDI总数特别大,好几千甚至接近10000个上限),然后再使用GDIView工具查看到底是哪一类GDI对象数量特别大:

基本可以确定该类对象有泄漏。然后去查看代码,检查每个操作该类GDI对象的地方,看看是否存在GDI对象使用完后没有释放。
使用GDIView工具查看具体是哪个GDI对象发生了泄漏。确定泄漏对象之后,需要去查看代码去排查GDI对象的泄漏点。但软件的模块多,代码量大,不好漫无目标地排查。可以尝试去找到复现问题的办法,根据复现问题的操作步骤和场景,猜测问题可能出在哪些代码块中,即缩小代码排查的范围。
关于如何使用GDIView去排查GDI对象以及项目问题排查实例,可以查看我之前写的文章:
深入探究 C++ 程序中的资源泄漏问题
https://blog.csdn.net/chenlycly/article/details/133631728使用GDIView工具排查GDI对象泄漏问题(常用分析工具)
https://blog.csdn.net/chenlycly/article/details/125399896使用GDIView工具排查GDI对象泄漏导致C++程序UI界面绘制异常的问题
https://blog.csdn.net/chenlycly/article/details/140731065使用GDIView工具排查GDI对象泄漏案例的若干细节总结
https://blog.csdn.net/chenlycly/article/details/141526436
5、CreateCompatibleBitmap返回错误码8的原因及解决办法(用CreateDIBSection替换CreateCompatibleBitmap)
之前我们在加载图片去绘制窗口时(比如将图片加载起来显示到窗口中),如果图片尺寸过大,会出现CreateCompatibleBitmap返回失败,即创建位图失败的问题。调用GetLastError获取调用CreateCompatibleBitmap失败的LastError值为8,查看该错误码的含义为:

即创建位图时需要对应的内存,而内存资源不足,导致申请内存失败,所以CreateCompatibleBitmap调用失败了。创建位图的示例代码如下:
HDC hDC = ::GetDC( NULL );
HDC hMemDC = ::CreateCompatibleDC( hdc );
HBITMAP hMemBitmap = ::CreateCompatibleBitmap( hdc, nBmpWidth, nBmpHeight );
比如我们要加载的图片尺寸为3000*3000,则需要的内存大小为:
图片的宽高相乘,得到图片的像素个数,每个像素占4个字节(R、G、B、Alpha各占一个字节),则创建这样尺寸的位图需要的内存为:
3000*3000*4 = 34MB
34MB的内存很大。
调用CreateCompatibleBitmap创建是DDB(Device-dependent bitmap)设备相关位图,创建该位图使用的是系统内核的分页内存,这是稀有资源,可能会出现内存资源不够用的情况。可以使用API函数CreateDIBSection去创建DIB(Device-independent bitmap)设备无关位图,这种方式下使用的是虚拟内存,基本就会出现内存不足的问题了。关于CreateCompatibleBitmap和CreateDIBSection的详细说明,可以查看我之前写的文章:
CreateCompatibleBitmap返回错误码8的原因及解决方案(使用CreateDIBSection替换CreateCompatibleBitmap)
https://blog.csdn.net/chenlycly/article/details/139586621
之前开发的截图功能,在部分机器上会频繁出现CreateCompatibleBitmap创建失败的问题,导致截图失败。后来就是用CreateDIBSection替换CreateCompatibleBitmap解决的。
使用CreateDIBSection创建位图的示例代码如下:
BITMAPINFOHEADER bmih;memset(&bmih, 0, sizeof(BITMAPINFOHEADER));bmih.biSize = sizeof(BITMAPINFOHEADER);bmih.biBitCount = 24;bmih.biCompression = BI_RGB;bmih.biPlanes = 1;bmih.biWidth = nImageWidth; // 位图的宽度bmih.biHeight = nImageHeight; // 位图的高度BITMAPINFO bmi;memset(&bmi, 0, sizeof(BITMAPINFO));bmi.bmiHeader = bmih;void* p;hBitmap = ::CreateDIBSection(cdc.GetSafeHdc(), &bmi, DIB_RGB_COLORS, &p, NULL, 0);
6、Windows开发人员必须要学会到微软MSDN上查看函数的详细说明
在调用Windows系统API函数遇到问题时,需要到微软MSDN帮助页面中查看API函数的详细说明。MSDN上可能会给出调用函数时的若干注意事项或限制条件(约束条件),或者给出调用API函数的示例代码可供参考,在函数说明中可能会找到引发问题的原因!会使用MSDN,是一个Windows开发人员基本要求!
除了去查看MSDN上的说明,在使用工具时遇到问题,可以尝试到工具的官网上查找官方的说明,比如我们有次在使用GDIView时排查GDI对象泄漏时始终无法定位问题时,就是到GDIView工具的官网上找到了问题的答案,相关问题说明可以去查看我之前写的文章:
到GDIView等工具官网上或者微软MSDN上查看文档化说明去解决问题
https://blog.csdn.net/chenlycly/article/details/126004453
7、最后
使用GDI对象去编写绘图的代码相对简单,但在编码过程中要注意上面讲到的若干细节问题。
相关文章:
使用GDI对象绘制UI时需要注意的若干细节问题总结
目录 1、一个bitmap不能同时被选进两个dc中 2、CreateCompatibleDC和CreateCompatibleBitmap要使用同一个dc作为参数 3、不能删除已经被选入DC中的GDI对象 4、使用完的GDI对象,要将之释放掉,否则会导致GDI对象泄漏 5、CreateCompatibleBitmap返回错…...
51单片机(STC89C52RC版本)学习笔记(更新中...)
文章目录 参考资料1. 准备工作1.1 win10配置51单片机开发环境1.1 Ubuntu配置51单片机开发环境问题1:mcs51/8051.h依赖于mcs51/lint.h问题2:提示找不到头文件mcs51/8051.h 2. 认识51单片机2.1 STC89C52单片机2.2 管脚图2.3 原理图2.4 按键抖动2.5 头文件说…...
七:仪表盘安装-controller node
一:工具、环境准备-controller node 二:OpenStack环境准备-controller node 三:安装服务-controller node 四:工具、环境准备-compute node 五:OpenStack环境准备-compute node 六:安装服务-compute node 七…...
C++设计模式之外观模式
动机 下图中左边方案的问题在于组件的客户和组件中各种复杂的子系统有了过多的耦合,随着外部客户程序和各子系统的演化,这种过多的耦合面临很多变化的挑战。 如何简化外部客户程序和系统间的交互接口?如何将外部客户程序的演化和内部子系统…...
显卡(Graphics Processing Unit,GPU)比特币挖矿
1. 比特币挖矿基本原理 比特币挖矿是通过参与比特币网络的共识机制——工作量证明(Proof of Work, PoW) 来完成的。具体来说,矿工通过不断尝试不同的哈希值,以解决一个难度逐渐增大的数学问题,从而验证交易并获得比特…...
【SARL】单智能体强化学习(Single-Agent Reinforcement Learning)《纲要》
📢本篇文章是博主强化学习(RL)领域学习时,用于个人学习、研究或者欣赏使用,并基于博主对相关等领域的一些理解而记录的学习摘录和笔记,若有不当和侵权之处,指出后将会立即改正,还望谅…...
CSS 动画效果实现:图片展示与交互
🌈个人主页:前端青山 🔥系列专栏:Css篇 🔖人终将被年少不可得之物困其一生 依旧青山,本期给大家带来Css篇专栏内容:CSS 动画效果实现:图片展示与交互 前言 在现代网页设计中,动态效果能够显著…...
【机器学习】—Transformers的扩展应用:从NLP到多领域突破
好久不见!喜欢就关注吧~ 云边有个稻草人-CSDN博客 目录 引言 一、Transformer架构解析 (一)、核心组件 (二)、架构图 二、领域扩展:从NLP到更多场景 1. 自然语言处理(NLP) 2…...
Linux权限机制深度解读:系统安全的第一道防线
文章目录 前言‼️一、Linux权限的概念‼️二、Linux权限管理❕2.1 文件访问者的分类(人)❕2.2 文件类型和访问权限(事物属性)✔️1. 文件类型✔️2. 基本权限✔️3. 权限值的表示方法 ❕2.3 文件访问权限的相关设置方法✔️1. ch…...
NineData云原生智能数据管理平台新功能发布|2024年11月版
本月发布 8 项更新,其中重点发布 2 项、功能优化 6 项。 重点发布 数据库 Devops - 数据生成支持多个数据源 NineData 支持在数据库中自动生成符合特定业务场景的随机数据,用于模拟实际生产环境中的数据情况,帮助用户在不使用真实数据的情况…...
Vue中控制组件的挂载位置
在 Vue 中,append-to-body“true” 主要用于一些第三方组件(如 Element UI 或 Ant Design Vue 中的弹出框、下拉菜单等)来控制组件的挂载位置。具体来说,当你设置 append-to-body“true” 时,它会将该组件的 DOM 元素插…...
查看docker容器日志
容器里面的服务运行报错了,要查看容器的日志 要查看 Docker 容器的日志,可以使用 docker logs 命令。以下是一些常见的使用方法: 基本用法 docker logs <container_name_or_id> 查看最近的日志 docker logs --tail 100 <contai…...
Apache Commons工具类库使用整理
文章目录 Apache Commons工具类库分类- commons-lang3字符串工具:StringUtils日期工具:DateUtils数值工具:NumberUtils对象工具:ObjectUtils数组工具:ArrayUtils异常工具:ExceptionUtils枚举工具࿱…...
力扣第89题 格雷编码
题目描述 格雷编码序列是一个二进制数字序列,其中的每两个相邻的数字只有一个二进制位不同。给定一个整数 n,表示格雷编码的位数,要求返回 n 位的格雷编码序列。 示例 1 输入: n 2输出: [0, 1, 3, 2]解释&#x…...
Linux C/C++编程中的多线程编程基本概念
【图书推荐】《Linux C与C一线开发实践(第2版)》_linux c与c一线开发实践pdf-CSDN博客《Linux C与C一线开发实践(第2版)(Linux技术丛书)》(朱文伟,李建英)【摘要 书评 试读】- 京东图书 (jd.com…...
解决Tomcat运行时错误:“Address localhost:1099 is already in use”
目录 背景: 过程: 报错的原因: 解决的方法: 总结: 直接结束Java.exe进程: 使用neststat -aon | findstr 1099 命令: 选择建议: 背景: 准备运行Tomcat服务器调试项目时,程序下…...
C/C++中的调用约定
在C/C编程中,调用约定(calling conventions)是一组指定如何调用函数的规则。主要在你调用代码之外的函数(例如OS API,操作系统应用程序接口)或OS调用你(如WinMain的情况)时起作用。如果编译器不知道正确的调用约定,那么你很可能会遇到非常奇怪…...
微信创建小程序码 - 数量不受限制
获取小程序码:小程序码为圆图,且不受数量限制。 目录 文档 接口地址 请求方式 功能描述 注意事项 获取 scene 值 请求参数 返回参数 对接 请求方法 获取小程序码 调用获取小程序码 总结 文档 接口地址 https://api.weixin.qq.com/wxa/get…...
springboot/ssm美食分享系统Java代码web项目美食烹饪笔记分享交流
springboot/ssm美食分享系统ava美食烹饪笔记分享交流系统web美食源码 基于springboot(可改ssm)vue项目 开发语言:Java 框架:springboot/可改ssm vue JDK版本:JDK1.8(或11) 服务器:tomcat 数据库&#…...
【Redis篇】 List 列表
在 Redis 中,List 是一种非常常见的数据类型,用于表示一个有序的字符串集合。与传统的链表结构类似,Redis 的 List 支持在两端进行高效的插入和删除操作,因此非常适合实现队列(Queue)和栈(Stack…...
19c补丁后oracle属主变化,导致不能识别磁盘组
补丁后服务器重启,数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后,存在与用户组权限相关的问题。具体表现为,Oracle 实例的运行用户(oracle)和集…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
电脑插入多块移动硬盘后经常出现卡顿和蓝屏
当电脑在插入多块移动硬盘后频繁出现卡顿和蓝屏问题时,可能涉及硬件资源冲突、驱动兼容性、供电不足或系统设置等多方面原因。以下是逐步排查和解决方案: 1. 检查电源供电问题 问题原因:多块移动硬盘同时运行可能导致USB接口供电不足&#x…...
Matlab | matlab常用命令总结
常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...
NXP S32K146 T-Box 携手 SD NAND(贴片式TF卡):驱动汽车智能革新的黄金组合
在汽车智能化的汹涌浪潮中,车辆不再仅仅是传统的交通工具,而是逐步演变为高度智能的移动终端。这一转变的核心支撑,来自于车内关键技术的深度融合与协同创新。车载远程信息处理盒(T-Box)方案:NXP S32K146 与…...
JavaScript 数据类型详解
JavaScript 数据类型详解 JavaScript 数据类型分为 原始类型(Primitive) 和 对象类型(Object) 两大类,共 8 种(ES11): 一、原始类型(7种) 1. undefined 定…...
Webpack性能优化:构建速度与体积优化策略
一、构建速度优化 1、升级Webpack和Node.js 优化效果:Webpack 4比Webpack 3构建时间降低60%-98%。原因: V8引擎优化(for of替代forEach、Map/Set替代Object)。默认使用更快的md4哈希算法。AST直接从Loa…...
苹果AI眼镜:从“工具”到“社交姿态”的范式革命——重新定义AI交互入口的未来机会
在2025年的AI硬件浪潮中,苹果AI眼镜(Apple Glasses)正在引发一场关于“人机交互形态”的深度思考。它并非简单地替代AirPods或Apple Watch,而是开辟了一个全新的、日常可接受的AI入口。其核心价值不在于功能的堆叠,而在于如何通过形态设计打破社交壁垒,成为用户“全天佩戴…...
前端中slice和splic的区别
1. slice slice 用于从数组中提取一部分元素,返回一个新的数组。 特点: 不修改原数组:slice 不会改变原数组,而是返回一个新的数组。提取数组的部分:slice 会根据指定的开始索引和结束索引提取数组的一部分。不包含…...
