普通视图
国行 iPhone Air 首发实测:跑遍运营商,eSIM 的坑我们帮你都踩了
重大更新:
今天苹果无线软件技术与生态系统 VP Arun Mathias 接受爱范儿采访时透露:未来将会在中国大陆推出快速转换功能,用户在设备端激活 eSIM 功能后,后续切换设备可以通过该功能把 eSIM 换到新设备上,无需再跑一趟营业厅。
过去的几天里,爱范儿拿到了国行版 iPhone Air,在广州多家营业厅深度体验了完整的中国大陆运营商 eSIM 开卡流程。我们还和多位了解 eSIM 业务的运营商人士做了深度沟通,咨询了大家关心的重点问题。
剧透一下,由于业务处在运行初期,加上政策限制,国行 eSIM 的总体体验并不是非常的理想、丝滑。但办理过程的效率还是不错的,在这里为接待我们的三家运营商工作人员点赞。
实体卡怎么转成 eSIM?
我们先去了广东联通总部营业厅,并按照要求携带了手机和编辑本人身份证。整个办理过程和实体 SIM 业务办理基本无异,提交证件,报上旧号码,工作人员就会在手机上写入 eSIM。
整个写入流程其实只用了不到 5 分钟左右,效率还是比较不错的。其它的时间主要是工作人员做介绍和我们签署协议,以及我们准备了很多问题给对方。相信随着工作人员办理经验积累,速度会更快。
过程中,我们需要在一些须知文书上签名授权,工作人员也会留存本人和身份证照片作为备案。
直到 eSIM 激活之前,我们的旧手机插着实体卡都还能用。一旦激活,实体卡就会立刻停机。
需要注意的是,虽然运营商在公告里说可以跨区域办理,但我们实际办理过程中,跨省 eSIM 转换业务还是不行的:我们编辑 A 的联通号码归属地北京,在广州的营业厅无法转换为 eSIM(所以换成了广州本地的编辑 B 来办理)。
这个体验,对于在北上广深等大城市漂着的朋友们,肯定是不太友好。如果你不在号码归属地生活,又要最快速度尝鲜 eSIM,恐怕只能回一趟归属地。
但根据我们的判断,运营商肯定不会一直守着不放。理论上,当 eSIM 业务正式铺开,政策也会更新,跨区域办理应该也会打开。
关于漫游和外卡?
在营业厅,爱范儿尽可能问了所有和漫游、外卡有关的问题,但遗憾的是由于业务上马太快,很多工作人员也无法做出完善的回答。我们能够确定的是:
首先,使用国行 iPhone Air 办理激活 eSIM 之后,出国漫游和过去实体卡一模一样,体验不会有可感差别。
- 外行 iPhone Air 确实无法写入和激活中国大陆运营商 eSIM 卡服务。
- 并且,国行 iPhone Air 在境内也无法写入外国运营商 eSIM 卡。
最后,关于国行手机在境外期间办理境外运营商的 eSIM 卡,这个问题不属于国内运营商能够回答的范畴,因此我们也没有得到答案。以及由于时间限制,我们还没来得及带着国行机型去境外实测开卡。
但根据之前的公开资料,国行 iPhone Air A3518 型号是全网通,频段支持覆盖全球主流国家和地区市场的运营商, 所以理论上应该可以到境外开卡。
换 eSIM 用不用变更套餐?
很多读者跟我们反映了套餐资费的问题。实际上完全不用担心。
首先,从实体卡到 eSIM 的转换,不收取额外费用。
不过,我们在某营业厅遇到了先收取 20 元工本费的情况,但办结后原路退回了,这可能是由于具体业务流程,或为了办理方便而导致。如果你在办理时也遇到类似情况,大可不必担心,理论上三大运营商都是不收费的。
其次,原套餐可以直接保留,不需要变更套餐/额外付费。包括宽带+手机卡的融合套餐,也都是可以保留的。
但是,如果你已经办理了 eSIM,后来又想转换回实体卡,则需要按照营业厅要求缴纳工本费。这是因为营业厅需要制作一张新卡,你之前已经停机的实体卡不可重新启用。
最后,我们也问了营业厅关于 Apple Watch/平板电脑一号双终端的情况,三家运营商都表示暂未收到相关通知,需要等到 iPhone Air 正式开售后才会有更新。因此对于这部分用户,如果你有强烈的一号双终端需求,我们的保守建议是等一等,持续关注运营商的公告。
手机损坏/换手机,eSIM 怎么迁移?
关于这一点,爱范儿从三大运营商的营业厅都得到了明确的答复:
无论你的 iPhone Air 需要维修,还是将来升级换机——只要你需要将 eSIM 迁移到新手机上,抑或暂时转换回实体 SIM 卡,你都必须「人机证合一」再跑一次营业厅线下办理……
届时,工作人员会协助你解绑 eSIM,办新的实体卡,或在新的 eSIM 手机上重新下载和激活 eSIM 卡。
这里需要注意的是,截至目前,三大运营商的补换卡政策是「每人每月最多可以补换卡 5 次」,而这个迁移卡的过程会消耗一个次数(原来的手机修好了,再迁移回来,也会消耗次数。)
开卡换卡过程是否顺滑流畅?
我们有一个编辑,之前办过十多张各个国家和地区的 eSIM 卡,在用的也有七八张。他已经是港行 iPhone Air 用户,手机里已经写了多张 eSIM 卡。
他认为,和海外运营商的 eSIM 注册、激活、切换体验相比,这台国行 iPhone Air 确实要折腾的多。
主要是因为在目前阶段,eSIM 业务办理与营业厅线下强绑定。而且,激活之后如果要迁移补换也很麻烦——可以想象,在 10 月 22 日国行 iPhone Air 正式发售当天以及之后的一段时间内,营业厅将迎接近年来罕见的高人流。
我们和多位一线办理人员及后台人员做了交流,他们表示,由于国行 iPhone Air 开售很突然,eSIM 手机业务上的太快,培训期限非常紧,难免出现不熟练的情况,希望用户能够理解包容。
在这里爱范儿想说的是:国行 eSIM 办理体验再不好,政策再不理想,也不是营业厅一线工作人员的错。他们和我们一样,都是打工人。如果你带着新机去营业厅,希望你对工作人员多体谅一点。
以上就是本次爱范儿使用国行 iPhone Air 的 eSIM 开卡体验。如果一句话抽象来总结,那就是「除了不方便的地方,其它都还挺方便的」……
如果视频和文字版没能回答你的更多问题,欢迎在评论区留言,我们的多位编辑会在线回答!与此同时,如果你对 iPhone Air 本身感兴趣,可以看我们之前的评测视频《iPhone Air 的 4 个亮点和 6 个代价》。
联合作者:马扶摇,张展毓,乔纳森何,杜晨
#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。
iPhone Air 港版评测:瘸腿是真瘸腿,好看也是真好看
虽然今年的 iPhone 17 标准版与 iPhone 17 Pro 系列都迎来了非常大的提升,但铝合金无论热性能再怎么优异,在质感和观感上始终都和苹果已经在 Apple Watch 上实验过的抛光钛金属工艺相差甚远。
而今年如果想要在 iPhone 产品线里买到钛金属的机型,就只剩下 iPhone Air 这一支独苗了。
从某些角度来说,iPhone Air 和当年的 iPhone X 有点像——它们都用着全新的硬件设计,处在硬件重大变革的前夜,让一部分愿意冒险的用户提前体验到了未来的感觉。
甚至于,在使用体验方面,iPhone Air 都和 iPhone X 有几分类似:这个硬件非常迷人,这个体验非常忐忑。
不过今年大陆国行版本的 iPhone Air 推迟发售,爱范儿手中的这台 iPhone Air 并非正式的评测样机,而是编辑部一位小伙伴自购的港版日用机。
正因如此,爱范儿需要对本篇评测做出如下免责声明:
本文是基于港版 iPhone Air 的使用体验,并非购买建议,有关网络制式、运营商开卡等信息,请以爱范儿后续国行版本 iPhone Air 评测为准。
初体验:轻轻轻轻轻
虽然苹果取消赠送充电器这件事一直以来都是被反复批评,但是当我们打开 iPhone Air 外盒的那一刻,突然感觉到或许只有它才真正适合这种薄薄的包装盒。
虽然在 9 月 10 号凌晨的现场体验中,爱范儿为大家转播了位于发布会现场的同事将 iPhone Air 拿上手的体验,然而很多细节的确只有在把真机拿在手上才能体验到:
比如这个抛光钛金属的边框,相比 iPhone 17 Pro 系列的一体成型铝合金中框,拿在手上会有一种「更温润」的体验——虽然在客观事实上,这是由于钛的导热性不如铝导致的。
更重要的是,在热导性能之外,抛光钛金属第一眼看上去就是要比磨砂铝合金更精致和高级,这种能够看到光线沿着金属表面流淌的观感,就像在看一辆停在展厅里的概念车一样——
只不过这种高级感的前提,一定得是在边框干净的前提下。
今年 iPhone Air 的抛光钛金属边框,和前两年 Pro 机型上使用的「手术级不锈钢」面临着一模一样的问题:只要手碰到就会弄脏、只要弄脏就会显得邋遢。
iPhone Air 作为一款 6.5 寸屏幕的手机,虽然并没有对此前的 Plus 机型形成彻底的替代,但是结合它 165g 的重量,仍然是近两年难得一见的「又大又轻」的直板手机。
正如我们在上个月的一篇硬哲学中提出的:小屏会死,轻薄永存。iPhone 13 mini 那样极端的尺寸,在如今的内容生产和消费环境中已经不再适配了。
反而是像 iPhone Air 和 S25 Edge 这样的「轻薄大屏」会成为另一股不可忽视的潮流。
因为哪怕算上各种轻薄的折叠屏手机、甚至是可折叠平板,iPhone Air 依旧是我们几年以来体验到的,手感最接近「把一整块纯粹的屏幕握在手里」的真正的「明日产品」。
至于 S25 Edge 为什么感觉不像明日产品,原因很简单——
它的装甲铝边框几乎是直上直下的,没有任何圆弧过渡,握在手里不仅触觉上更厚重,也让人很难忽视掉边框的存在。
用起来:瘸瘸瘸瘸瘸
当我们真正迁移了微信聊天记录、开始使用 iPhone Air 的时候,很难不去想到它内部那块容量仅仅 3149mAh 的超薄钢壳电池。
因此,我们有必要把最近几十个小时的实际感受放在最前面:
iPhone Air 的续航虽然不优,但也的确没有我们预想中的那么差劲,在日常的使用强度中,它的掉电速度其实和使用了一年之后的 iPhone 16 Pro 差不多。
除此之外,根据购物网站和科技论坛上的各种反馈我们可以看到,今年选择升级 iPhone 17 系列的用户群中,有不少 iPhone 12、13 代 Pro 机型的老用户。
其中,iPhone 12 Pro 的电池容量为 2815mAh,「十三香」的 iPhone 13 Pro 电池容量为 3095mAh, 即使 iPhone 14 Pro 也只有 3200mAh。
——这样一比,iPhone Air 的电池容量实际上并没有那么不堪。
更重要的是,今年的 A19 Pro 处理器在能效方面的进步很明显,iPhone Air 能够同时吃上 SoC 能效高和 LTPO 可变刷新率省电两项红利,对于那些升级上来的老用户来说,体验其实不会有特别明显的缩水。
只不过 iPhone Air 作为迄今为止形态最激进的 iPhone 之一,在实际使用中其实还是面临着一些问题的。
首先,由于 iPhone Air 尚未在大陆开售,我们平时使用的很多国产 app 还没有针对 iPhone Air 位置下移的灵动岛做出适配,存在界面和控件 bug:
不是切掉搜索框,就是顶部 banner 错位,航旅纵横的灵动岛彩蛋都露出来了
其中的绝大多数虽然不影响使用,但很影响观感,并且用户也没有什么修正的办法,只能等待 iPhone Air 在国内正式开售之后由软件开发商慢慢处理了。
其次,iPhone Air 的单扬声器也是一个无法被「选择性忽视」的问题。
通过微机分的拆机视频我们可以看到,iPhone Air 顶部的「高原」内部足足三分之一的空间被让渡给了扬声器:
图|哔哩哔哩 @微机分WekiHome
并且 iPhone Air 没有传统意义上的扬声器开孔,背部高原里的扬声器虽然尺寸不小,但唯一的出声孔只有顶部的微缝听筒,哪怕有足够的低频,也会被过滤得七七八八。
因此至少在影音娱乐角度来看,iPhone Air 还是更适合那些在家有音箱、出门戴耳机的人群。
事实上,我家的 HomePod mini 原本因为买了条形音响吃灰了好久,反而在我开始用 iPhone Air 之后焕发新生了。
最后,就是 iPhone Air 的散热问题。
虽然 iPhone Air 使用的 A19 Pro 处理器相比 iPhone 17 Pro 系列砍了核心,但整体的能耗并没有显著的变化,使用中依然是会发热的。
并且由于 iPhone Air 内部的堆叠密度更高、钛金属更不容易散热,以及 Air 体积小导致的机身热容量小,这几天用下来的感受是毋庸置疑偏热的。
不过轻薄也有轻薄的优点——
虽然 iPhone Air 有点像 iPhone 15 Pro 那样「火龙果」,但机身热容量小也就意味着它降温很快,从室外走进室内不一会就会恢复正常温度。
并且 iPhone Air 紧凑的布局和较大的机身还有另一个好处:它的主板位置很高,SoC 更是压在「高原」正下方,正常握持姿势下其实很难摸到背部最热的区域,热感不像 iPhone 16 Pro 那么明显。
只不过综合看下来,在 2025 年这样一个手机越来越厚重、但也越来越全能的时候,iPhone Air 的使用体验无疑是非常「偏科」的——
换个说法,其实也就是瘸腿。
但偏科也好,瘸腿也罢,对于那些已经下定决心买 iPhone Air 的人来说,肯定都是事先就知情的,毕竟 iPhone 不会把闪光灯做成和镜头一样的黑色圆圈、然后放在镜头旁边——
尤其是在我检查了一遍去年的 iCloud 相册、发现绝大多数我用 iPhone 16 Pro 拍出来的照片都是主摄和主摄裁切之后,iPhone Air 的单摄也就没有什么不能接受的了。
eSIM:难难难难难
在聊完硬件之后,我们就不得不面对房间里面的大象了:
iPhone Air 搭配 eSIM,究竟应该怎么用?
由于大陆国行版本的 iPhone Air 仍未开售、国内运营商的政策也未实际落地,因此这里不展开讨论有关 eSIM 的细节,我们只说今年港版 iPhone 的 eSIM 策略。
中环国际金融中心 Apple 店|苹果官网
在 iPhone 17 之前,港版 iPhone 与国行 iPhone 一致,使用的都是双实体 SIM 卡的组合,不支持添加 eSIM。
但是今年,港版的 iPhone 17 系列(除 Air 外)都改成了单实体卡 + eSIM 的方案,与其他大部分国际版一致。
而港版的 iPhone Air(A3517)则有些特殊:它虽然支持安装八九张 eSIM 卡,但不支持安装大陆运营商的 eSIM,因为国行官网写了大陆 eSIM 仅能在国行 iPhone Air(A3518)机型安装。
因此如果你和编辑部的这位同事一样,选择购买港版的 iPhone Air,那么即使在后续国行开售、三大运营商开通 eSIM 业务之后,也是不能去办理开卡的。
这就要求你必须拥有港澳台或者其他国际地区的 eSIM 套餐,并且这些套餐还要开通漫游,才能在大陆区域正常的使用移动网络,否则你的 iPhone Air 就是一台超大号的 iPod Touch。
更加需要留意的是,哪怕你在使用港澳或者国际运营商的 eSIM 服务,除了资费贵之外,它也不见得就比实体 SIM 卡更方便——
比如这位同事正在使用的香港运营商,在把 eSIM 从 iPhone 16 Pro 转移到 iPhone Air 上的时候,要收足足 28 港币的「重新发卡费」,并且还需要重新登记身份信息,最终前后花了四十多分钟才连上网。
并且除了转移困难(甚至要收费)之外,eSIM 的漫游资费、不同运营商支持的频段、在大陆能够连上谁家的基站,都是相当随缘的。
总之对于现阶段,如果你已经是 eSIM 用户,那么选购港版 iPhone Air 或者其他型号没什么问题。
但如果你单纯只是想早点用上 iPhone Air 就冲港版,遇到的麻烦和需要的精力将远远大于 iPhone Air 本身带来的兴奋。
总结:让子弹飞一会
那么在真正使用过一段时间的 iPhone Air 之后,我们的感受如何呢?
爱范儿认为:iPhone Air 是一台近年来很少见的,象征意义大于实用意义的智能手机。
或许正是今年的 iPhone 17 和 iPhone 17 Pro 都罕见地务实,让苹果必须要在 iPhone Air 身上,实现一些极限的设计指标。
换句话说,iPhone Air 对于形态的探索,突破了最基础的「手机工具属性」,你花钱买 iPhone Air 本质上更像是在买一种新鲜的体验。
iPhone Air 注定不适合 95% 的人,它身上「为折叠屏试水」的痕迹太明显了,甚至连我也感觉自己并不完全符合 Air 的用户画像。
但如果你在家有音响、出门有车充、拍照有相机、每天手机屏幕使用时间不超过三四小时,智能手机对于你来说只是一个基础的交流工具和电子钱包,你在手机之外仍然能够拥有丰富的活动——那至少对你来说,iPhone Air 还是非常值得一试的。
#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。
东北地区首单公募REITs成功发行
孟加拉国首都达卡国际机场货站火灾致机场航班暂停
大国工程新进展 金沙江昌波水电站成功截流
印度加快进口俄罗斯石油速度
日本政府拟提高签证申请手续费
暧昧但不确立关系,年轻女孩们困在situationship里
从性开始
男生的身高超过180,一身黑色衬衫、黑色裙裤,及肩长发扎成了马尾,慢悠悠地朝铁门口走过来。
远远地,21岁的小树看到这个瘦高的人影就“猜到是他”。男生是她在tinder上划到的,已经聊了快两个月。小树看过他在软件主页上放出的个人照片——长相,完全的理想型,简介也没有雷点。他初中就去美国读书了,优越的家庭条件让小树觉得两人无法相配。即便如此,她还是抱着“追星”的心态想见他一面,因为“我在现实生活中还没有见过这么帅的男生”。
见到真人她却有点害羞。下意识地,她害怕对方嫌弃自己的外表,往地铁口的阴影里躲了躲,哪怕延长一秒让她晚点面对他也好。但男生应对如常。第一次的约会,他们去了酒吧聊天,一个半小时后转场去KTV唱歌。
在酒精和音乐的加持下,他们之间的距离被不自觉地拉近,然后是接吻,然后是酒店……所有事都发生在4个小时以内,“就像缘分一样,一切自然而然地发生了。”小树说。
这就是小树人生中的第一段situationship。
在《牛津英语词典》里,situationship一词的官方解释是——“一种缺乏明确标签或承诺,但存在一定程度情感和/或性亲密的关系。”看定义,他们的关系完全符合。
对于感情经历稀薄的小树而言,初次见面关系推进就如此迅速,连她自己也觉得不可思议。
男生有一种让小树安心到卸下防备的阴柔气质。“不像跟其他男生在一起的别扭,跟他在一起的时候我一点都不紧张,莫名地有一种安全感和松弛感。”小树说。以至于这个晚上,她情不自禁地想说出自己家里“那些破事”,好像对他已经完全信任,“那时我觉得他对我也滋生了一种保护欲,我想他一定是喜欢我的。”
当situationship这个词远渡重洋来到中国,越来越多国内年轻人们都开始接纳和实践类似的新型情感关系。尤其是,主动选择不恋爱、只situationship的女生越来越多。在社交媒体搜索“situationship”,许多女孩都记录了自己的situationship经历和想法。
但涉及到对这种关系的具体定义和表现,大家却很难达成一致。最关键的是,这种关系实在太像一种美化版的“约炮”。连小树自己也觉得很像。
29岁的叁贰更直接,她一开始就是冲着与situationship强绑定的肉体关系来的。
从今年5月开始叁贰实践了这段新型关系,但直到男生和她明确situationship的关系定位前,她也依然觉得两人是纯“炮友”。他们会在每个周末见面,做爱,这样的“周末关系”持续了7次。
图片来源《他其实没那么喜欢你》截图
但叁贰又觉得这其中有说不清道不明的超出炮友的成分——除去性关系,他们还会一起健身、买菜、做饭、散步、逛商场,一起讨论感兴趣的电影或社会话题,给予对方陪伴。她发现自己对对方除了身体的渴望之外,还有情感的依恋。而这种相处模式,也完全符合叁贰理想中和伴侣的相处模式。
于是在国内年轻人中,situationship这个舶来品就变成了多种“非正式关系”的统称,一种炮友以上、恋人未满的模糊状态。
转正的博弈
海外的约会文化中,situationship通常是初始阶段,理论上说,这一时期,男女双方与多人约会且有性关系,都是完全合理的。只有当关系深入到relationship——也就是谈上恋爱后,双方才进入到保持1V1的排他性关系的阶段。
换句话说,人可以同时保持一段或多段暧昧关系,并同时是单身。
《Tinder2022年度报告》显示,会员信息中填写单身的比例增加了49%。由此可见situationship的优势:操着单身人设,也能同时享受来自一位或多位异性的照拂。许多年轻人都呈现出“薛定谔的单身”状态,他们也表示自己更喜欢situationship,因为这样的关系压力更小,且,这是一种“有效的关系”。
图源小红书@8 4 15
劣势就也很明显了——
当男女双方都止步、且满足于这种温水煮青蛙的状态时,两人都能只享受亲密关系带来的温存,而不履行其需要的承诺。
但大多数人在天平上都不是对等的。那些主动选择situationship的女孩,似乎也并没有对外展示的那般潇洒。事实是,困在situationship里的女孩,越来越多了。
在持续了两个多月“纯炮友”的日子后,叁贰在2025年8月成为了主动终结关系的那个人。她给对方发了信息:“过去的这段时间很美好,但我现在真的没有时间和精力去运营一段关系,祝你未来一切都好。”
虽然是由她发起的结束,原因却是——她发觉自己已经越陷越深。明明自己是在享受这种陪伴,她的内心却越来越痛苦。
二人是以“炮友”开始的,在认识之初,他们就明确了除对方之外还会接触其他的异性。但,当叁贰对男生产生情感依赖后,她对这个前提条件越来越无法忍受。渐渐地,那些甜蜜时刻带来的多巴胺反馈,已经比不上对方若即若离和忽冷忽热所带来的伤害。
起初的叁贰并不在意对方是否回复消息,后来却是,“他一不回我,我就觉得他应该是在发展别的关系”。她意识到,自己在这段关系中开始排外了。“既然这段关系无法再更进一步,就不要让它继续扰乱我的精力。”叁贰说。她发出了分手通知,不久,男生回复到,接受这样的分开,也祝她一切都好。叁贰随即删除了对方的联系方式。
Situationship实在太考验双方对自己情感的掌控力。尤其是女生这一侧,当肉体亲密关系产生时,能做到性爱分离的人太少,似乎抽身也总比另一方更痛苦一些。
26岁,刚结束4个月situationship的CC同样深受其害。
和这位男生同样是在社交软件上认识的。聊了大概一个月,两人发生了关系,之后,CC对男生的依赖程度越来越高,“是激素的影响”,她这么觉得。潜意识里她已经完全把对方当成男朋友对待,可另一边,男生对CC的态度却急转直下,消息不回,约见面也难。CC也质问过男生为什么前后态度差距这么大,对方却回答,“你想多了,我一直都是一样的。”
图片来源《他其实没那么喜欢你》截图
那段时间里,CC的内耗已经影响到了正常的工作和生活。她选择跟男生“来个了断”,特意挑了一个周末把男生约了出来。问对方:我们到底是什么关系。男生却回答:“我们是好朋友+亲密关系。”CC提出了转正成恋爱关系的要求,男生很干脆地拒绝了。
这段关系也随着对话一起结束了。一切停留在男生的最后一句话:“有点后悔了,早知道这样当初就不该开始。”
本质上,situationship就是一种男女权力关系的博弈,产生“转正”想法的一方,已经输了。
晚婚的“副产品”
这种不清不楚的动态平衡,是基于都市年轻男女的新世代需求出现的。
像复旦大学社会学系副教授沈奕斐在《社会学爱情思维课》中说的,随着年轻人的经济水平和人格越来越独立,他们不愿意过早被婚姻捆绑,陷入房子、车子、孩子等复杂琐碎的事务中去。面对人性的不确定性、婚后角色变化的恐慌,许多人会患上“承诺恐惧症”,不愿意用恋爱的关系来绑定不可知的未来。
谈恋爱,就意味着双方要向彼此履行承诺,承担责任,甚至最终走向婚姻。但在situationship里只需要享受当下的快乐,就算这是一种“有毒”的甜蜜,也成了年轻人们的最优选。
26岁的设计师小麦已经习惯了用situationship做婚姻的挡箭牌。
她的这段situationship已维系了近三年。他们始终没有确立恋爱关系,但也始终没有断了联系。
在小麦看来,男生“人很好,很阳光”,不像以前她接触的那些“大谈艺术”的空洞的男生。疫情期间他主动把自己积攒的抗原给她送了过来,在她生病时给她买小蛋糕,两人维持着稳定的联络,互相关心支持。但男生大她5岁,已经到了被家里催婚的年龄,“他就觉得只要是谈恋爱,一定是冲着结婚去的。他也明确和我说了。”
对工作刚走上正轨的小麦来说,结婚是件太遥远的事。更何况如果用结婚对象的标准来考察对方,曾经觉得他有很多的优点,也马上就被密密麻麻的细小缺点盖过了,从住所混乱,到旅游时没有规划……记忆里的甜蜜全都变成了压力。一次,男生告诉小麦,他二舅母打电话催他结婚,说“岁数再大了,生出来的孩子像小耗子(营养不良)”,这无形中给小麦增添了更多压力。
因此,将这段关系维持在“不谈”的状态让她更有安全感,也不会带给男方多余的幻想。
图片来源《关于约会的一切》截图
事实上,东亚年轻人晚婚已然成为了一种趋势。以隔壁韩国为例,根据韩国统计局的数据,韩国女性的初婚年龄早在2016年就突破了30岁,2022年,30-34岁成为韩国女性最主要的初婚年龄段。国内同样如此,年轻人的初婚年龄在逐渐推迟,北上广深等一线城市的平均初婚年龄也达到了30岁以上。像小麦所说,“还没玩够呢,不着急。”
有一次她也问过男生,“咱俩算什么关系?”对方回答:“咱俩不搭子吗?”她想了想觉得,有一个固定搭子,待在一起很开心也不错,“至少在想要结婚以前,用这种非正式的相处方式做过渡,挺好的。”
差一口气的relationship
像小麦一样,不内耗于situationship的女孩,确实也是少数。
转正被拒的CC,冷静下来后才开始复盘两人之间的关系。
随即,许多原因出现在脑海里,而最首要的——他们未来不会在同一座城市生活,她绝对无法接受异地。想到这里CC顿时觉得,自己这场“转正的博弈”是没有意义的。同样,对方的视角也是如此。
尤其是对这些一线城市高流动性的年轻人来说,连自身都充满着不可知的变数,就更不用说和他人缔结长久的正式亲密关系。
在叁贰看来,这种说不清楚的关系带来的痛苦是远大于快乐的。在这段长达三个月的非正式关系里,她已经耗费了太多的精力,“我宁愿正经谈个恋爱”。最后,她和situationship对象重新联系,还是确立了正式的恋爱关系,她也说,自己以后再也不会尝试situationship了。
终究,过渡状态只是迫不得已,甜点也不能当正餐吃。之所以选择situationship,还是因为谈一场正式的恋爱太难了。
在一线城市,普遍的情况都是——婚恋市场上一直呈现出女多男少的结构。根据西南百合数据中心的统计,2024年一线城市相亲市场,男女比例严重失衡,最夸张的成都市,男女比例甚至达到了1:43。
很多时候,合适的男生往往早被别人"抢走",而一眼心动的对象又总是不愿意确立恋爱关系,毕竟,"人家也没玩够",不想被买车、买房、彩礼等困扰。结果就是,留给不少都市女性的选择大多是:奔着结婚的目的去相亲市场上“找队友”,或者,在交友软件上找到了这些“不负责任”的短择对象。
结束一段situationship后,女生们还是只能自己调节,走出这种复杂的体验。
CC还是情不自禁总会想起那个男生,她不停看书、听博客,强迫自己走出来。她将自己对这段关系的思考发布在社交媒体上,不少受到情伤的女生都有共鸣。随后她组建了一个situationship互助群,大家在群里相互分享、安慰,劝诫彼此要更爱自己,关注自身成长。不过,群里的女生并不全是situationship,有很多人是女追男,男的吊她们,再后来,群里渐渐没人说话了。
CC也试过跟一些有situationship经历的男生聊天,了解男性视角下的关系定位。聊下来她总结,会尝试situationship的男生主要分为三种类型:
1、看不上女方型:只能保持这种关系,对方达不到他的期望。
2、不想被束缚型:觉得女友会管控他,压力大。
3、渣男型:非1v1关系,长期多线程。
“最后这种最离谱,不知道哪来的魅力。”CC说。她想,接下来自己还是会积极寻找一个可以长久相处的对象,“但如果一直找不到,我大概还是会尝试这种关系。”
本文来自微信公众号“后浪研究所”,作者:朱青翊、许嘉婧,36氪经授权发布。
卖价过万的「大头娃娃」,成了「痛系」年轻人的新型奢侈品
人类的头围通常在55~60cm之间。但神奇的是,70~80cm的卡通大头戴在人体上也毫不违和。
最近,越来越多年轻人迷上了这种二次元风格的玩偶服、头壳,把自己变成“行走的娃娃”。
他们被称作“kig玩家”,全称“kigurumi”,这是个日语舶来词,意为“把娃娃穿起来”。就算是身高1米8的男性,只要定制合适的头壳,也可以把自己变成大眼睛萌妹。
它不属于二次元,也不属于三次元,他们是2.5D的存在。和cos圈不同,有一种对kig的最直观理解:“cosplay是在用三次元表现二次元,但kig是把二次元直接抠到三次元,像是手办一样。”
也可以说,kig是一种门槛更低的cosplay——玩家不需要化妆,他们的真实面孔不被展示;也不需要完美的身材,他们会穿上一层肉色紧身衣,遮盖每一寸裸露的肌肤。这一切都是为了做到隐去自我,还原角色,把喜欢的二次元角色带入现实世界。
在国内,这还是个小众前卫的领域,但价格超过想象。单是一个kig娃娃头壳,行业内的均价就在3000元左右,头部商家甚至能卖6000到上万元。
当过去的小众ACG文化把谷子、痛楼赤裸裸地摆在大众面前,眼见二次元赛道入局人增多,市场转向一片红海,但总有一些人狙击到更小众的细分市场,找到新的蓝海。就像这家kig头壳定制服务店——偶域KIGLAND,成立一年多就拿到了奇绩创坛种子轮融资。
年轻人玩的东西,越来越让人看不明白了。
只要998
偶域的第一次市场亮相,就给2024年的kig圈带来了一个轰动的大新闻:998!全场只要998!这是他们的首个“圈内大火”的COSPLAY头壳——葱绿色双马尾的元气少女。
淘宝评论区卖家秀上身效果
获得这样一个头壳只需998块钱,什么概念?
一位入kig坑5年的资深玩家洋子告诉我,3000元是这个行业的基准线。2022年她买的第一个BJD娃娃风格头壳就花了3000,要是再追求高质量,行业早期河妖工坊的头壳,花3000元也只能买到个二手的。她之前在闲鱼上收过一个,到货时头壳还浸着前任主人的二手烟味,晾了很久才散干净。
洋子(右一)的第一个BJD娃娃风格头壳
现在你说998全新?很难不怀疑是欺诈。偶域的粉丝群里,不少人也是一直持观望态度,生怕收到质量糟糕的圈钱货。但偶域一边是在私域群内发300大额券,早期的几十名购入的用户实际只花了698元,一边是承诺为收到质量不合格头壳的用户免费重做,直到每个收到货的用户都能对这不到千元的头壳称赞一声可爱。
这些承诺让那些游走不定的用户也忍不住下单尝鲜,等拿到头壳后,他们的反应也很一致,“这质量998,要啥自行车?”偶域的这桩赔本买卖,是被同行骂了很久的“装什么白莲花,破坏市场竞争”。但对普通玩家来说,这可是天大的好事,“哪里来的人做慈善的?”
创始人李明威是个2024年刚入行的00后。
年纪不大,履历却相当丰富。毕业于哈尔滨体育学院,他曾是速滑运动员、教练和裁判,给招商银行哈尔滨信息部做过软件外包,做过web3创业公司CTO,干过同人漫展策展人……
一连串的title,看似和工业设计、快消品毫无关联。但能支撑他做kig圈创业的核心身份,还是老二次元。
李明威不仅是老二次元,还是个总先人一步的小众老二次元。2016年,国内压根都还没普及“谷子”这个词时,他就在从上海供货商那里进口“吧唧”(动漫徽章),拿回哈尔滨漫展售卖了;2018年,他就组织过同人社群,成功开展了好几次地方“同人only活动”——这也是今年二次元地方漫展的大热趋势;2022年,疫情即将解封时,他观察到许久未曾办过线下交流集会的二次元群体蓬勃的社交欲望,就提前开始入局做cosplay周边道具。
时至今日,二次元经济早已从一小撮人的娱乐,变成了大众的消费狂欢。根据艾媒咨询数据,国内泛二次元用户规模由2017年的2.12亿人增长至2024年的5.03亿人,拓展到动漫、游戏、小说等广泛的二次元领域。但其中共通的是,年轻人不想再把对虚拟角色的喜爱藏在心里,而是要光明正大地摆在台面上,将之作为另一种象征个人身份的社交标签。
在这种底层逻辑驱使下,2023年检索创业新想法时,李明威自然地把目光移向kig圈。
他在2020年关注到kigurumi这个说法,当时展示头壳的博主还主要集中在推特上。他在“兔子”这家个人店铺定制了自己的第一个动漫风格美少女头壳,以Remi为id作为最早的一批vtuber(虚拟主播)在网上曝光,还曾在B站带着头壳直播写代码。
Remi 的造型
这个圈子是有受众基础,但也存在固有问题。目前,大部分头壳制作商还是以小作坊的模式运行,一个小店一个月最多15单。头壳制作商产能严重跟不上,还是对标头部的工坊,一些店家的工期在3个月到一年半,用户甚至有钱也排不进订单序列。
显然,这个市场还有庞大的需求没有被满足。
做二次元的“超级工厂”
2023年,李明威刚结束了一家科技公司的全职工作,打算All in到kigurumi创业项目里,技术搭档马涵也作为合伙人加入。在上海周边,就属昆山工业园区地价低,他在花桥镇租了一间便宜的民宅,从零到一学习制作头壳。
大体上一个头壳有3个组成部分,3D打印的硬质脸壳、手作假发和妆面。
当时最烧钱且费时的问题是,许多个人工坊无法自己制作3D打印的脸壳。据他调研,小作坊要把脸壳外包出去建模、打印、喷漆,光是这部分报目表就1000元打不住,正因如此,个人kig制作者的定价才会如此高。
衡量下来,他决定自学3D建模,再找外部工厂做打印,成本能压缩到200-300元一个脸壳。包括假发的打版和脸模上妆他也是现学现卖。他们拆了一台缝纫机来做发网,采用“古法打版”,用保鲜膜确定裁切位置;化妆则是一点点从美术线稿练起,学调色。
自然过程中走了不少弯路,像是用针缝了半天发网,最后发现别人家都是用磁铁;自己喷漆掌握不好火候,人脸喷得油光锃亮都成了废料。可想而知失败作品极多,到后期,他们连做模具的钱都没有了。这样“吭哧吭哧”到11月,“10个里面有1个能看的。”但鼓捣一通后,也是成功接到几个订单。
一开始李明威没想过搞大规模生产,只觉得他和马涵两人搭配,一个月做那么几单,赚个生活费平分了挺好。24年对他来说是个分水岭,在他们的小作坊质量达标后,“我面前有两条路,要么是做小店,要么是认真创业。但我不知道小店的出路是什么,我觉得小店可持续性很差。”
他认识许多同行的小店,生存周期也就在这个区间,每月做个三五单,后来有回去上班的、退圈的,大家四散而去,终究做不长久。
“这个东西不是说技术有多难,而是要解决生产与灵活多变需求匹配的问题。我不希望这个事情是过于主观或经验化的,我想要的是标准化的。所以我决定还是要认真向创业去做,我们想做能匹配更多需求的‘二次元超级工作室’。”
两人又各自掏空积蓄贷了款,凑出20万搭建整个作坊。那是24年江浙沪地区的桑拿天,由于吸塑机的功率在2000W以上,屋里的空调和设备只允许开一个,那当然不会是空调。
在160度的作业温度下,房间里的室温得有40度,冷却只靠一台小米风扇。这段经历让他对空调产生了执念,以至于现在,他的厂房也是整个工业园区里鲜少给员工配备空调的。
早期李明威的工作室
他的另一项“降本创新”是假发。一般在cos圈负责假发制作的人叫“毛娘”,毛娘都是凭借对二次元的热爱自学剪裁、染色、喷漆,完全是费时费力的手工活。闲鱼上毛娘平均收费在500-1000元,还需要排单等待,工期从半个月到一个月不等。同行做假发,招的也都是懂二次元的毛娘。
但为了效率,李明威是真的招募了专业的托尼老师。在昆山这个普遍月薪4-5k的工业城市,李明威给托尼开出了1w3的月薪。他聊了4、5个本地下岗发型师,光是解释“二次元是什么”就耗费了很多时间成本。不理解的人很多,但功夫不负有心人,还是有一位对上电波的托尼想试试这个新岗位。
受过专业洗剪吹训练的老师,现在已经成了工作室的造型总监。他一个下午能同时剪出5个头。“而且这个kig头也不会痛,他也不用一直有和客人沟通的压力,对老师来说这工作内容还是更轻松了。” 李明威说。
今年工作室扩容,李明威搬到了昆山一处更大的工业园区。他们占据一整层,周围是做精加工设备、五金回收的,而他们每天搬着一堆卡通大头在楼下打包发货,收获了不少工人讶异的眼光。
在这个小众细分的二次元领域,他们“把一家快炒小馆干成了成熟的连锁餐饮”。
偶域后台的待做订单
不再昂贵的“可爱”
7月份,“后浪研究所”走访了李明威的工作室,见识到了客户五花八门的定制订单。一份订单通常会附上4-5张动漫人物参考图。
这里有几百份出处各异的ACG角色的订单、数以万计规模的操作日志,难点在于这些都是2D平面动漫造型,要怎么把二次元纸片人高度还原成三维活人呢?
目前李明威正在积极打造一个能够理解3D建模与客户需求语义的AI模型。未来他们打算引入自研AI模型帮助人工做切割,识别出脸型、眼睛眉毛鼻子的位置、大小、形态等参数,让AI帮助拆解这种个性化。比如,通过一张平面图的睫毛弯曲度检查,就能推导人物睫毛的占地面积和整体位置。
他的设想是,未来的产品形态可以实现用户一键传图后直接生成可投入生产的工业建模。随着订单量越来越多,AI训练用数据集也会渐趋丰富,更容易做出一个大众观感上“可爱”的头壳。
终归,戴上头壳后是否可爱,还是个很主观的概率事件。他能做的只是尽可能拉高这个概率。
每天他们会把做好的头壳照片发给用户,并收到海量客户修改建议,可能精细到——刘海的长度位置不满意,刘海有没有挡住睫毛,眉毛或舌头的形状不满意,眼睛没有神……这是一个千人千面的乙方工作。
李明威也上线过一个能允许用户自由调节五官部位参数的3D打印系统,类似高级版4399捏脸小游戏。但遗憾的是很快他就收到了大量负面反馈,“这个体验对于用户来说很糟糕,他们希望的是一键传图,就能得到高度还原照片的3D建模效果。”
而最近他们的AI建模迭代,已经能做到用户给理想图,产品自动完成3D建模素体,又省了一道工序。
本身作为老kig玩家的李明威很清楚,“可爱”对玩家们来说有多重要。李明威研究过角色的五官面部比例,“动漫角色之所以受人欢迎是因为它更像一个婴儿、或者说猫咪的面貌,猫咪和婴儿会促进催产素的分泌。”客户穿戴后,凭借经验公式,当头在肩宽的1/2~2/3之间,头身比在1:6到1:7时,戴上头壳可以得到最黄金的身材比例。
kig圈大部分都是男性——以可爱的形象示人,被更多人看见,在二次元社群小圈子里获得更多关注,这方面的需求量并不少。近几年也有越来越多女性玩家涌入,在多数头壳店铺的在线群组中里男女比可以达到2:1。不管壳背后的主体是男是女、是高矮胖瘦美丑如何,戴上kigurumi都能变成可爱娃娃。
但在这个以奢侈品逻辑运行的小众圈子里,“可爱”是昂贵的,一眼可见的,钱烧得多,就可爱。算个账,定制头壳最便宜3000块,算上肉色紧身衣和各种cosplay道具,一套成型的kig装扮起码在5000块。与其说比拼对角色的爱,不如说是在拼财力。
而现在这个被小众贵价产品垄断的圈子里,已经有源源不断的新鲜血液涌入。
玩家洋子告诉我,入坑的第5年,她观察到行业里涌现出了不少中低价位的新店,包括像偶域这样做低价品的头壳制作商出现——2000元左右,许多始终处于观望状态的玩家也觉得,自己能越过那条心理预算线,购入人生中第一个头壳了。
今年的bw漫展,他也发现kigurumi玩偶越来越多。以往走一天也就能遇到3、5个,这次他们一群大娃娃站在一起拍了个合照,足足20多人,统一的大眼睛和扁平化轮廓,她们比普通人更高,更大,更显眼。
漫展上的kigurumi玩具大合照
在头壳里,人是很安全的。
kigurumi头壳的视窗开在睫毛上方,一条细细的缝线,待在头壳里密不透风,视野也会受阻。在他们的视野中看不清普通的人,只能看到同高度、同维度的kig娃娃们,挂着统一的明媚笑容,一个温暖的世界。
(文中图片由受访者提供)
本文来自微信公众号“后浪研究所”,作者:许嘉婧、薇薇子,36氪经授权发布。
山西全力保障秋粮收购资金需求
警告信激增 英国税局剑指加密逃税
杨振宁逝世:改变了中国人觉得不如人的心理/库克:苹果AI正努力入华/GPT-5攻克「百年数学难题」遭反转|Hunt Good周报
欢迎收看最新一期的 Hunt Good 周报!
在本期内容你会看到:
8 条新鲜资讯
3 个有用工具
1 个有趣案例
3 个鲜明观点
Hunt for News|先进头条
杨振宁逝世,享年 103 岁
据新华社报道,享誉世界的物理学家、诺贝尔物理学奖获得者,中国科学院院士,清华大学教授、清华大学高等研究院名誉院长杨振宁先生,因病于 2025 年 10 月 18 日在北京逝世,享年 103 岁。
公开资料显示,杨振宁 1922 年出生于安徽合肥,上世纪 40 年代赴美留学任教,他与同是华裔物理学家的李政道于 1956 年共同提出宇称不守恒理论,因而获得 1957 年诺贝尔物理学奖,成为最早华人诺奖得主之一。
「杨-米尔斯规范场论」,是研究凝聚原子核的力的精深理论。
杨振宁和米尔斯把电磁作用是由定域规范不变性所决定的观念推广到对易性的定域对称群,提出具有定域同位旋不变性的理论,发现必须引进 3 种矢量规范场,它们形成同位旋转动群的伴随表示。揭示出规范不变性可能是电磁作用和其它作用的共同本质,从而开辟了用此规范原理来统一各种相互作用的新途径。
杨振宁晚年曾多次谈及自己的人生体悟,他曾说:「我这一生最重要的贡献,是帮助改变了中国人自己觉得不如人的心理作用。我想,我在科学工作的成就,帮助中国人的自信心增加了。」
苹果 CEO:Apple Intelligence 正努力入华
10 月 18 日, 苹果公司首席执行官蒂姆·库克(Tim Cook)现身上海,在全球财富管理论坛·2025 上海苏河湾大会上,与清华大学经管学院院长、全球财富管理论坛执委会主席白重恩进行了对话。
据第一财经报道,在对话环节中, 库克就「科技驱动时代的创新边界」议题透露, 苹果正积极推动 Apple Intelligence 进入中国市场。他表示:「我们正在推动苹果智能进入中国,在操作系统层面整合人工智能的功能,让人们在每天使用的所有应用程序中,都能借助 AI 的力量。」
库克特别强调了 AI 技术的重要价值, 指出 AI 正在改变人们生活甚至挽救生命。本周在走访苹果上海浦东陆家嘴旗舰店时, 他特别与中国消费者交流了 Apple Watch 的跌倒检测等健康监测功能。
此外,报道中提到,促成 Apple Intelligence 在华发布是库克此行的核心目标之一, 同时他还肩负着与国内运营商协商在 iPhone Air 中推广 eSIM 技术的重要使命。
OpenAI 推「ChatGPT 登录」功能,打造个人 AI 订阅生态
据知情人士透露,OpenAI 正在推销一项更具野心的服务——允许访客使用 ChatGPT 凭证登录其网站,类似于目前广泛使用的 Google 或 Facebook 账号登录,采用该登录功能的公司可以将使用 OpenAI 模型的成本转移给客户。
具体而言,当用户使用 ChatGPT 账号登录某个基于 OpenAI 模型的初创公司服务时,该初创公司应向 OpenAI 支付的费用将从用户 ChatGPT 账户的容量限制中扣除。
免费用户每五小时可向 GPT-5 发送约 10 个查询,其中部分查询额度将用于抵消初创公司的 API 费用。如果免费用户在使用第三方服务时达到使用限额,系统会提示其升级到付费账户。
这种模式对使用频率较低、从未达到容量上限的用户具有吸引力,也能帮助缺乏资金支付高额 API 账单的小型初创公司降低成本。
不过,对于按使用量收费的初创公司而言,这可能损害其收入。
业内人士指出,这些举措凸显了 OpenAI 希望像苹果、谷歌和 Facebook 一样,将影响力扩展到消费者在线生活的各个方面。OpenAI 已告知投资者,预计到 2030 年将通过非付费用户间接产生约 1100 亿美元收入。
https://www.theinformation.com/articles/openais-growing-ecosystem-play?rc=qmzset
我国生成式人工智能用户规模超 5 亿
据新华社报道,10 月 18 日,中国互联网络信息中心在 2025(第六届)中国互联网基础资源大会上发布《生成式人工智能应用发展报告(2025)》。
报告显示,截至 2025 年 6 月,我国生成式人工智能用户规模达 5.15 亿人,较 2024 年 12 月增长 2.66 亿人,用户规模半年翻番;普及率为 36.5%。
报告认为,生成式人工智能正逐渐融入我国各类群体的日常生活中,中青年、高学历用户是核心群体。在所有生成式人工智能用户中,40 岁以下中青年用户占比达到 74.6%,大专、本科及以上高学历用户占比为 37.5%
报告指出,国产生成式人工智能大模型得到用户广泛青睐,并推动各种应用场景下的智能化改造升级。
调查发现,超九成用户首选国产大模型。生成式人工智能被广泛应用于智能搜索、内容创作、办公助手、智能硬件等多种场景,还在农业生产、工业制造、科学研究等领域得到积极探索实践。
https://www.news.cn/fortune/20251018/22bbffa5b01a47078a558a0ab46e66a4/c.html
维基百科警告:AI 导致人类访问量大幅下降
维基百科的托管机构维基媒体基金会近日发出警告,由于越来越多用户通过生成式 AI 聊天机器人和搜索引擎摘要获取信息,而非直接访问网站,导致这个全球最大在线百科全书的人类访问量出现危险性下降,威胁到其长期可持续发展。
基金会产品高级总监马歇尔·米勒在博客中表示,修正机器人检测系统后发现,维基百科过去几个月的人类页面浏览量与 2024 年同期相比下降了约 8%。他指出,这反映了生成式 AI 和社交媒体对人们获取信息方式的影响,尤其是搜索引擎开始直接提供答案,而这些答案往往基于维基百科内容。
米勒强调,访问量减少将带来严重后果。他说:「随着对维基百科的访问量减少,愿意参与并丰富内容的志愿者可能会越来越少,支持这项工作的个人捐赠者也可能减少。」
讽刺的是,虽然 AI 导致维基百科流量下降,但其数据对 AI 的价值却前所未有地高。几乎所有大型语言模型都在维基百科数据集上训练,谷歌等平台多年来也一直挖掘维基百科内容来支持其摘要功能,这些功能反过来又分流了维基百科本身的流量。
这一发现与其他研究相呼应。今年 7 月皮尤研究中心发现,仅有 1% 的谷歌搜索用户会点击 AI 摘要中的链接访问原始页面。基金会表示正在加强政策执行、制定归属框架并开发新技术能力,同时呼吁用户在搜索信息时主动寻找引用并点击原始资料,支持由真实的人创作的可信知识。
https://www.404media.co/wikipedia-says-ai-is-causing-a-dangerous-decline-in-human-visitors/
Gemini 3.0 或将于 12 月发布
据 Sources.news 报道,谷歌计划于 12 月推出旗舰 AI 模型 Gemini 的最新版本 3.0,该版本预计将实现显著性能提升,有望跻身行业排行榜前列。
作为谷歌 AI 战略的核心产品,Gemini 应用曾凭借热门的 Nano Banana 图像生成模型,一度登顶 iOS App Store 排行榜,短暂取代 ChatGPT 的榜首位置。
值得关注的是,报道中还提到,谷歌内部正讨论将部分 Gemini 高级功能纳入免费版本的方案。此外,谷歌还组建了一支小型秘密团队,致力于将 Gemini 3.0 集成到苹果的操作系统中,拓展应用场景。
https://sources.news/p/google-readies-gemini-3-perplexity
OpenAI 宣布自研 AI 芯片
本周,OpenAI 与芯片巨头博通宣布达成一项价值数十亿美元的重大合作协议,双方将在未来四年内共同开发和部署 10 吉瓦的定制 AI 芯片和计算系统,以满足 OpenAI 日益增长的庞大计算需求。
根据协议,OpenAI 将自主设计图形处理单元 (GPU),将其在开发强大 AI 模型过程中积累的经验整合到硬件系统中。这些芯片将由两家公司共同开发,博通负责从明年下半年开始部署。
新系统将采用博通的以太网技术和其他连接技术,部署在 OpenAI 自有及第三方运营的数据中心。据悉,双方 18 个月前就已开始定制芯片合作,此次进一步扩大至服务器机架和网络设备等相关组件。
这笔巨额交易使 OpenAI 与博通、英伟达和 AMD 三大芯片巨头约定购买的计算能力总规模达到 26 吉瓦。OpenAI CEO 山姆·奥特曼和负责基础设施建设的总裁格雷格·布罗克曼表示,公司目前可用的计算能力远远不足。随着 AI 产品需求快速增长,他们希望在全球建设大型数据中心以保持领先。
据知情人士透露,奥特曼最近告诉员工,OpenAI 计划到 2033 年建设 250 吉瓦的新计算能力,按当前标准这将耗资超过 10 万亿美元。
https://openai.com/index/openai-and-broadcom-announce-strategic-collaboration/
苹果新 AI 搜索主管转投 Meta
据彭博社记者 Mark Gurman 报道,苹果公司负责 AI 搜索项目的高管 Ke Yang 即将离职,加入 Meta。
这一变动发生在他刚刚接手「Answers,Knowledge and Information」(直译为「答案、知识和信息」,简称 AKI)团队数周之后。
该团队的任务是为 Siri 增强类 ChatGPT 功能,使其能够从网络实时获取信息。
知情人士透露,Ke Yang 的离开是苹果人工智能部门近期一系列高层出走中的最新一例。
今年以来,已有约十余名核心成员离开苹果基础模型团队,其中部分人同样转投 Meta,加入其新成立的「Superintelligence Labs」。
苹果原计划在 2025 年 3 月推出全新版本的 Siri,整合 AKI 团队研发的搜索功能,并补齐此前推迟的多项特性,包括调用个人数据以处理更复杂的请求。
该项目被视为苹果追赶 OpenAI、Perplexity 以及 Google Gemini 等竞争对手的重要举措。
随着 Ke Yang 的离职,AKI 团队将转由苹果副总裁 Benoit Dupin 接管,他目前负责机器学习相关的云基础设施。
https://www.bloomberg.com/news/articles/2025-10-15/apple-s-newly-tapped-head-of-chatgpt-like-ai-search-effort-to-leave-for-meta
Hunt for Tools|先进工具
🛜 Manus 1.5 正式发布,一键开发完整 Web 应用
10 月 17 日,AI 智能体平台 Manus 宣布推出全新版本 Manus 1.5。
官方表示,本次更新在速度与性能方面实现了全面提升,并进一步验证了其核心架构的通用性。
与传统的「AI 网站生成器」不同,Manus 团队强调,他们并非单纯开发一款工具,而是持续进化底层框架,并为其配备合适的功能模块。得益于这一思路,Manus 在短短一个月内便实现了「sota 级别」的 AI Web 应用构建能力。
值得注意的是,Manus 1.5 的新能力与平台现有功能深度打通。例如,用户可快速搭建服务介绍网站,并在收集到客户信息后,通过 Manus 客户端和邮件推送触发后续任务,如自动生成个性化幻灯片。
官方表示,这一增强功能已面向所有用户开放,其背后的基础设施是团队更宏大愿景的一部分 —— 打造一个任何人都能通过对话调用云计算与 AI 全部力量的平台。
https://manus.im/zh-cn/blog/manus-1.5-release
英伟达开售全球最小 AI 超级计算机,黄仁勋给马斯克「送货上门」
本周,NVIDIA 在官网发文,宣布正式开售 DGX Spark,这是一款号称「全球最小 AI 超级计算机」的桌面级产品。首台设备由 NVIDIA CEO 黄仁勋亲手交付给 Elon Musk,地点选在 SpaceX 的 Starbase 基地。
据悉,DGX Spark 基于 Grace Blackwell 架构,单机可提供 1 Petaflop AI 性能,配备 128GB 统一内存,能够在本地运行高达 2000 亿参数的推理模型,并支持对 700 亿参数模型进行微调。
官方强调,该产品面向开发者、研究人员与创作者,旨在将超级计算机级别的算力带到桌面。
黄仁勋表示:「2016 年我们推出 DGX-1,并交付给当时的 OpenAI,那台机器催生了 ChatGPT,开启了 AI 革命。如今 DGX Spark 将再次把超级计算机放到开发者桌面,点燃新一轮突破。」
马斯克也在 X 上回应称:「这台 DGX Spark 的能效比黄仁勋 2016 年交付给我的 DGX-1DGX-1 高出约 100 倍,那是史上第一台专用 AI 计算机」。
DGX Spark 将于 10 月 15 日起在 NVIDIA 官网及合作渠道开启订购。
相关阅读:时隔 9 年,黄仁勋再次给马斯克送货上门,跳票大半年的 AI 个人超算终于来了
Windows 11 迎来重磅更新:Copilot 全面接管语音、屏幕与任务栏
近日,微软在官网发文,宣布为 Windows 11 推出大规模更新,核心在于全面引入 AI 功能,让每台设备都成为「AIPC」。
本次更新的重点包括:
- Hey,Copilot:用户可通过语音直接唤醒 Copilot,实现免手操作;
- Copilot Vision:支持读取屏幕内容并实时指导操作,甚至能在界面上标注点击步骤;
- Ask Copilot:将 Copilot 集成至任务栏,一键直达;
- Copilot Actions:可在本地执行任务,如整理照片、提取 PDF 信息;
- Copilot Connectors:打通 OneDrive、Outlook 与 Google 全家桶,实现跨平台数据检索。
此外,微软还将 Manus AI Agent 引入 Windows,用户可在文件资源管理器中直接调用「使用 Manus 创建网站」功能,几分钟内生成网页。
其他更新还包括与 Filmora 的视频编辑集成、Zoom 快捷会议安排,以及 Gaming Copilot 测试版。微软强调,语音交互不会取代键盘和鼠标,而是成为第三种输入方式。
尽管这些新功能主要面向支持 Copilot 的国家/地区,但微软的这次更新也为 AI PC 原生操作系统指明了一个可能的发展方向。
相关阅读:Windows 11 大更新:动嘴就能让 AI 操控电脑,还有 Manus 强势上岗
Hunt for Fun|先玩
🥱 GPT-5 攻克「百年数学难题」遭反转,OpenAI 科学家删帖致歉
近日, 一则关于 GPT-5「一个周末解决 10 个百年数学难题」的消息在学术界引发轩然大波, 但随后被证实存在严重误导。
事件起源于 OpenAI 研究科学家、前微软副总裁塞巴斯蒂安·布贝克上周首次披露, 两名数学研究人员利用 GPT-5 在一个周末内找到了 10 个未解决埃尔德什难题的答案。
埃尔德什难题是著名数学家保罗·埃尔德什生前提出的约 1000 多个数学问题, 此前人类只解决了部分。OpenAI 研究人员之一马克·塞尔克也随后确认, 他们通过数千次查询 GPT-5, 在 10 个问题上找到了解决方案, 并在另外 11 个问题上取得显著进展。
然而, 事实真相很快浮出水面。
埃尔德什问题网站维护者托马斯·布卢姆澄清称, 这是「严重的歪曲」,GPT-5 只是找到了他个人此前不知道的已发表文献, 这些问题实际上早已被其他数学家解决。网站上标注的「未解决」状态仅表示维护者本人尚未找到相关论文, 而非学术界真正的未解难题。
布贝克随后删除了原帖并道歉, 承认只是在文献中找到了已有的解决方案, 并非 AI 独立完成数学证明。Meta 首席 AI 科学家杨立昆也在评论区贴脸输出,讽刺他们被自己过度炒作 GPT的言论坑惨了。
https://x.com/SebastienBubeck/status/1979539604522127746
Hunt for Insight|先知
🟰 陶哲轩:AI 对数学研究的核心价值在提效而非攻坚
菲尔兹奖得主、被誉为「数学界莫扎特」的华裔数学家陶哲轩近日发表文章,阐述了他对人工智能在数学研究中应用前景的看法。
陶哲轩指出,AI 在数学领域近期最有成效的应用,并非用最强模型攻克最难问题,而是利用中等能力工具加速那些普通但耗时的关键研究任务。
他认为,在这些任务中人类专家可以凭借经验来引导和验证 AI 产出,这种 AI 结果本身也可由人工完成的特点恰恰是优势,因为专家能更可靠地评估输出结果。
他以文献综述为例说明。对于有明确名称和成熟研究群体的问题,现有检索工具已足够强大,但当相关文献零散、缺乏统一命名,或因期刊冷门、研究群体间缺乏交流等原因导致引用关系难以追踪时,传统检索就变得极为耗时。
而 AI 工具的另一潜在优势是能促使「负面结果」得到报告。传统上研究者若未找到相关文献通常不会明确报告,担心日后发现遗漏会显得尴尬,这可能导致重复劳动或误判问题状态。但使用 AI 系统性检索时,同时报告正面和负面结果就显得更自然,有助于更准确呈现问题在现有文献中的真实状态。
https://mathstodon.xyz/@tao/115385022005130505
Figma CEO 称 AI 不会取代工作,各部门持续招聘
当时时间 10 月 17 日,设计工具公司 Figma CEO 迪伦・菲尔德在播客中明确表示,AI 不会威胁到人类工作,反而能为行业创造新机遇。
菲尔德提到,Figma 9 月开展的一项涵盖 1199 名设计师、产品经理、开发者等从业者的调查显示,近 60% 的产品构建者因 AI 能投入更多高价值工作,约 70% 的受访者认为自身效率显著提升。
他强调,AI 的核心作用是辅助人类而非替代,应聚焦如何适应技术发展、摆脱重复劳动,而非过度担忧。
总部位于旧金山的 Figma 成立于 2012 年,今年 7 月成功上市,目前市值近 300 亿美元,员工规模超 1600 人。
菲尔德透露,公司正持续在各部门扩充岗位,虽在探索 AI 提升效率、降低成本的可能,但更看重其解锁增长新机遇的潜力。这并非他首次表态,此前他也曾多次强调,AI 是增强人类工作的工具,设计师仍需发挥主导作用,技术将让更多人获得创作机会。
https://www.businessinsider.com/figma-ceo-dylan-field-ai-jobs-hiring-2025-10
前 OpenAI 科学家卡帕西:AGI 仍需十年,强化学习存在根本缺陷
特斯拉前自动驾驶负责人、OpenAI 联合创始人安德烈·卡帕西近日在播客访谈中系统阐述了他对人工智能发展的最新看法, 认为实现通用人工智能(AGI)至少还需要十年时间, 并对当前 AI 技术路径提出了尖锐批评。
在谈到强化学习时, 他表示强化学习「非常糟糕」, 因为它假设解决问题过程中的每个步骤都是正确的, 实际上却充满噪音。他指出, 人类绝不会像 AI 那样进行数百次尝试, 然后仅根据最终结果来加权整个过程。当前大语言模型评判者也容易被对抗性样本欺骗, 导致训练过程出现严重偏差。
关于超级智能, 他认为 AI 发展是计算演进的自然延伸, 不会出现人们想象的「智能爆炸」, 而是会延续过去几百年来 2% 左右的经济增长率。他将 AI 比作历史上的编译器、搜索引擎等工具, 认为它们都是递归式自我改进过程的一部分。
在教育领域, 卡帕西正在创建 Eureka Labs, 致力于打造「星际舰队学院」式的精英技术教育机构。他相信 AI 将彻底改变教育, 但强调当前 AI 能力尚不足以提供真正的一对一辅导体验。他设想未来每个人都能掌握多门语言和各学科知识, 人类将像健身一样追求智力提升。
https://www.dwarkesh.com/p/andrej-karpathy
彩蛋时间
作者:@CharaspowerAI
提示词:A pencil drawing of [character or object] [breaking through / emerging from / interacting with] [a paper surface or cracked wall], in the style of a tattoo sketch on white paper. Black pen and pencil only, with [one specific element] in [a vivid color] as the only colored detail. Trompe-l’œil effect with [torn edges / curled paper / cracked wall], realistic shadowing, sketchbook illustration style, high detail.
链接:https://x.com/CharaspowerAI/status/1978861011273654384
#欢迎关注爱范儿官方微信公众号:爱范儿(微信号:ifanr),更多精彩内容第一时间为您奉上。
中国AIGC用户破5亿,增长1倍;美团:今年超7成外卖低于15元;新能源事故,「破窗锤」被网友买爆|极客早知道
超 90% 选择国产模型:我国生成式 AI 用户规模达 5.15 亿人、2025 上半年环比增长 106.6%
分析显示,ChatGPT 的移动应用下载量和日常使用量正在放缓
全球车企毛利率排名出炉:赛力斯第二 小米第四
美团:今年餐饮客单价几乎重回十年前 外卖订单有 75% 低于 15 块
阿里巴巴与蚂蚁联合投资设立香港总部,立足中国面向全球

中国首款全碳纤维火箭「微光一号」通过可行性评审,转入工程实施阶段

消息称索尼 PS5 Pro 游戏机国行定价 5499 元,本月底出货
汽车破窗锤本周悄然走俏 有店铺销量陡增 500%
Pinia 状态管理原理与实战全解析
一、前言:为什么选择 Pinia?
在 Vue2 时代,我们常用 Vuex 来做全局状态管理。
但是 Vue3 带来了全新的响应式系统(Composition API + Proxy),于是 Vue 官方团队推出了 Pinia —— 一款更轻量、更现代、更易用的状态管理库。
Pinia 的核心理念是:
“让状态管理像使用普通变量一样简单。”
相比 Vuex,它具备以下优势:
特点 | Vuex | Pinia |
---|---|---|
语法 | 基于 Mutations/Actions | 直接使用函数 |
类型推导 | 较弱 | TypeScript 支持友好 |
响应式实现 | Object.defineProperty | Vue3 Proxy |
模块化 | 需手动命名空间 | 天然支持模块化 |
体积 | 较大 | 小巧轻量(约1KB) |
二、Pinia 的核心原理
要理解 Pinia,先要知道它是如何在底层维持响应式的。
1. 状态的本质:Reactive
Pinia 使用 Vue3 的 reactive() 来存储状态。
每个 store 内部其实就是一个被 reactive 包裹的对象。
import { reactive } from 'vue'
const state = reactive({
count: 0
})
当 state.count++ 改变时,所有引用它的组件都会自动更新。
这就是 Pinia 响应式的根本机制。
2. Getter 的本质:Computed
在 Pinia 中,getter 相当于 Vue 中的 computed。
getters: {
doubleCount: (state) => state.count * 2
}
Pinia 会在内部把它转成一个 计算属性,只有依赖变化时才会重新计算。
因此它是 响应式、缓存式 的。
3. Action 的本质:普通函数 + 作用域代理
Pinia 不再强制使用 Mutation。
Action 其实就是对状态修改的封装函数。
actions: {
increment() {
this.count++
}
}
Pinia 通过 Proxy 让 this 指向 store 实例,因此你可以像访问普通对象一样修改状态。
4. 模块与依赖收集机制
每一个 store 都是一个独立的响应式作用域(Reactive Scope)。
Pinia 会将它注册到全局的 store 容器中(类似一个 Map 结构),并在组件使用时完成依赖收集。
组件一旦引用某个 store 的状态,Pinia 就会追踪它的依赖关系。
当 store 内的状态改变时,Pinia 会自动触发依赖更新 —— 这就是响应式传播的原理。
三、Pinia 的安装与配置
1️⃣ 安装
npm install pinia
# 或者
yarn add pinia
2️⃣ 创建与挂载
在 main.js 中引入 Pinia 并挂载到 Vue 应用:
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
四、定义第一个 Store
Pinia 推荐使用 defineStore() 来定义一个 store。
// src/stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
// 1. state:存放共享数据
state: () => ({
count: 0,
name: 'Pinia示例'
}),
// 2. getters:相当于计算属性
getters: {
doubleCount: (state) => state.count * 2
},
// 3. actions:用于定义修改逻辑
actions: {
increment() {
this.count++
},
setCount(val) {
this.count = val
}
}
})
五、在组件中使用 Store
在组件中使用时,就像普通变量一样简单。
<template>
<div>
<h2>{{ counter.name }}</h2>
<p>当前数量:{{ counter.count }}</p>
<p>双倍数量:{{ counter.doubleCount }}</p>
<button @click="counter.increment">增加</button>
</div>
</template>
<script setup>
import { useCounterStore } from '@/stores/counter'
const counter = useCounterStore()
</script>
💡 响应式自动生效:
当 counter.count 改变时,界面会自动更新,无需手动刷新。
六、解构与响应式陷阱
Pinia store 是响应式对象,如果你用结构赋值要注意保持响应性。
错误写法 ❌:
const { count } = useCounterStore()
console.log(count) // 不会响应更新
正确写法 ✅:
import { storeToRefs } from 'pinia'
const store = useCounterStore()
const { count, doubleCount } = storeToRefs(store)
storeToRefs() 会帮你保留响应式引用。
七、模块化管理多个 Store
Pinia 天然支持多 store,无需命名空间:
// user.js
export const useUserStore = defineStore('user', {
state: () => ({
name: '张三',
token: ''
}),
actions: {
login(name) {
this.name = name
this.token = 'token123'
}
}
})
在组件中可以自由组合使用:
import { useUserStore } from '@/stores/user'
import { useCounterStore } from '@/stores/counter'
const user = useUserStore()
const counter = useCounterStore()
八、持久化存储(localStorage)
Pinia 本身不带持久化功能,但可以通过插件轻松实现:
✅ 手动持久化:
watch(
() => store.count,
(newVal) => {
localStorage.setItem('count', newVal)
}
)
✅ 使用插件(推荐):
安装:
npm i pinia-plugin-persistedstate
注册插件:
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
开启持久化:
export const useUserStore = defineStore('user', {
state: () => ({ name: '', token: '' }),
persist: true
})
九、Pinia + TypeScript 实践(简要示例)
Pinia 的类型推导非常强大。
在 TS 项目中可直接推断出 state 和 getter 的类型。
export const useTodoStore = defineStore('todo', {
state: () => ({
list: [] as string[]
}),
actions: {
addTodo(item: string) {
this.list.push(item)
}
}
})
// 自动推导类型
const store = useTodoStore()
store.addTodo('学习 Pinia')
十、Pinia 内部运行机制简述
Pinia 内部核心模块包括:
-
Store 实例注册
每个 defineStore() 都注册到全局 pinia._s 容器中。
-
Reactive 封装
使用 reactive() 包装 state,配合 Vue 的 effect 机制实现依赖收集。
-
Getter 包装为 computed
保证 getter 的懒计算与缓存特性。
-
Action 包装代理
使用 Proxy 代理 this 指向当前 store,并自动注入 devtools 日志。
-
订阅机制
Pinia 提供 store.$subscribe(),可以监听 state 变化。
十一、实战示例:Todo 应用
<template>
<div>
<h2>我的待办事项</h2>
<input v-model="newTask" @keyup.enter="addTodo" placeholder="输入任务..."/>
<ul>
<li v-for="(item, index) in todos.list" :key="index">
{{ item }}
<button @click="removeTodo(index)">删除</button>
</li>
</ul>
</div>
</template>
<script setup>
import { ref } from 'vue'
import { useTodoStore } from '@/stores/todo'
const todos = useTodoStore()
const newTask = ref('')
const addTodo = () => {
if (newTask.value.trim()) {
todos.addTodo(newTask.value)
newTask.value = ''
}
}
const removeTodo = (i) => todos.list.splice(i, 1)
</script>
十二、总结
内容 | 关键点 |
---|---|
状态管理核心 | Vue3 的 reactive 与 computed |
改进点 | 无需 mutation、天然模块化 |
类型支持 | 友好且强大 |
响应式机制 | Proxy + Effect 依赖追踪 |
持久化 | 插件 pinia-plugin-persistedstate |
适用场景 | 中大型 Vue3 项目,全局状态同步 |
Pinia 的设计哲学是:
“简单到你几乎忘了自己在用状态管理库。”
Vue3 状态管理完全指南:从响应式 API 到 Pinia
什么是状态管理?
在 Vue 开发中,状态管理是一个核心概念。简单来说,状态就是驱动应用的数据源。每一个 Vue 组件实例都在管理自己的响应式状态,让我们从一个简单的计数器组件开始理解:
<script setup>
import { ref } from 'vue'
// 状态 - 驱动应用的数据源
const count = ref(0)
// 动作 - 修改状态的方法
function increment() {
count.value++
}
</script>
<!-- 视图 - 状态的声明式映射 -->
<template>{{ count }}</template>
这个简单的例子展示了状态管理的三个核心要素:
-
状态:数据源 (
count
) - 视图:状态的声明式映射 (模板)
-
动作:状态变更的逻辑 (
increment
)
这就是所谓的"单向数据流"概念。
为什么需要状态管理?
当应用变得复杂时,我们会遇到两个典型问题:
问题 1:多个组件共享状态
<!-- ComponentA.vue -->
<template>组件 A: {{ count }}</template>
<!-- ComponentB.vue -->
<template>组件 B: {{ count }}</template>
如果多个视图依赖于同一份状态,传统的解决方案是通过 props 逐级传递,但这在深层次组件树中会变得非常繁琐,导致 Prop 逐级透传问题。
问题 2:多组件修改同一状态
来自不同视图的交互都需要更改同一份状态时,直接通过事件或模板引用会导致代码难以维护。
解决方案:将共享状态抽取到全局单例中管理。
使用响应式 API 实现简单状态管理
Vue 的响应式系统本身就提供了状态管理的能力。
创建全局状态 Store
// store.js
import { reactive } from 'vue'
export const store = reactive({
count: 0,
user: null,
todos: []
})
在组件中使用
<!-- ComponentA.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>
<div>From A: {{ store.count }}</div>
<button @click="store.count++">+1</button>
</template>
<!-- ComponentB.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>
<div>From B: {{ store.count }}</div>
<button @click="store.count++">+1</button>
</template>
问题:任意修改的风险
上面的实现有个问题:任何导入 store 的组件都可以随意修改状态,这在大型应用中难以维护。
改进:封装状态修改逻辑
// store.js
import { reactive } from 'vue'
export const store = reactive({
// 状态
count: 0,
user: null,
todos: [],
// 动作 - 封装状态修改逻辑
increment() {
this.count++
},
setUser(user) {
this.user = user
},
addTodo(todo) {
this.todos.push(todo)
},
removeTodo(id) {
this.todos = this.todos.filter(todo => todo.id !== id)
}
})
<!-- ComponentB.vue -->
<script setup>
import { store } from './store.js'
</script>
<template>
<button @click="store.increment()">
From B: {{ store.count }}
</button>
</template>
注意:这里使用 store.increment()
带圆括号调用,因为它不是组件方法,需要正确的 this 上下文。
使用组合式函数管理状态
// useCounter.js
import { ref } from 'vue'
// 全局状态
const globalCount = ref(1)
export function useCount() {
// 局部状态
const localCount = ref(1)
function incrementGlobal() {
globalCount.value++
}
function incrementLocal() {
localCount.value++
}
return {
globalCount: readonly(globalCount), // 使用 readonly 保护全局状态
localCount,
incrementGlobal,
incrementLocal
}
}
Pinia:现代化的状态管理库
虽然手动状态管理在简单场景中足够,但生产级应用需要更多功能:
- 团队协作约定
- Vue DevTools 集成
- 模块热更新
- 服务端渲染支持
- 完善的 TypeScript 支持
Pinia 是 Vue 官方推荐的状态管理库,它解决了上述所有问题。
为什么选择 Pinia?
- ✅ 类型安全:完美的 TypeScript 支持
- ✅ DevTools 支持:时间旅行调试等
- ✅ 模块热更新:开发时保持状态
- ✅ 简洁的 API:学习成本低
- ✅ 组合式 API:与 Vue 3 完美契合
安装和配置
npm install pinia
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')
创建 Store
选项式 Store
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
// 状态
state: () => ({
count: 0,
user: null
}),
// 计算属性
getters: {
doubleCount: (state) => state.count * 2,
isAuthenticated: (state) => state.user !== null
},
// 动作
actions: {
increment() {
this.count++
},
async login(credentials) {
const user = await api.login(credentials)
this.user = user
},
logout() {
this.user = null
}
}
})
组合式 Store(推荐)
// stores/counter.js
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
export const useCounterStore = defineStore('counter', () => {
// 状态
const count = ref(0)
const user = ref(null)
// 计算属性
const doubleCount = computed(() => count.value * 2)
const isAuthenticated = computed(() => user.value !== null)
// 动作
function increment() {
count.value++
}
async function login(credentials) {
const response = await fetch('/api/login', {
method: 'POST',
body: JSON.stringify(credentials)
})
user.value = await response.json()
}
function logout() {
user.value = null
}
return {
count,
user,
doubleCount,
isAuthenticated,
increment,
login,
logout
}
})
在组件中使用 Store
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'
const counterStore = useCounterStore()
// 使用 storeToRefs 保持响应式并解构
const { count, doubleCount, isAuthenticated } = storeToRefs(counterStore)
const { increment, login } = counterStore
// 直接修改状态(不推荐)
const directIncrement = () => {
counterStore.count++
}
// 使用 action(推荐)
const actionIncrement = () => {
counterStore.increment()
}
// 批量修改
const patchUpdate = () => {
counterStore.$patch({
count: counterStore.count + 1,
user: { name: 'Updated User' }
})
}
// 重置状态
const resetStore = () => {
counterStore.$reset()
}
// 订阅状态变化
counterStore.$subscribe((mutation, state) => {
console.log('状态变化:', mutation)
console.log('新状态:', state)
})
</script>
<template>
<div>
<p>计数: {{ count }}</p>
<p>双倍计数: {{ doubleCount }}</p>
<p>认证状态: {{ isAuthenticated ? '已登录' : '未登录' }}</p>
<button @click="increment">增加</button>
<button @click="directIncrement">直接增加</button>
<button @click="patchUpdate">批量更新</button>
<button @click="resetStore">重置</button>
</div>
</template>
在 Store 之间使用其他 Store
// stores/auth.js
import { defineStore } from 'pinia'
export const useAuthStore = defineStore('auth', () => {
const user = ref(null)
const token = ref('')
function setAuth(userData, authToken) {
user.value = userData
token.value = authToken
}
return { user, token, setAuth }
})
// stores/todos.js
import { defineStore } from 'pinia'
import { useAuthStore } from './auth'
export const useTodosStore = defineStore('todos', () => {
const authStore = useAuthStore()
const todos = ref([])
async function fetchTodos() {
// 使用其他 store 的状态
if (!authStore.token) {
throw new Error('未认证')
}
const response = await fetch('/api/todos', {
headers: {
Authorization: `Bearer ${authStore.token}`
}
})
todos.value = await response.json()
}
return { todos, fetchTodos }
})
高级模式和最佳实践
1. 数据持久化
// plugins/persistence.js
import { watch } from 'vue'
export function persistStore(store, key = store.$id) {
// 从 localStorage 恢复状态
const persisted = localStorage.getItem(key)
if (persisted) {
store.$patch(JSON.parse(persisted))
}
// 监听状态变化并保存
watch(
() => store.$state,
(state) => {
localStorage.setItem(key, JSON.stringify(state))
},
{ deep: true }
)
}
// 在 store 中使用
export const usePersistedStore = defineStore('persisted', () => {
const state = ref({})
// 在 store 创建后调用
onMounted(() => {
persistStore(usePersistedStore())
})
return { state }
})
2. API 集成模式
// stores/posts.js
import { defineStore } from 'pinia'
export const usePostsStore = defineStore('posts', () => {
const posts = ref([])
const loading = ref(false)
const error = ref(null)
async function fetchPosts() {
loading.value = true
error.value = null
try {
const response = await fetch('/api/posts')
if (!response.ok) throw new Error('获取失败')
posts.value = await response.json()
} catch (err) {
error.value = err.message
} finally {
loading.value = false
}
}
async function createPost(postData) {
const response = await fetch('/api/posts', {
method: 'POST',
body: JSON.stringify(postData)
})
const newPost = await response.json()
posts.value.push(newPost)
return newPost
}
return {
posts,
loading,
error,
fetchPosts,
createPost
}
})
3. 类型安全的 Store(TypeScript)
// stores/types.ts
export interface User {
id: number
name: string
email: string
}
export interface AuthState {
user: User | null
token: string
}
// stores/auth.ts
import { defineStore } from 'pinia'
import type { User, AuthState } from './types'
export const useAuthStore = defineStore('auth', {
state: (): AuthState => ({
user: null,
token: ''
}),
getters: {
isAuthenticated: (state): boolean => state.user !== null,
userName: (state): string => state.user?.name || ''
},
actions: {
setAuth(user: User, token: string): void {
this.user = user
this.token = token
},
clearAuth(): void {
this.user = null
this.token = ''
}
}
})
4. 测试 Store
// stores/__tests__/counter.spec.js
import { setActivePinia, createPinia } from 'pinia'
import { useCounterStore } from '../counter'
describe('Counter Store', () => {
beforeEach(() => {
setActivePinia(createPinia())
})
test('increment', () => {
const store = useCounterStore()
expect(store.count).toBe(0)
store.increment()
expect(store.count).toBe(1)
})
test('doubleCount getter', () => {
const store = useCounterStore()
store.count = 4
expect(store.doubleCount).toBe(8)
})
})
总结
什么时候使用哪种状态管理?
场景 | 推荐方案 | 理由 |
---|---|---|
简单组件状态 | 组件内 ref /reactive
|
简单直接 |
少量组件共享 | 响应式全局对象 | 快速实现 |
中型应用 | Pinia (组合式) | 类型安全,易于测试 |
大型企业应用 | Pinia + 严格模式 | 可维护性,团队协作 |
核心原则
- 单一数据源:全局状态集中管理
- 状态只读:通过 actions 修改状态
- 纯函数修改:相同的输入总是得到相同的输出
- 不可变更新:不直接修改原状态,而是创建新状态
Vue 内置组件全解析:提升开发效率的五大神器
在 Vue 开发中,除了我们日常编写的业务组件外,框架还提供了一系列内置组件,它们为我们处理常见的开发场景提供了优雅的解决方案。今天,我们就来深入探讨 Vue 的五大内置组件:
Transition
、TransitionGroup
、KeepAlive
、Teleport
和Suspense
。
1. Transition - 丝滑的过渡动画
什么是 Transition?
Transition 组件用于在元素或组件的插入、更新和移除时添加动画效果,让用户体验更加流畅。
基本使用
<template>
<button @click="show = !show">切换</button>
<Transition name="fade">
<p v-if="show">Hello, Vue!</p>
</Transition>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(true)
</script>
<style scoped>
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.5s ease;
}
.fade-enter-from,
.fade-leave-to {
opacity: 0;
}
</style>
过渡类名详解
Transition 组件会自动应用以下 6 个 CSS 类名:
-
v-enter-from
:进入动画的起始状态 -
v-enter-active
:进入动画的激活状态 -
v-enter-to
:进入动画的结束状态 -
v-leave-from
:离开动画的起始状态 -
v-leave-active
:离开动画的激活状态 -
v-leave-to
:离开动画的结束状态
注意:其中的 v
是默认前缀,可以通过 name
属性自定义。
JavaScript 钩子
除了 CSS 过渡,还可以使用 JavaScript 钩子:
<template>
<Transition
@before-enter="onBeforeEnter"
@enter="onEnter"
@after-enter="onAfterEnter"
@enter-cancelled="onEnterCancelled"
@before-leave="onBeforeLeave"
@leave="onLeave"
@after-leave="onAfterLeave"
@leave-cancelled="onLeaveCancelled"
>
<div v-if="show">内容</div>
</Transition>
</template>
<script setup>
import { ref } from 'vue'
const show = ref(true)
const onBeforeEnter = (el) => {
// 元素插入 DOM 前的回调
}
const onEnter = (el, done) => {
// 元素插入 DOM 后的回调
// 需要手动调用 done() 来结束过渡
done()
}
</script>
模式控制
<Transition mode="out-in">
<button :key="isEditing" @click="isEditing = !isEditing">
{{ isEditing ? '保存' : '编辑' }}
</button>
</Transition>
支持的模式:
-
in-out
:新元素先进入,当前元素后离开 -
out-in
:当前元素先离开,新元素后进入
2. TransitionGroup - 列表过渡专家
什么是 TransitionGroup?
TransitionGroup 组件专门用于处理动态列表中元素的进入、离开和移动的动画效果。
基本使用
<template>
<button @click="addItem">添加</button>
<button @click="removeItem">移除</button>
<TransitionGroup name="list" tag="ul">
<li v-for="item in items" :key="item.id">
{{ item.text }}
</li>
</TransitionGroup>
</template>
<script setup>
import { ref } from 'vue'
const items = ref([
{ id: 1, text: '项目 1' },
{ id: 2, text: '项目 2' },
{ id: 3, text: '项目 3' }
])
let nextId = 4
const addItem = () => {
items.value.push({ id: nextId++, text: `项目 ${nextId}` })
}
const removeItem = () => {
items.value.pop()
}
</script>
<style scoped>
.list-enter-active,
.list-leave-active {
transition: all 0.5s ease;
}
.list-enter-from {
opacity: 0;
transform: translateX(30px);
}
.list-leave-to {
opacity: 0;
transform: translateX(-30px);
}
/* 确保离开的元素脱离文档流 */
.list-leave-active {
position: absolute;
}
</style>
关键特性
- 必须设置 key:每个元素都需要唯一的 key
- 支持 CSS 变换:自动检测元素位置变化应用移动动画
- tag 属性:指定包裹容器的标签,默认为不渲染包裹元素
3. KeepAlive - 组件缓存大师
什么是 KeepAlive?
KeepAlive 组件用于缓存不活动的组件实例,避免重复渲染,保持组件状态。
基本使用
<template>
<div>
<button @click="currentTab = 'Home'">首页</button>
<button @click="currentTab = 'About'">关于</button>
<KeepAlive>
<component :is="currentTab" />
</KeepAlive>
</div>
</template>
<script setup>
import { ref, shallowRef } from 'vue'
import Home from './Home.vue'
import About from './About.vue'
const currentTab = ref('Home')
const tabs = {
Home,
About
}
</script>
高级配置
<KeepAlive
:include="/Home|About/"
:exclude="['Settings']"
:max="10"
>
<component :is="currentComponent" />
</KeepAlive>
- include:只有名称匹配的组件会被缓存(字符串、正则或数组)
- exclude:任何名称匹配的组件都不会被缓存
- max:最多可缓存的组件实例数量
生命周期钩子
被缓存的组件会获得两个新的生命周期钩子:
<script setup>
import { onActivated, onDeactivated } from 'vue'
onActivated(() => {
// 组件被激活时调用
console.log('组件激活')
})
onDeactivated(() => {
// 组件被停用时调用
console.log('组件停用')
})
</script>
4. Teleport - 任意门组件
什么是 Teleport?
Teleport 组件允许我们将组件模板的一部分"传送"到 DOM 中的其他位置,而不影响组件的逻辑关系。
基本使用
<template>
<div class="app">
<button @click="showModal = true">打开模态框</button>
<Teleport to="body">
<div v-if="showModal" class="modal">
<div class="modal-content">
<h2>模态框标题</h2>
<p>这是模态框内容</p>
<button @click="showModal = false">关闭</button>
</div>
</div>
</Teleport>
</div>
</template>
<script setup>
import { ref } from 'vue'
const showModal = ref(false)
</script>
<style scoped>
.modal {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
justify-content: center;
align-items: center;
}
.modal-content {
background: white;
padding: 20px;
border-radius: 8px;
}
</style>
多个 Teleport 到同一目标
<template>
<Teleport to="#modals">
<div>第一个模态框</div>
</Teleport>
<Teleport to="#modals">
<div>第二个模态框</div>
</Teleport>
</template>
渲染结果:
<div id="modals">
<div>第一个模态框</div>
<div>第二个模态框</div>
</div>
禁用 Teleport
<Teleport to="body" :disabled="isMobile">
<div>内容</div>
</Teleport>
5. Suspense - 异步组件管家
什么是 Suspense?
Suspense 组件用于协调组件树中的异步依赖,在等待异步组件时显示加载状态。
基本使用
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div class="loading">加载中...</div>
</template>
</Suspense>
</template>
<script setup>
import { defineAsyncComponent } from 'vue'
const AsyncComponent = defineAsyncComponent(() =>
import('./AsyncComponent.vue')
)
</script>
<style scoped>
.loading {
text-align: center;
padding: 20px;
color: #666;
}
</style>
异步 setup 组件
<template>
<Suspense>
<template #default>
<ComponentWithAsyncSetup />
</template>
<template #fallback>
<div>加载用户数据...</div>
</template>
</Suspense>
</template>
<script setup>
import { ref } from 'vue'
const ComponentWithAsyncSetup = {
async setup() {
const userData = await fetchUserData()
return { userData }
},
template: `<div>用户: {{ userData.name }}</div>`
}
async function fetchUserData() {
// 模拟 API 调用
return new Promise(resolve => {
setTimeout(() => {
resolve({ name: 'Vue 开发者' })
}, 2000)
})
}
</script>
事件处理
<template>
<Suspense @pending="onPending" @resolve="onResolve" @fallback="onFallback">
<AsyncComponent />
</Suspense>
</template>
<script setup>
const onPending = () => {
console.log('开始加载异步组件')
}
const onResolve = () => {
console.log('异步组件加载完成')
}
const onFallback = () => {
console.log('显示加载状态')
}
</script>
实战案例:组合使用内置组件
让我们看一个综合使用多个内置组件的例子:
<template>
<div class="app">
<!-- 标签页切换 -->
<nav>
<button
v-for="tab in tabs"
:key="tab.id"
@click="currentTab = tab.id"
>
{{ tab.name }}
</button>
</nav>
<!-- 主要内容区域 -->
<main>
<KeepAlive>
<Transition name="slide" mode="out-in">
<Suspense>
<template #default>
<component :is="currentTabComponent" />
</template>
<template #fallback>
<div class="loading">加载中...</div>
</template>
</Suspense>
</Transition>
</KeepAlive>
</main>
<!-- 全局通知 -->
<Teleport to="#notifications">
<TransitionGroup name="notification">
<div
v-for="notification in notifications"
:key="notification.id"
class="notification"
>
{{ notification.message }}
</div>
</TransitionGroup>
</Teleport>
</div>
</template>
<script setup>
import { ref, computed, defineAsyncComponent } from 'vue'
// 标签页状态
const currentTab = ref('home')
const tabs = [
{ id: 'home', name: '首页' },
{ id: 'profile', name: '个人资料' },
{ id: 'settings', name: '设置' }
]
// 异步组件
const currentTabComponent = computed(() =>
defineAsyncComponent(() => import(`./${currentTab.value}.vue`))
)
// 通知系统
const notifications = ref([])
// 添加通知
const addNotification = (message) => {
const id = Date.now()
notifications.value.push({ id, message })
setTimeout(() => {
notifications.value = notifications.value.filter(n => n.id !== id)
}, 3000)
}
</script>
<style scoped>
.slide-enter-active,
.slide-leave-active {
transition: all 0.3s ease;
}
.slide-enter-from {
opacity: 0;
transform: translateX(50px);
}
.slide-leave-to {
opacity: 0;
transform: translateX(-50px);
}
.notification-enter-active,
.notification-leave-active {
transition: all 0.3s ease;
}
.notification-enter-from {
opacity: 0;
transform: translateY(-30px);
}
.notification-leave-to {
opacity: 0;
transform: translateX(100%);
}
.loading {
text-align: center;
padding: 50px;
font-size: 18px;
}
</style>
总结
Vue 的内置组件为我们提供了强大的工具来处理常见的开发需求:
- Transition:为单个元素/组件添加过渡动画
- TransitionGroup:为列表项添加排序和动画效果
- KeepAlive:缓存组件状态,提升性能
- Teleport:将内容渲染到 DOM 任意位置
- Suspense:优雅处理异步组件加载状态
这些内置组件不仅功能强大,而且可以灵活组合使用,帮助我们构建更加优雅、高效的 Vue 应用。掌握它们的使用,将让你的 Vue 开发技能更上一层楼!
希望这篇文章能帮助你全面理解 Vue 的内置组件,并在实际项目中灵活运用。Happy Coding! 🚀
大前端时代来临,年轻人应该知道的——业内主流跨端框架对比
随着跨端框架生态的逐渐完善,市面上诸多 TO C 应用采用多端一码可以极大降低开发成本 提升产品迭代效率。 本文对市面主流跨端开发框架对比和分析。 希望对你有帮助, 欢迎一键三连~
一、详细对比表格
框架 | React Native | Flutter | Electron | Qt | Taro | |
---|---|---|---|---|---|---|
核心特点 | - 使用 JavaScript 和 React 进行开发 - 可以调用原生 API - 支持热重载 |
- 使用 Dart 语言 - 高性能的 UI 渲染引擎 - 支持 iOS、Android、Web、桌面等多平台 |
- 使用 Web 技术(HTML、CSS、JavaScript) - 打包为跨平台桌面应用 |
- 使用 C++ 开发跨平台应用 - 提供原生 UI 和图形库 - 支持嵌入式开发 |
- 基于 React 和 Vue - 支持多个平台(小程序、H5、原生) - 用 TypeScript/JavaScript 开发 |
|
主要语言 | JavaScript, TypeScript | Dart | JavaScript, HTML, CSS | C++, Python, QML | JavaScript, TypeScript, React/Vue | |
支持平台 | iOS, Android, Windows, macOS, Web | iOS, Android, Web, Windows, macOS, Linux | Windows, macOS, Linux | Windows, macOS, Linux, 嵌入式 | iOS, Android, 微信小程序, H5, 支付宝小程序等 | |
优势 | - 大量社区支持和库 - 可直接访问原生代码 - 热重载提高开发效率 - 对比其他框架,较成熟且稳定 |
- 强大的 UI 渲染能力,支持高性能应用 - 一次开发多平台运行 - 丰富的组件和插件生态 |
- 适合桌面端应用开发 - 跨平台支持,包括 Windows、macOS 和 Linux - 可以与原生模块交互 |
- 性能优秀,适合大型应用和嵌入式设备 - 支持丰富的 UI 和图形渲染功能 - 跨平台开发,适合企业级应用 |
- 适合多平台开发,特别是小程序 - 支持 React 和 Vue,开发灵活 - 生成小程序和 H5 能力强大 |
|
不足 | - 性能略逊于原生应用,复杂场景下需优化 - 原生模块集成较为复杂 - 对比其他框架,初期配置略复杂 |
- 需要学习 Dart 语言 - 对于复杂原生功能的支持较弱 - 对已有项目的接入可能存在困难 |
- 性能较低,体积较大 - 相比原生桌面应用,启动速度较慢 - 需要较高的资源消耗 |
- 学习曲线较陡,尤其是 C++ 部分 - 文档较少,社区相对较小 - 开发效率较低,相比其他框架更复杂 |
- 适合中小型应用,性能和UI相对简单 - 对于复杂的多端需求,可能需要大量配置 - 相较于其他框架,支持的原生功能较少 |
|
开发效率 | 高,热重载和组件化带来较高的开发效率 | 高,尤其适合UI复杂的应用,热重载功能也提升开发效率 | 中,桌面应用的开发相对较复杂 | 低,开发涉及底层代码,需要较高的技术要求 | 高,支持小程序开发,适合快速开发与迭代 | |
性能 | 较好,但在性能敏感的场景下需要优化 | 优秀,接近原生性能,UI 渲染能力强 | 较差,性能开销较大,适合桌面应用但不适合性能要求高的应用 | 非常好,原生性能,特别适合大规模企业级应用 | 中,适合小程序和H5,性能不如原生开发 | |
应用广泛度 | 高,广泛应用于电商、社交、金融等多种行业 | 较高,尤其在新的项目和需要高性能UI的应用中受到青睐 | 中,主要用于桌面端应用,适用于一些企业工具类应用 | 中,主要用于嵌入式设备和企业级应用 | 高,特别是在国内市场,主要用于小程序开发 | |
适用场景 | - 社交、购物、电商、新闻、娱乐类应用 - 需要快速开发、跨平台的应用 |
- 高度定制化的应用,尤其是 UI 复杂的移动应用和桌面应用 | - 需要跨平台桌面端应用,适用于各类办公软件、开发工具等 | - 企业级应用 - 嵌入式系统开发 - 高性能应用 |
- 多平台(小程序+Web)的跨端应用,特别适合中国市场的需求 | |
生态支持 | 强大的社区支持,丰富的第三方库和插件 | 迅速发展的生态,Google 和 Flutter 社区的支持 | 较小,主要由 Electron 官方和一些社区维护 | 适合专业开发者,企业级应用较多 | 国内市场的支持较强,针对小程序有深度优化 |
二、总结:
React Native:开发效率高,生态支持丰富,但性能略逊于原生应用。
Flutter:性能优秀,UI 渲染能力强,适用于需要复杂 UI 的跨平台应用,学习曲线稍陡,需要掌握 Dart。
Electron:主要用于桌面端应用,适合工具类和办公软件,但性能和体积较大,不适用于对性能要求较高的应用。
Qt:适合企业级桌面应用和嵌入式开发,性能强大,支持多平台,但学习曲线较陡,开发效率较低。
Taro:特别适用于小程序开发和 H5 应用,支持多个平台,开发效率高,适合国内市场。
JavaScript语法进阶(一)
原始值和引用值
栈跟堆的特点
- 栈
- 先进后出
- 内存分配连续且自动管理
- 访问速度快
- 空间比较小
- 堆
- 空间大
- 内存不是连续的,管理依赖垃圾回收机制
- 访问速度相对于栈比较慢
原始值类型存在7种
- Number(数字):表示数值,包括整数和浮点数。
- String(字符串):表示文本数据,使用引号括起来。
- Boolean(布尔值):表示逻辑值,即true或者false.
- Null(空):表示一个空值或没有值的对象。
- Undefined(未定义):表示一个未被赋值的变量的值
- Symbol(唯一值符号):表示唯一的标识符。
- bigint:表示任意精度的整数,用 n作为字面量后缀
// number
const a = 1
// string
const b = 'zifuch'
引用值类型
- 对象,对象包括为数组对象,日期对象,函数对象,等等等,一切皆对象
const obj = { a:1, b:2 } const arr = ['1','2','3']
两者存值的方式
-
原始值存储在栈中
let a = 1; let b = 2;
-
引用值存储在推中
const a = { b:1, c:2 }
复制值
-
原始值复制
let a = 1; let b = a; b = 2; console.log("a的值是:",a); console.log("b的值是:",b);
-
引用值复制
const a = { b:1, c:2, } const copyA = a; copy.c = 5; console.log("a.c的值是:",a.c);
-
引用值复制2
const a = { b:1, c:2, } const copyA = a; copyA = { b: 3, c: 4, } copy.c = 5; console.log("a.c的值是:",a.c);
浅拷贝和深拷贝
-
浅拷贝
浅拷贝是只复制对象的第一层属性,如果属性是引用类型(对象、数组等),拷贝的是引用地址,而不是新对象。
- object.assign()
- 扩展运行符...
const obj1 = { a: 1, b: { c: 2 } }; const obj2 = Object.assign({}, obj1); obj2.a = 100; // 不影响 obj1 obj2.b.c = 200; // 影响 obj1,因为 b 是引用 console.log(obj1.b.c); // 200(共享 b 对象)
-
深拷贝
深拷贝会递归复制对象的所有层级属性,确保拷贝后的对象与原对象完全独立。
- JSON.parse(JSON.stringify(...))
- structuredClone()浏览器内置API
- Lodash工具库
垃圾回收机制
JS的垃圾回收机制(Garbage Collection,简称GC)帮我们自动管理内存,对于不再使用的对象占用的内存进行释放。
- Garbage : 指不再被引用、不可达的内存对象。
- Collection: 指 JS 引擎自动检测并释放这些无用内存的过程。 常见的垃圾回收机制有两种,引用计数和标记清除。
引用计数
每个对象都有一个计数器,记录当前有多少个引用指向它。
规则
- 声明变量并给它赋一个引用值的时候,值的引用数+1
- 类似的把同一个值又被赋值给另外一个变量,值的引用数也+1
- 保存对该引用的变量被其它值给覆盖的时候,值的引用数-1
- 当引用解除(比如赋值为null)时,值的引用数-1
let obj = { name: "JS" }; // 引用计数 +1
let a = obj; // 引用计数 +1
obj = null; // 引用计数 -1 (现在还剩 a 引用)
b = null; // 引用计数 -1 (没有引用了,计数为 0 → 可回收)
缺点
当出现循环引用的情况出现的时候,引用计数永远不会清0。
function problem() {
let objectA = new Object(); // A对象引用计数 +1
let objectB = new Object(); // B对象引用计数 +1
objectA.someOtherObject = objectB; // B对象引用计数 +1
objectB.anotherObject = objectA; // A对象引用计数 +1
}
problem();
那有人说,我都置为null不就可以了,比如像下这样
function problem() {
let objectA = new Object(); // A对象引用计数 +1
let objectB = new Object(); // B对象引用计数 +1
objectA.someOtherObject = objectB; // B对象引用计数 +1
objectB.anotherObject = objectA; // A对象引用计数 +1
objectA.someOtherObject = null;
objectB.anotherObject = null;
let objectA = null;
let objectB = null;
}
problem();
但是现实开发中的循环引用会复杂很多,开发者很难自己追踪到里面的关系,容易造成内存泄漏。so,它被淘汰了。
标记清除
标记清除是JavaScript中最常用的垃圾回收机制,特别是在V8引擎之中,而其核心思想是可达性(Reachability)
规则
标记阶段: 垃圾回收器从根对象(通常是全局对象、活动执行栈和闭包等)出发,遍历所有可访问的对象,并标记为活动对象。在这个阶段,垃圾回收器会识别出所有被引用的对象,将其标记为“存活”。
清除阶段: 在标记阶段完成后,垃圾回收器会对堆内存进行扫描,清除所有未标记的对象,这些对象被认为是“垃圾”,因为它们不再被任何活动对象引用。清除阶段会释放这些垃圾对象所占用的内存空间,使其可用于未来的对象分配。
作用域
概念 : js代码在查找变量时的一个范围。
词法作用域
作用域在代码编写时就已经确定下来,并且由函数声明的位置决定,而不是由函数调用的位置决定。
var name = "global";
function foo() {
console.log(name);
}
function bar() {
var name = "bar";
foo();
}
bar(); // 输出global
JS的三个作用域
- 全局作用域: 对浏览器来说全局的作用域的话就是挂载window上的变量,或者是顶层用var声明的变量。使用 let 和 const 的顶级声明不会定义在全局上下文中,但在作用域链解析上效果是一样的。
- 函数作用域: 在函数执行的时候,函数内部的变量具有函数作用域。
- 块级作用域: 嵌套在{}括号里面的变量(var声明的变量不具备块级作用域)
执行上下文和执行上下文栈
执行上下文(上下文):变量或函数的上下文决定他们能访问到哪些数据。每个上下文都有一个关联的词法环境(Lexical Environment)\变量对象(variable object)。
执行上下文栈:当代码执行流进入函数时,函数的上下文被推到一个上下文栈上。 在函数执行完之后,上下文栈会弹出该函数上下文,将控制权返还给之前的执行上下文。ECMAScript 程序的执行流就是通过这个上下文栈进行控制的。
let a = 1
function f1() {
const b = 2;
function f2 () {
const c = 3;
}
f2();
}
f1();
作用域链
上下文中的代码在执行的时候,会创建变量对象的一个作用域链(scope chain),指向上一个作用域。这个作用域链决定了当前上下文中的代码在访问变量和函数时的顺序
let a = 1
function f1() {
const b = 2;
function f2 () {
const c = 3;
}
f2();
}
f1();
例子
var a = 10;
var b = 10;
var c = 10;
function foo() {
var b = 20;
function bar() {
var c = 30;
console.log(a, b, c,d);
}
bar();
}
foo();
注意点:
- 函数的参数属于当前函数上下文。
- 如果内部作用域和外部作用域使用相同的变量名,则直接使用离当前作用域近的变量名,有书籍称为遮蔽。
分享文章链接
- juejin.cn/post/721142… 作者对《你不知道的JS》第一部分第二部分总结的挺好。
- github.com/getify/You-… 《你不知道的js》原文
闭包
概念:闭包指的是那些引用了另一个函数作用域中变量的函数,通常是在嵌套中实现的。(即函数内部嵌套函数,内部函数使用了外部函数作用域变量)
function outer() {
let count = 0; // outer 的局部变量
function inner() {
count++;
console.log(count);
}
return inner;
}
const fn = outer(); // outer 执行结束,但 count 没被销毁
fn(); // 1
fn(); // 2
fn(); // 3
为了帮助理解闭包,举了以下三个情况,希望对你有帮助。
- 情况1
function outer() { let count = 0; // outer 的局部变量 function inner() { count++; console.log(count); } return inner; } // 定义了函数 函数没有执行 可以理解为闭包的结构体有了 但是闭包不存在
- 情况2
function outer() { let count = 0; // outer 的局部变量 function inner() { count++; console.log(count); } return inner; } outer(); // 闭包产生了 但是闭包不会持久存在,因为没有保留对它的引用
- 情况3
function outer() { let count = 0; // outer 的局部变量 function inner() { count++; console.log(count); } return inner; } fn = outer(); // 闭包产生了 fn保留了对它的引用 持久存在
this
概念:this 引用的是把函数当成方法调用的上下文对象,这时候通常称其为 this 值。
默认绑定
全局上下文中调用函数的this指向window
window.color = 'red'
function fn() {
consoel.log("color:",this.color)
}
fn(); // color: 'red'
隐式绑定
函数作为对象的方法调用,this 绑定到该对象
let obj = {
color: 'blue'
fn: fn;
}
function fn () {
console.log("color:",this.color);
}
obj.fn(); // color: 'blue'
显示绑定
使用call、apply、bind显示指定this
function fn() {
console.log("color:",this.color);
}
const obj = { obj: 'yellow' };
greet.call(obj); // color: 'yellow'
new关键字绑定
构造函数被new调用时,this指向新创建的对象
function Color (color) {
this.color = color;
}
const c = new Color("yellow");
console.log(c.color); // 'yellow'
注意
- 箭头函数不绑定自己的this,它会捕获定义是的外层作用域中的this
window.color = 'red';
let obj = {
color: 'green';
fn: () => {
console.log('color:',this.color);
}
}
obj.fn(); // color: 'red'
- 绑定的优先级
new绑定>显示绑定>隐式绑定>默认绑定
// 以下是显示绑定和隐式绑定对比的列子
function foo() {
console.log( this.a );
}
var obj1 = {
a: 2,
foo: foo
};
var obj2 = {
a: 3,
foo: foo
};
obj1.foo(); // 2
obj2.foo(); // 3
obj1.foo.call( obj2 ); // 3
obj2.foo.call( obj1 ); // 2
原型和原型链
JS是一门面向对象语言,那么面向对象语言的特点是封装、继承、多态。在C++或者Java里面都是由类去实现,但JS没有类的说法,在JS里面是由原型实现的,ES6才拥有了类,但本质上是原型的语法糖。
构造函数:构造函数是用于创建特定类型对象/实例的一种方法。默认首字母大写。
new关键字:用于创建构造函数的对象。
在c++里面我们创建同一类型的对象一般是这么写
#include <iostream>
using namespace std;
class Animal {
public:
// 成员变量
string name;
int age;
// 构造函数
Animal(string n, int a) {
name = n;
age = a;
}
// 成员方法:打印动物信息
void printInfo() {
cout << "Animal Name: " << name << ", Age: " << age << endl;
}
};
int main() {
// 创建对象
Animal dog("Buddy", 3);
Animal cat("Kitty", 2);
// 调用方法
dog.printInfo(); // Animal Name: Buddy, Age: 3
cat.printInfo(); // Animal Name: Kitty, Age: 2
return 0;
}
在js我们不使用原型的话大概是这么写
// 构造函数
function Animal(name, age) {
this.name = name;
this.age = age;
// 方法直接在构造函数中定义
this.printInfo = function() {
console.log(`Animal Name: ${this.name}, Age: ${this.age}`);
};
}
// 创建对象
const dog = new Animal("Buddy", 3);
const cat = new Animal("Kitty", 2);
// 调用方法
dog.printInfo(); // Animal Name: Buddy, Age: 3
cat.printInfo(); // Animal Name: Kitty, Age: 2
这么写的缺点是:每new一次,就会在内存里重新创建一个新的函数对象,虽然它两长的一模一样,但他们指向的函数不一样,会导致内存浪费。
dog.prinrInfo === cat.printInfo // false
// 插播: == 不比较类型 === 需要比较类型
// 1 == '1' √ 1 === '1' ×
使用原型进行改善
// 构造函数
function Animal(name, age) {
this.name = name;
this.age = age;
}
Animal.prototype.pritInfo = function {
console.log(`Animal Name: ${this.name}, Age: ${this.age}`);
}
// 创建对象
const dog = new Animal("Buddy", 3);
const cat = new Animal("Kitty", 2);
// 调用方法
dog.printInfo(); // Animal Name: Buddy, Age: 3
cat.printInfo(); // Animal Name: Kitty, Age: 2
// dog.printInfo === cat.printInfo;
接下来,进入正文...
显示原型
每一个函数身上都会创建一个prototype属性,函数原型是一个对象。在它上面定义的属性和方法可以被对象实例共享。
function Animal () {
//.....
}
Animal.prototype.name = '猫'
const animal = new Animal();
console.log(animal.name); // '猫'
constructor
原型对象身上存在一个默认的constructor属性,指回与之关联的构造函数。
Animal.prototype.constructor === Animal
隐式原型
每次调用构造函数创建一个新实例,这个实例的内部 [[Prototype]] 指针就会被赋值为构造函数的原型对象。
在现代化浏览器如Firefox、Safari 和 Chrome 会在每个对象上暴露 "proto" 属性,通过这个属性可以访问对象的原型。
function Animal () {
//.....
}
let animal = new Animal();
animal.__proto__ === Animal.prototype;
原型链
构造函数的原型是一个对象,那么会存在这么一个关系
Animal.prototype.__proto__ === Object.prototype
那么Object原型的原型是什么?为null。正常的原型链都会终止于 Object 的原型对象。
Animal.prototype.__proto__.__proto__ === null
那么构造函数也是一个对象,由Function构造函数创建,Function构造函数由也是由本身创建。
总结:
当我们通过对象访问它的属性的时候,会按照这个属性的名称开始搜索。先搜索对象实例本身,如果对象实例本身没有找到就会沿着隐式原型__proto__上的原型对象上查找,直至找到原型链的终端null为止。
为什么是隐式原型链?实例与构造函数原型之间有直接的联系,但实例与构造函数之间没有。