[{"data":1,"prerenderedAt":8717},["ShallowReactive",2],{"page-\u002Fvue\u002Fvue源码解读-通用工具函数":3},{"id":4,"title":5,"body":6,"description":12,"extension":8711,"meta":8712,"navigation":1127,"path":8713,"seo":8714,"stem":8715,"__hash__":8716},"content\u002FVue\u002Fvue源码解读-通用工具函数.md","Vue源码解读 通用工具函数",{"type":7,"value":8,"toc":8585},"minimark",[9,13,28,31,60,63,66,71,78,86,89,99,102,117,128,134,137,144,150,157,167,175,185,188,193,200,205,207,225,227,249,252,267,270,272,280,282,290,293,296,303,314,317,324,329,336,440,454,494,505,508,517,552,555,573,578,582,593,746,785,788,843,846,882,891,897,900,925,1008,1036,1043,1052,1258,1261,1379,1385,1404,1441,1447,1483,1558,1565,1667,1686,1759,1778,1834,1840,2259,2267,2326,2355,2395,2415,2418,2426,2433,2436,2465,2473,2481,2488,2501,2507,2531,2533,2540,2549,2627,2631,2634,2654,2712,2722,2727,2730,2764,2771,2774,2807,2814,2817,2843,2849,2852,2900,2907,2987,2993,3030,3042,3084,3089,3128,3144,3149,3183,3190,3300,3308,3378,3386,3389,3444,3450,3456,3543,3547,3555,3602,3610,3678,3684,3688,3738,3741,3839,3849,3856,3858,3883,3891,3894,3912,3916,3921,3939,3943,3946,3953,4060,4186,4196,4275,4289,4292,4359,4372,4375,4383,4391,4418,4426,4445,4449,4452,4463,4472,4526,4532,4535,4564,4568,4578,4658,4665,4672,4701,4704,4711,4869,4878,4883,4949,5069,5095,5099,5102,5130,5134,5144,5155,5166,5173,5426,5434,5438,5578,5595,5788,5795,5803,5820,5824,5830,5917,5987,6000,6026,6034,6059,6062,6122,6133,6151,6295,6299,6311,6344,6351,6453,6460,6516,6523,6648,6655,6671,6674,6706,6708,6716,6724,6799,6803,6812,6926,6930,6942,6964,6972,6980,7070,7081,7099,7105,7108,7111,7234,7345,7361,7368,7377,7405,7413,7439,7442,7445,7452,7465,7467,7474,7478,7481,7503,7523,7533,7539,7566,7574,7590,7594,7601,7616,7620,7783,7793,7800,7804,7807,7866,7879,7881,7885,7898,8081,8083,8089,8096,8117,8130,8140,8226,8235,8237,8244,8256,8318,8325,8333,8355,8359,8366,8403,8407,8413,8461,8464,8581],[10,11,12],"p",{},"尝试将给定的值宽松地转换为数字\u002F**",[14,15,16,20,22,25],"ul",{},[17,18,19],"li",{},"通用工具函数库",[17,21],{},[17,23,24],{},"该模块包含了 Vue 3 中最常用的工具函数，提供了类型检查、字符串处理、",[17,26,27],{},"对象操作、数组操作等基础功能。这些函数被 Vue 的各个核心模块广泛使用。\n*\u002F",[10,29,30],{},"import { makeMap } from '.\u002FmakeMap'",[10,32,33,34,48,49,51,52,54,55,57,58],{},"\u002F** 空对象常量，开发环境使用 Object.freeze 冻结 ",[35,36,37,38,42,43,47],"em",{},"\u002F\nexport const EMPTY_OBJ: { readonly ",[39,40,41],"span",{},"key: string",": any } = ",[44,45,46],"strong",{},"DEV","\n? Object.freeze({})\n: {}\n\u002F","* 空数组常量，开发环境使用 Object.freeze 冻结 *\u002F\nexport const EMPTY_ARR: readonly never",[39,50],{}," = ",[44,53,46],{}," ? Object.freeze(",[39,56],{},") : ",[39,59],{},[10,61,62],{},"\u002F** 空函数，用于默认值 *\u002F\nexport const NOOP = (): void => {}",[10,64,65],{},"\u002F**",[14,67,68],{},[17,69,70],{},"总是返回 false 的函数\n*\u002F\nexport const NO = () => false",[10,72,73,74,77],{},"export const isOn = (key: string): boolean =>\nkey.charCodeAt(0) === 111 \u002F* o ",[35,75,76],{},"\u002F &&\nkey.charCodeAt(1) === 110 \u002F"," n *\u002F &&\n\u002F\u002F uppercase letter\n(key.charCodeAt(2) > 122 || key.charCodeAt(2) \u003C 97)",[10,79,80,81,85],{},"export const isModelListener = (key: string): key is ",[82,83,84],"code",{},"onUpdate:${string}"," =>\nkey.startsWith('onUpdate:')",[10,87,88],{},"export const extend: typeof Object.assign = Object.assign",[10,90,91,92],{},"export const remove = ",[93,94,95,96,98],"t",{},"(arr: T",[39,97],{},", el: T): void => {\nconst i = arr.indexOf(el)\nif (i > -1) {\narr.splice(i, 1)\n}\n}",[10,100,101],{},"const hasOwnProperty = Object.prototype.hasOwnProperty\nexport const hasOwn = (\nval: object,\nkey: string | symbol,\n): key is keyof typeof val => hasOwnProperty.call(val, key)",[10,103,104,105,108,109],{},"export const isArray: typeof Array.isArray = Array.isArray\nexport const isMap = (val: unknown): val is Map\u003Cany, any> =>\ntoTypeString(val) === '",[39,106,107],{},"object Map","'\nexport const isSet = (val: unknown): val is Set",[110,111,112,113,116],"any",{}," =>\ntoTypeString(val) === '",[39,114,115],{},"object Set","'",[10,118,119,120,123,124,127],{},"export const isDate = (val: unknown): val is Date =>\ntoTypeString(val) === '",[39,121,122],{},"object Date","'\nexport const isRegExp = (val: unknown): val is RegExp =>\ntoTypeString(val) === '",[39,125,126],{},"object RegExp","'\nexport const isFunction = (val: unknown): val is Function =>\ntypeof val === 'function'\nexport const isString = (val: unknown): val is string => typeof val === 'string'\nexport const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'\nexport const isObject = (val: unknown): val is Record\u003Cany, any> =>\nval !== null && typeof val === 'object'",[10,129,130,131],{},"export const isPromise = \u003CT = any>(val: unknown): val is Promise",[93,132,133],{}," => {\nreturn (\n(isObject(val) || isFunction(val)) &&\nisFunction((val as any).then) &&\nisFunction((val as any).catch)\n)\n}",[10,135,136],{},"export const objectToString: typeof Object.prototype.toString =\nObject.prototype.toString\nexport const toTypeString = (value: unknown): string =>\nobjectToString.call(value)",[10,138,139,140,143],{},"export const toRawType = (value: unknown): string => {\n\u002F\u002F extract \"RawType\" from strings like \"",[39,141,142],{},"object RawType","\"\nreturn toTypeString(value).slice(8, -1)\n}",[10,145,146,147,116],{},"export const isPlainObject = (val: unknown): val is object =>\ntoTypeString(val) === '",[39,148,149],{},"object Object",[10,151,152,153,156],{},"export const isIntegerKey = (key: unknown): boolean =>\nisString(key) &&\nkey !== 'NaN' &&\nkey",[39,154,155],{},"0"," !== '-' &&\n'' + parseInt(key, 10) === key",[10,158,159,160,166],{},"export const isReservedProp: (key: string) => boolean = \u002F",[35,161,162,163],{},"@",[44,164,165],{},"PURE","\u002F makeMap(\n\u002F\u002F the leading comma is intentional so empty string \"\" is also included\n',key,ref,ref_for,ref_key,' +\n'onVnodeBeforeMount,onVnodeMounted,' +\n'onVnodeBeforeUpdate,onVnodeUpdated,' +\n'onVnodeBeforeUnmount,onVnodeUnmounted',\n)",[10,168,169,170,174],{},"export const isBuiltInDirective: (key: string) => boolean =\n\u002F",[35,171,162,172],{},[44,173,165],{},"\u002F makeMap(\n'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo',\n)",[10,176,177,178,181,182,184],{},"const cacheStringFunction = \u003CT extends (str: string) => string>(fn: T): T => {\nconst cache: Record\u003Cstring, string> = Object.create(null)\nreturn ((str: string) => {\nconst hit = cache",[39,179,180],{},"str","\nreturn hit || (cache",[39,183,180],{}," = fn(str))\n}) as T\n}",[10,186,187],{},"const camelizeRE = \u002F-\\w\u002Fg\n\u002F**",[14,189,190],{},[17,191,192],{},"@private\n*\u002F\nexport const camelize: (str: string) => string = cacheStringFunction(\n(str: string): string => {\nreturn str.replace(camelizeRE, c => c.slice(1).toUpperCase())\n},\n)",[10,194,195,196,199],{},"const hyphenateRE = \u002F\\B(",[39,197,198],{},"A-Z",")\u002Fg\n\u002F**",[14,201,202],{},[17,203,204],{},"@private\n*\u002F\nexport const hyphenate: (str: string) => string = cacheStringFunction(\n(str: string) => str.replace(hyphenateRE, '-$1').toLowerCase(),\n)",[10,206,65],{},[14,208,209],{},[17,210,211,212],{},"@private\n*\u002F\nexport const capitalize: ",[93,213,215,216],{"extends":214,"string":214},"","(str: T) => Capitalize",[93,217,218,219],{}," =\ncacheStringFunction(",[93,220,221,222],{"extends":214,"string":214},"(str: T) => {\nreturn (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize",[93,223,224],{},"\n})",[10,226,65],{},[14,228,229],{},[17,230,231,232],{},"@private\n*\u002F\nexport const toHandlerKey: ",[93,233,234,235,238,239],{"extends":214,"string":214},"(\nstr: T,\n) => T extends '' ? '' : ",[82,236,237],{},"on${Capitalize\u003CT>}"," = cacheStringFunction(\n",[93,240,241,242,245,246,248],{"extends":214,"string":214},"(str: T) => {\nconst s = str ? ",[82,243,244],{},"on${capitalize(str)}"," : ``\nreturn s as T extends '' ? '' : ",[82,247,237],{},"\n},\n)",[10,250,251],{},"\u002F\u002F compare whether a value has changed, accounting for NaN.\nexport const hasChanged = (value: any, oldValue: any): boolean =>\n!Object.is(value, oldValue)",[10,253,254,255,257,258,260,261,266],{},"export const invokeArrayFns = (fns: Function",[39,256],{},", ...arg: any",[39,259],{},"): void => {\nfor (let i = 0; i \u003C fns.length; i++) {\nfns",[262,263,265],"a",{"href":264},"...arg","i","\n}\n}",[10,268,269],{},"export const def = (\nobj: object,\nkey: string | symbol,\nvalue: any,\nwritable = false,\n): void => {\nObject.defineProperty(obj, key, {\nconfigurable: true,\nenumerable: false,\nwritable,\nvalue,\n})\n}",[10,271,65],{},[14,273,274,277],{},[17,275,276],{},"\"123-foo\" will be parsed to 123",[17,278,279],{},"This is used for the .number modifier in v-model\n*\u002F\nexport const looseToNumber = (val: any): any => {\nconst n = parseFloat(val)\nreturn isNaN(n) ? val : n\n}",[10,281,65],{},[14,283,284,287],{},[17,285,286],{},"Only concerns number-like strings",[17,288,289],{},"\"123-foo\" will be returned as-is\n*\u002F\nexport const toNumber = (val: any): any => {\nconst n = isString(val) ? Number(val) : NaN\nreturn isNaN(n) ? val : n\n}",[10,291,292],{},"\u002F\u002F for typeof global checks without @types\u002Fnode\ndeclare var global: {}",[10,294,295],{},"let _globalThis: any\nexport const getGlobalThis = (): any => {\nreturn (\n_globalThis ||\n(_globalThis =\ntypeof globalThis !== 'undefined'\n? globalThis\n: typeof self !== 'undefined'\n? self\n: typeof window !== 'undefined'\n? window\n: typeof global !== 'undefined'\n? global\n: {})\n)\n}",[10,297,298,299,302],{},"const identRE = \u002F^[_$a-zA-Z\\xA0-\\uFFFF]",[39,300,301],{},"_$a-zA-Z0-9\\xA0-\\uFFFF","*$\u002F",[10,304,305,306,309,310,313],{},"export function genPropsAccessExp(name: string): string {\nreturn identRE.test(name)\n? ",[82,307,308],{},"__props.${name}","\n: ",[82,311,312],{},"__props[${JSON.stringify(name)}]","\n}",[10,315,316],{},"export function genCacheKey(source: string, options: any): string {\nreturn (\nsource +\nJSON.stringify(options, (_, val) =>\ntypeof val === 'function' ? val.toString() : val,\n)\n)\n}",[10,318,319,320,323],{},"它集中了 Vue 框架在所有模块（如响应式、编译器、运行时）中都需要使用的",[44,321,322],{},"底层、高性能的基础操作","，涵盖了类型检查、字符串格式化、数组操作和性能优化等多个方面。",[325,326,328],"h2",{"id":327},"_1-核心常量与空操作","1. 核心常量与空操作",[10,330,331,332,335],{},"​\t这些是用于提高代码可读性、",[44,333,334],{},"避免重复创建对象和保证类型安全的常量","。",[337,338,339,355],"table",{},[340,341,342],"thead",{},[343,344,345,349,352],"tr",{},[346,347,348],"th",{},"函数\u002F常量",[346,350,351],{},"作用",[346,353,354],{},"目的\u002F原理",[356,357,358,386,407,422],"tbody",{},[343,359,360,368,371],{},[361,362,363],"td",{},[44,364,365],{},[82,366,367],{},"EMPTY_OBJ",[361,369,370],{},"空对象常量",[361,372,373,374,377,378,381,382,385],{},"避免重复创建空对象。在 ",[82,375,376],{},"__DEV__","（开发环境）下使用 ",[82,379,380],{},"Object.freeze()"," ",[44,383,384],{},"冻结","，确保对象的不可变性，避免意外修改。",[343,387,388,395,398],{},[361,389,390],{},[44,391,392],{},[82,393,394],{},"EMPTY_ARR",[361,396,397],{},"空数组常量",[361,399,400,401,403,404,335],{},"与 ",[82,402,367],{}," 相同，提供一个",[44,405,406],{},"冻结的空数组",[343,408,409,416,419],{},[361,410,411],{},[44,412,413],{},[82,414,415],{},"NOOP",[361,417,418],{},"空函数",[361,420,421],{},"“No Operation”的缩写，用于函数参数的默认值，表示什么都不做。",[343,423,424,431,437],{},[361,425,426],{},[44,427,428],{},[82,429,430],{},"NO",[361,432,433,434],{},"总是返回 ",[82,435,436],{},"false",[361,438,439],{},"用于作为钩子函数的默认值，例如，如果某个选项未提供，则默认为不启用。",[10,441,442,443,445,446,453],{},"这里讲一下冻结的空数组的含义：",[82,444,380],{}," 是 JavaScript 中用于实现",[44,447,448,449,452],{},"不可变性（Immutability）",[44,450,451],{},"的方法。当一个对象（包括数组）被冻结后，以下操作将","被禁止","，并且在严格模式下会抛出错误：",[14,455,456,461,466,471,477],{},[17,457,458],{},[44,459,460],{},"修改现有属性的值。",[17,462,463],{},[44,464,465],{},"添加新属性。",[17,467,468],{},[44,469,470],{},"删除现有属性。",[17,472,473,476],{},[44,474,475],{},"修改数组元素","（因为数组元素本质上是属性）。",[17,478,479,482,483,486,487,486,490,493],{},[44,480,481],{},"调用数组变异方法","（如 ",[82,484,485],{},"push","、",[82,488,489],{},"pop",[82,491,492],{},"splice"," 等）。",[10,495,496,497,500,501,504],{},"因此，",[82,498,499],{},"Object.freeze([])"," 得到的是一个",[44,502,503],{},"永远为空、且不能被任何人修改","的数组。在 Vue 源码中，使用冻结的空数组主要有以下两个目的：",[10,506,507],{},"A. 运行时安全 (Safety)",[10,509,510,511,514,515,335],{},"当 Vue 组件或",[44,512,513],{},"内部函数需要返回一个空数组作为默认值时","，它们会返回 ",[82,516,394],{},[14,518,519,537],{},[17,520,521,524,525,528,529,532,533,536],{},[44,522,523],{},"如果没有冻结："," 如果一个函数返回了 ",[82,526,527],{},"[]","，而调用方不小心对它执行了 ",[82,530,531],{},"push()"," 操作，那么这个",[44,534,535],{},"共享","的空数组就被污染了，可能会导致其他依赖这个空数组的地方出现意外的 bug。",[17,538,539,545,546,548,549,335],{},[44,540,541,542,544],{},"使用 ",[82,543,394],{},"："," 任何试图修改 ",[82,547,394],{}," 的操作都会失败或抛出错误，从而确保了",[44,550,551],{},"代码的安全性和可预测性",[10,553,554],{},"B. 性能优化 (Performance)",[14,556,557],{},[17,558,559,562,563,565,566,335],{},[44,560,561],{},"避免重复创建："," 在 Vue 的生命周期中，可能会有成千上万次需要返回一个空数组的场景（例如，组件没有子节点、某个选项没有提供）。通过共享一个全局的 ",[82,564,394],{}," 常量，",[44,567,568,569,572],{},"避免了每次都创建新的数组对象 (",[82,570,571],{},"new Array()",") 的内存分配和垃圾回收开销",[574,575,577],"h3",{"id":576},"_3-代码中的条件判断","3. 代码中的条件判断",[325,579,581],{"id":580},"_2-类型检查工具type-checking","2. 类型检查工具（Type Checking）",[10,583,584,585,588,589,592],{},"​\t这组函数",[44,586,587],{},"用于在运行时安全、准确地判断一个值的类型","。Vue 倾向于使用 ",[82,590,591],{},"Object.prototype.toString"," 进行精确类型检查。",[337,594,595,607],{},[340,596,597],{},[343,598,599,602,604],{},[346,600,601],{},"函数",[346,603,351],{},[346,605,606],{},"原理",[356,608,609,630,652,687,708,731],{},[343,610,611,618,621],{},[361,612,613],{},[44,614,615],{},[82,616,617],{},"toTypeString",[361,619,620],{},"获取值的原始类型字符串。",[361,622,541,623,626,627,335],{},[82,624,625],{},"Object.prototype.toString.call(value)","，返回如 ",[82,628,629],{},"\"[object Array]\"",[343,631,632,639,642],{},[361,633,634],{},[44,635,636],{},[82,637,638],{},"toRawType",[361,640,641],{},"提取原始类型名。",[361,643,644,645,648,649,335],{},"从 ",[82,646,647],{},"[object RawType]"," 中提取 ",[82,650,651],{},"RawType",[343,653,654,674,677],{},[361,655,656],{},[44,657,658,661,662,661,665,661,668,661,671],{},[82,659,660],{},"isMap",", ",[82,663,664],{},"isSet",[82,666,667],{},"isDate",[82,669,670],{},"isRegExp",[82,672,673],{},"isPlainObject",[361,675,676],{},"精确判断特定对象类型。",[361,678,679,680,682,683,686],{},"依赖 ",[82,681,617],{}," 的结果进行判断，比 ",[82,684,685],{},"typeof"," 更可靠。",[343,688,689,696,703],{},[361,690,691],{},[44,692,693],{},[82,694,695],{},"isObject",[361,697,698,699,702],{},"检查是否为非 ",[82,700,701],{},"null"," 的对象。",[361,704,705,335],{},[82,706,707],{},"val !== null && typeof val === 'object'",[343,709,710,717,720],{},[361,711,712],{},[44,713,714],{},[82,715,716],{},"isPromise",[361,718,719],{},"检查是否为 Promise。",[361,721,722,723,726,727,730],{},"检查值是否为对象或函数，并具有 ",[82,724,725],{},"then"," 和 ",[82,728,729],{},"catch"," 方法。",[343,732,733,740,743],{},[361,734,735],{},[44,736,737],{},[82,738,739],{},"isIntegerKey",[361,741,742],{},"检查字符串是否是有效的整数索引。",[361,744,745],{},"用于判断对象属性是否可能是数组的索引，例如在响应式系统中的优化。",[747,748,752],"pre",{"className":749,"code":750,"language":751,"meta":214,"style":214},"language-js shiki shiki-themes github-light github-dark","export const extend: typeof Object.assign = Object.assign\n","js",[82,753,754],{"__ignoreMap":214},[39,755,758,762,765,769,772,775,779,782],{"class":756,"line":757},"line",1,[39,759,761],{"class":760},"szBVR","export",[39,763,764],{"class":760}," const",[39,766,768],{"class":767},"sj4cs"," extend",[39,770,771],{"class":760},":",[39,773,774],{"class":760}," typeof",[39,776,778],{"class":777},"sVt8B"," Object.assign ",[39,780,781],{"class":760},"=",[39,783,784],{"class":777}," Object.assign\n",[10,786,787],{},"上面是别名与模块化封装",[14,789,790,803],{},[17,791,792,795,796,799,800,335],{},[44,793,794],{},"创建别名："," 将标准的 JavaScript 内建函数 ",[82,797,798],{},"Object.assign"," 赋值给一个新常量 ",[82,801,802],{},"extend",[17,804,805,808,809,811,812,814,815,818,819,821,822,824,825,827,828],{},[44,806,807],{},"模块化封装："," 将这个 ",[82,810,802],{}," 别名通过 ",[82,813,761],{}," 导出，使其成为 Vue ",[82,816,817],{},"shared"," 工具库的一部分。这使得 Vue 的其他模块（如编译器、运行时）可以统一地从 ",[82,820,817],{}," 模块中导入 ",[82,823,802],{}," 来执行对象合并操作，而不是直接访问全局的 ",[82,826,798],{},"。\n",[14,829,830],{},[17,831,832,835,836,839,840,335],{},[35,833,834],{},"示例："," 在其他模块中会写成 ",[82,837,838],{},"import { extend } from '@vue\u002Fshared'","，然后使用 ",[82,841,842],{},"extend(target, source)",[10,844,845],{},"这行代码包含的 TypeScript 语法确保了类型安全：",[14,847,848],{},[17,849,850,855],{},[44,851,852],{},[82,853,854],{},"export const extend: typeof Object.assign",[14,856,857,872],{},[17,858,859,862,863,865,866,381,868,871],{},[82,860,861],{},"typeof Object.assign","：这行告诉 TypeScript 编译器，",[82,864,802],{}," 这个常量必须具有与内置的 ",[82,867,798],{},[44,869,870],{},"完全相同的函数签名","（即参数类型、返回值类型）。",[17,873,874,875,877,878,881],{},"这保证了任何使用 ",[82,876,802],{}," 的地方都能",[44,879,880],{},"得到正确的类型检查和智能提示","，增强了代码的健壮性。",[10,883,884,886,887,890],{},[82,885,798],{}," 是一个标准的 JavaScript 内置函数，它的作用是",[44,888,889],{},"将一个或多个源对象的所有可枚举（Enumerable）的自有（Own）属性复制到目标对象（Target Object）上","，并返回目标对象。",[574,892,894,896],{"id":893},"objectassign-的函数签名signature",[82,895,798],{}," 的函数签名（Signature）",[10,898,899],{},"在 TypeScript 中，它的签名可以大致概括为：",[747,901,905],{"className":902,"code":903,"language":904,"meta":214,"style":214},"language-ts shiki shiki-themes github-light github-dark","Object.assign(target: object, ...sources: any[]): any\n","ts",[82,906,907],{"__ignoreMap":214},[39,908,909,912,916,919,922],{"class":756,"line":757},[39,910,911],{"class":777},"Object.",[39,913,915],{"class":914},"sScJk","assign",[39,917,918],{"class":777},"(target: object, ",[39,920,921],{"class":760},"...",[39,923,924],{"class":777},"sources: any[]): any\n",[337,926,927,940],{},[340,928,929],{},[343,930,931,934,937],{},[346,932,933],{},"参数名",[346,935,936],{},"描述",[346,938,939],{},"类型约束",[356,941,942,976],{},[343,943,944,951,961],{},[361,945,946],{},[44,947,948],{},[82,949,950],{},"target",[361,952,953,956,957,960],{},[44,954,955],{},"目标对象。"," 属性会被复制到这个对象上。这个对象会被改变（被",[44,958,959],{},"修改","）。",[361,962,963,964,967,968,971,972,975],{},"必须是一个对象 (",[82,965,966],{},"object",")。如果传入非对象值，它会被强制转换为对象（例如 ",[82,969,970],{},"Object(null)"," 或 ",[82,973,974],{},"Object(undefined)"," 会抛出错误，但基本类型会被包装）。",[343,977,978,985,995],{},[361,979,980],{},[44,981,982],{},[82,983,984],{},"...sources",[361,986,987,990,991,994],{},[44,988,989],{},"源对象。"," 属性将",[44,992,993],{},"从这些对象复制到目标对象","。可以有零个或多个源对象。",[361,996,997,998,971,1000,1003,1004,1007],{},"可以是任何类型。如果是 ",[82,999,701],{},[82,1001,1002],{},"undefined","，则跳过；如果是基本类型，会被包装成对象，但只有",[44,1005,1006],{},"可枚举","的属性会被复制（通常基本类型没有可枚举的自有属性）。",[10,1009,1010,1011,971,1014,1017,1018,1021,1022,1025,1026,1029,1030,381,1033,335],{},"运行时修改对象属性（在 JavaScript 中被称为 ",[44,1012,1013],{},"Duck Typing",[44,1015,1016],{},"动态性","）是 JavaScript 语言的内置能力。可以随时对任何对象添加、删除或修改属性，而不需要事先在类的定义中声明。而mixin也是一种实现方式。",[44,1019,1020],{},"Mixin"," 是一种设计模式，目的是为了",[44,1023,1024],{},"复用","代码或功能。它的实现方式就是将一个或多个",[44,1027,1028],{},"源对象（或函数）的属性和方法","复制到**目标对象（或类）**上，从而“混入”这些功能。",[44,1031,1032],{},"Mixin 是实现运行时属性修改的",[44,1034,1035],{},"一种结构化、有目的的方法",[574,1037,1039,1040,1042],{"id":1038},"mixin-的实现方式通常使用-objectassign","Mixin 的实现方式（通常使用 ",[82,1041,798],{},"）",[10,1044,1045,1046,1048,1049,1051],{},"​\tVue 源码中的 ",[82,1047,802],{}," (即 ",[82,1050,798],{},") 函数，就是实现 Mixin 的核心工具：",[747,1053,1055],{"className":749,"code":1054,"language":751,"meta":214,"style":214},"const LoggerMixin = {\n  log(message) {\n    console.log(`[LOG]: ${message}`);\n  }\n};\n\nconst UserMethods = {\n  \u002F\u002F 注意，这里的 extend 就是 Object.assign\n  start: function() {\n    this.status = 'running';\n  }\n};\n\nconst componentOptions = {}; \u002F\u002F 目标对象\n\n\u002F\u002F ⭐️ 使用 Object.assign \u002F extend 进行 Mixin\nObject.assign(componentOptions, LoggerMixin, UserMethods);\n\n\u002F\u002F componentOptions 现在拥有了 log 和 start 方法\ncomponentOptions.log(\"Mixin successful!\");\n",[82,1056,1057,1071,1087,1110,1116,1122,1129,1141,1148,1163,1180,1185,1190,1195,1211,1216,1222,1232,1237,1243],{"__ignoreMap":214},[39,1058,1059,1062,1065,1068],{"class":756,"line":757},[39,1060,1061],{"class":760},"const",[39,1063,1064],{"class":767}," LoggerMixin",[39,1066,1067],{"class":760}," =",[39,1069,1070],{"class":777}," {\n",[39,1072,1074,1077,1080,1084],{"class":756,"line":1073},2,[39,1075,1076],{"class":914},"  log",[39,1078,1079],{"class":777},"(",[39,1081,1083],{"class":1082},"s4XuR","message",[39,1085,1086],{"class":777},") {\n",[39,1088,1090,1093,1096,1098,1102,1104,1107],{"class":756,"line":1089},3,[39,1091,1092],{"class":777},"    console.",[39,1094,1095],{"class":914},"log",[39,1097,1079],{"class":777},[39,1099,1101],{"class":1100},"sZZnC","`[LOG]: ${",[39,1103,1083],{"class":777},[39,1105,1106],{"class":1100},"}`",[39,1108,1109],{"class":777},");\n",[39,1111,1113],{"class":756,"line":1112},4,[39,1114,1115],{"class":777},"  }\n",[39,1117,1119],{"class":756,"line":1118},5,[39,1120,1121],{"class":777},"};\n",[39,1123,1125],{"class":756,"line":1124},6,[39,1126,1128],{"emptyLinePlaceholder":1127},true,"\n",[39,1130,1132,1134,1137,1139],{"class":756,"line":1131},7,[39,1133,1061],{"class":760},[39,1135,1136],{"class":767}," UserMethods",[39,1138,1067],{"class":760},[39,1140,1070],{"class":777},[39,1142,1144],{"class":756,"line":1143},8,[39,1145,1147],{"class":1146},"sJ8bj","  \u002F\u002F 注意，这里的 extend 就是 Object.assign\n",[39,1149,1151,1154,1157,1160],{"class":756,"line":1150},9,[39,1152,1153],{"class":914},"  start",[39,1155,1156],{"class":777},": ",[39,1158,1159],{"class":760},"function",[39,1161,1162],{"class":777},"() {\n",[39,1164,1166,1169,1172,1174,1177],{"class":756,"line":1165},10,[39,1167,1168],{"class":767},"    this",[39,1170,1171],{"class":777},".status ",[39,1173,781],{"class":760},[39,1175,1176],{"class":1100}," 'running'",[39,1178,1179],{"class":777},";\n",[39,1181,1183],{"class":756,"line":1182},11,[39,1184,1115],{"class":777},[39,1186,1188],{"class":756,"line":1187},12,[39,1189,1121],{"class":777},[39,1191,1193],{"class":756,"line":1192},13,[39,1194,1128],{"emptyLinePlaceholder":1127},[39,1196,1198,1200,1203,1205,1208],{"class":756,"line":1197},14,[39,1199,1061],{"class":760},[39,1201,1202],{"class":767}," componentOptions",[39,1204,1067],{"class":760},[39,1206,1207],{"class":777}," {}; ",[39,1209,1210],{"class":1146},"\u002F\u002F 目标对象\n",[39,1212,1214],{"class":756,"line":1213},15,[39,1215,1128],{"emptyLinePlaceholder":1127},[39,1217,1219],{"class":756,"line":1218},16,[39,1220,1221],{"class":1146},"\u002F\u002F ⭐️ 使用 Object.assign \u002F extend 进行 Mixin\n",[39,1223,1225,1227,1229],{"class":756,"line":1224},17,[39,1226,911],{"class":777},[39,1228,915],{"class":914},[39,1230,1231],{"class":777},"(componentOptions, LoggerMixin, UserMethods);\n",[39,1233,1235],{"class":756,"line":1234},18,[39,1236,1128],{"emptyLinePlaceholder":1127},[39,1238,1240],{"class":756,"line":1239},19,[39,1241,1242],{"class":1146},"\u002F\u002F componentOptions 现在拥有了 log 和 start 方法\n",[39,1244,1246,1249,1251,1253,1256],{"class":756,"line":1245},20,[39,1247,1248],{"class":777},"componentOptions.",[39,1250,1095],{"class":914},[39,1252,1079],{"class":777},[39,1254,1255],{"class":1100},"\"Mixin successful!\"",[39,1257,1109],{"class":777},[325,1259,1260],{"id":1260},"安全地从一个数组中删除指定的元素",[747,1262,1264],{"className":902,"code":1263,"language":904,"meta":214,"style":214},"export const remove = \u003CT>(arr: T[], el: T): void => {\n  const i = arr.indexOf(el)\n  if (i > -1) {\n    arr.splice(i, 1)\n  }\n}\n",[82,1265,1266,1317,1336,1355,1370,1374],{"__ignoreMap":214},[39,1267,1268,1270,1272,1275,1277,1280,1283,1286,1289,1291,1294,1297,1300,1302,1304,1307,1309,1312,1315],{"class":756,"line":757},[39,1269,761],{"class":760},[39,1271,764],{"class":760},[39,1273,1274],{"class":914}," remove",[39,1276,1067],{"class":760},[39,1278,1279],{"class":777}," \u003C",[39,1281,1282],{"class":914},"T",[39,1284,1285],{"class":777},">(",[39,1287,1288],{"class":1082},"arr",[39,1290,771],{"class":760},[39,1292,1293],{"class":914}," T",[39,1295,1296],{"class":777},"[], ",[39,1298,1299],{"class":1082},"el",[39,1301,771],{"class":760},[39,1303,1293],{"class":914},[39,1305,1306],{"class":777},")",[39,1308,771],{"class":760},[39,1310,1311],{"class":767}," void",[39,1313,1314],{"class":760}," =>",[39,1316,1070],{"class":777},[39,1318,1319,1322,1325,1327,1330,1333],{"class":756,"line":1073},[39,1320,1321],{"class":760},"  const",[39,1323,1324],{"class":767}," i",[39,1326,1067],{"class":760},[39,1328,1329],{"class":777}," arr.",[39,1331,1332],{"class":914},"indexOf",[39,1334,1335],{"class":777},"(el)\n",[39,1337,1338,1341,1344,1347,1350,1353],{"class":756,"line":1089},[39,1339,1340],{"class":760},"  if",[39,1342,1343],{"class":777}," (i ",[39,1345,1346],{"class":760},">",[39,1348,1349],{"class":760}," -",[39,1351,1352],{"class":767},"1",[39,1354,1086],{"class":777},[39,1356,1357,1360,1362,1365,1367],{"class":756,"line":1112},[39,1358,1359],{"class":777},"    arr.",[39,1361,492],{"class":914},[39,1363,1364],{"class":777},"(i, ",[39,1366,1352],{"class":767},[39,1368,1369],{"class":777},")\n",[39,1371,1372],{"class":756,"line":1118},[39,1373,1115],{"class":777},[39,1375,1376],{"class":756,"line":1124},[39,1377,1378],{"class":777},"}\n",[574,1380,1382,1383,1306],{"id":1381},"步骤-a-查找元素的位置-indexof","步骤 A: 查找元素的位置 (",[82,1384,1332],{},[747,1386,1388],{"className":902,"code":1387,"language":904,"meta":214,"style":214},"const i = arr.indexOf(el)\n",[82,1389,1390],{"__ignoreMap":214},[39,1391,1392,1394,1396,1398,1400,1402],{"class":756,"line":757},[39,1393,1061],{"class":760},[39,1395,1324],{"class":767},[39,1397,1067],{"class":760},[39,1399,1329],{"class":777},[39,1401,1332],{"class":914},[39,1403,1335],{"class":777},[14,1405,1406,1423,1432],{},[17,1407,1408,1411,1412,1414,1415,381,1417,1420,1421,335],{},[82,1409,1410],{},"arr.indexOf(el)"," 遍历数组 ",[82,1413,1288],{},"，查找元素 ",[82,1416,1299],{},[44,1418,1419],{},"第一次出现","的索引位置 ",[82,1422,265],{},[17,1424,1425,1426,1428,1429,1431],{},"如果找到，",[82,1427,265],{}," 是一个大于或等于 ",[82,1430,155],{}," 的整数。",[17,1433,1434,1435,1437,1438,335],{},"如果找不到，",[82,1436,265],{}," 的值是 ",[82,1439,1440],{},"-1",[574,1442,1444,1445,1306],{"id":1443},"步骤-b-执行删除-splice","步骤 B: 执行删除 (",[82,1446,492],{},[747,1448,1450],{"className":902,"code":1449,"language":904,"meta":214,"style":214},"if (i > -1) {\n    arr.splice(i, 1)\n}\n",[82,1451,1452,1467,1479],{"__ignoreMap":214},[39,1453,1454,1457,1459,1461,1463,1465],{"class":756,"line":757},[39,1455,1456],{"class":760},"if",[39,1458,1343],{"class":777},[39,1460,1346],{"class":760},[39,1462,1349],{"class":760},[39,1464,1352],{"class":767},[39,1466,1086],{"class":777},[39,1468,1469,1471,1473,1475,1477],{"class":756,"line":1073},[39,1470,1359],{"class":777},[39,1472,492],{"class":914},[39,1474,1364],{"class":777},[39,1476,1352],{"class":767},[39,1478,1369],{"class":777},[39,1480,1481],{"class":756,"line":1089},[39,1482,1378],{"class":777},[14,1484,1485,1495,1519,1532,1546],{},[17,1486,1487,1490,1491,1494],{},[44,1488,1489],{},"条件检查："," 只有当元素被找到 (",[82,1492,1493],{},"i > -1",") 时，才执行删除操作。这确保了如果元素不存在，程序不会出错。",[17,1496,1497,1502,1503],{},[44,1498,1499,544],{},[82,1500,1501],{},"arr.splice(i, 1)"," 这是数组删除的核心。",[14,1504,1505,1511],{},[17,1506,1507,1508,1510],{},"第一个参数 ",[82,1509,265],{},"：指定开始修改数组的索引位置。",[17,1512,1513,1514,1516,1517,960],{},"第二个参数 ",[82,1515,1352],{},"：指定要移除的元素数量（只移除一个，即找到的 ",[82,1518,1299],{},[17,1520,1521,1524,1525,1527,1528,1531],{},[44,1522,1523],{},"高效性："," 尽管 ",[82,1526,1332],{}," 是 O(N)（线性时间复杂度）的操作，",[44,1529,1530],{},"但它比手动循环查找要简洁得多","，并且对于 Vue 源码中处理的通常较小的依赖数组（例如响应式系统的依赖集合），性能开销可以接受。",[17,1533,1534,1537,1538,1541,1542,1545],{},[44,1535,1536],{},"元素相等性："," 查找依赖于 JavaScript 的严格相等性比较 (",[82,1539,1540],{},"===",")，这意味着对于对象元素，只有当数组中包含",[44,1543,1544],{},"完全相同的对象引用","时，才会将其移除。",[17,1547,1548,1551,1552,1555,1556,335],{},[44,1549,1550],{},"直接修改："," 该函数是",[44,1553,1554],{},"变异 (Mutating)"," 操作，它会修改传入的原始数组 ",[82,1557,1288],{},[325,1559,1561,1564],{"id":1560},"安全且高效地检查对象自身是否包含某个属性的关键函数",[44,1562,1563],{},"安全且高效地检查对象自身是否包含某个属性","的关键函数。",[747,1566,1568],{"className":902,"code":1567,"language":904,"meta":214,"style":214},"const hasOwnProperty = Object.prototype.hasOwnProperty\nexport const hasOwn = (\n  val: object,\n  key: string | symbol,\n): key is keyof typeof val => hasOwnProperty.call(val, key)\n\n",[82,1569,1570,1591,1605,1618,1636],{"__ignoreMap":214},[39,1571,1572,1574,1577,1579,1582,1585,1588],{"class":756,"line":757},[39,1573,1061],{"class":760},[39,1575,1576],{"class":767}," hasOwnProperty",[39,1578,1067],{"class":760},[39,1580,1581],{"class":767}," Object",[39,1583,1584],{"class":777},".",[39,1586,1587],{"class":767},"prototype",[39,1589,1590],{"class":777},".hasOwnProperty\n",[39,1592,1593,1595,1597,1600,1602],{"class":756,"line":1073},[39,1594,761],{"class":760},[39,1596,764],{"class":760},[39,1598,1599],{"class":914}," hasOwn",[39,1601,1067],{"class":760},[39,1603,1604],{"class":777}," (\n",[39,1606,1607,1610,1612,1615],{"class":756,"line":1089},[39,1608,1609],{"class":1082},"  val",[39,1611,771],{"class":760},[39,1613,1614],{"class":767}," object",[39,1616,1617],{"class":777},",\n",[39,1619,1620,1623,1625,1628,1631,1634],{"class":756,"line":1112},[39,1621,1622],{"class":1082},"  key",[39,1624,771],{"class":760},[39,1626,1627],{"class":767}," string",[39,1629,1630],{"class":760}," |",[39,1632,1633],{"class":767}," symbol",[39,1635,1617],{"class":777},[39,1637,1638,1640,1642,1645,1648,1651,1653,1656,1658,1661,1664],{"class":756,"line":1118},[39,1639,1306],{"class":777},[39,1641,771],{"class":760},[39,1643,1644],{"class":1082}," key",[39,1646,1647],{"class":760}," is",[39,1649,1650],{"class":760}," keyof",[39,1652,774],{"class":760},[39,1654,1655],{"class":1082}," val",[39,1657,1314],{"class":760},[39,1659,1660],{"class":777}," hasOwnProperty.",[39,1662,1663],{"class":914},"call",[39,1665,1666],{"class":777},"(val, key)\n",[10,1668,1669,1670,1673,1674,1677,1678,1681,1682,1685],{},"在 JavaScript 中，最直接的",[44,1671,1672],{},"检查对象自身属性的方法","是 ",[82,1675,1676],{},"obj.hasOwnProperty(key)","。然而，这种方法存在一个潜在的风险，尤其是在处理来自外部或不可信来源的对象时：如果一个对象 ",[82,1679,1680],{},"val"," 自己定义了一个属性名也叫 ",[82,1683,1684],{},"hasOwnProperty","，它就会**覆盖（Shadow）**原型链上的原版方法，导致调用出错或返回错误的结果。",[747,1687,1689],{"className":902,"code":1688,"language":904,"meta":214,"style":214},"const maliciousObj = {\n  prop: 1,\n  \u002F\u002F 覆盖了原生的方法！\n  hasOwnProperty: () => true \n};\n\nmaliciousObj.hasOwnProperty('prop'); \u002F\u002F 总是返回 true，结果不准确\n",[82,1690,1691,1702,1711,1716,1733,1737,1741],{"__ignoreMap":214},[39,1692,1693,1695,1698,1700],{"class":756,"line":757},[39,1694,1061],{"class":760},[39,1696,1697],{"class":767}," maliciousObj",[39,1699,1067],{"class":760},[39,1701,1070],{"class":777},[39,1703,1704,1707,1709],{"class":756,"line":1073},[39,1705,1706],{"class":777},"  prop: ",[39,1708,1352],{"class":767},[39,1710,1617],{"class":777},[39,1712,1713],{"class":756,"line":1089},[39,1714,1715],{"class":1146},"  \u002F\u002F 覆盖了原生的方法！\n",[39,1717,1718,1721,1724,1727,1730],{"class":756,"line":1112},[39,1719,1720],{"class":914},"  hasOwnProperty",[39,1722,1723],{"class":777},": () ",[39,1725,1726],{"class":760},"=>",[39,1728,1729],{"class":767}," true",[39,1731,1732],{"class":777}," \n",[39,1734,1735],{"class":756,"line":1118},[39,1736,1121],{"class":777},[39,1738,1739],{"class":756,"line":1124},[39,1740,1128],{"emptyLinePlaceholder":1127},[39,1742,1743,1746,1748,1750,1753,1756],{"class":756,"line":1131},[39,1744,1745],{"class":777},"maliciousObj.",[39,1747,1684],{"class":914},[39,1749,1079],{"class":777},[39,1751,1752],{"class":1100},"'prop'",[39,1754,1755],{"class":777},"); ",[39,1757,1758],{"class":1146},"\u002F\u002F 总是返回 true，结果不准确\n",[10,1760,1761,1764,1765,1770,1771,1774,1775,1777],{},[82,1762,1763],{},"hasOwn"," 函数通过将 ",[44,1766,1767,1769],{},[82,1768,1684],{}," 方法“借用”","（Borrowing）或 ",[44,1772,1773],{},"“借用调用”","（Call Borrowing）到目标对象 ",[82,1776,1680],{}," 上来解决这个问题：",[747,1779,1781],{"className":902,"code":1780,"language":904,"meta":214,"style":214},"const hasOwnProperty = Object.prototype.hasOwnProperty \u002F\u002F 缓存原生方法\nexport const hasOwn = (val, key) => hasOwnProperty.call(val, key)\n",[82,1782,1783,1803],{"__ignoreMap":214},[39,1784,1785,1787,1789,1791,1793,1795,1797,1800],{"class":756,"line":757},[39,1786,1061],{"class":760},[39,1788,1576],{"class":767},[39,1790,1067],{"class":760},[39,1792,1581],{"class":767},[39,1794,1584],{"class":777},[39,1796,1587],{"class":767},[39,1798,1799],{"class":777},".hasOwnProperty ",[39,1801,1802],{"class":1146},"\u002F\u002F 缓存原生方法\n",[39,1804,1805,1807,1809,1811,1813,1816,1818,1820,1823,1826,1828,1830,1832],{"class":756,"line":1073},[39,1806,761],{"class":760},[39,1808,764],{"class":760},[39,1810,1599],{"class":914},[39,1812,1067],{"class":760},[39,1814,1815],{"class":777}," (",[39,1817,1680],{"class":1082},[39,1819,661],{"class":777},[39,1821,1822],{"class":1082},"key",[39,1824,1825],{"class":777},") ",[39,1827,1726],{"class":760},[39,1829,1660],{"class":777},[39,1831,1663],{"class":914},[39,1833,1666],{"class":777},[325,1835,1837],{"id":1836},"类型检测type-checking",[44,1838,1839],{},"类型检测（Type Checking）",[747,1841,1843],{"className":902,"code":1842,"language":904,"meta":214,"style":214},"\nexport const isArray: typeof Array.isArray = Array.isArray\nexport const isMap = (val: unknown): val is Map\u003Cany, any> =>\n  toTypeString(val) === '[object Map]'\nexport const isSet = (val: unknown): val is Set\u003Cany> =>\n  toTypeString(val) === '[object Set]'\n\nexport const isDate = (val: unknown): val is Date =>\n  toTypeString(val) === '[object Date]'\nexport const isRegExp = (val: unknown): val is RegExp =>\n  toTypeString(val) === '[object RegExp]'\nexport const isFunction = (val: unknown): val is Function =>\n  typeof val === 'function'\nexport const isString = (val: unknown): val is string => typeof val === 'string'\nexport const isSymbol = (val: unknown): val is symbol => typeof val === 'symbol'\nexport const isObject = (val: unknown): val is Record\u003Cany, any> =>\n  val !== null && typeof val === 'object'\n\n",[82,1844,1845,1849,1870,1916,1929,1967,1978,1982,2015,2026,2058,2069,2101,2114,2154,2194,2236],{"__ignoreMap":214},[39,1846,1847],{"class":756,"line":757},[39,1848,1128],{"emptyLinePlaceholder":1127},[39,1850,1851,1853,1855,1858,1860,1862,1865,1867],{"class":756,"line":1073},[39,1852,761],{"class":760},[39,1854,764],{"class":760},[39,1856,1857],{"class":767}," isArray",[39,1859,771],{"class":760},[39,1861,774],{"class":760},[39,1863,1864],{"class":777}," Array.isArray ",[39,1866,781],{"class":760},[39,1868,1869],{"class":777}," Array.isArray\n",[39,1871,1872,1874,1876,1879,1881,1883,1885,1887,1890,1892,1894,1896,1898,1901,1904,1906,1908,1910,1913],{"class":756,"line":1089},[39,1873,761],{"class":760},[39,1875,764],{"class":760},[39,1877,1878],{"class":914}," isMap",[39,1880,1067],{"class":760},[39,1882,1815],{"class":777},[39,1884,1680],{"class":1082},[39,1886,771],{"class":760},[39,1888,1889],{"class":767}," unknown",[39,1891,1306],{"class":777},[39,1893,771],{"class":760},[39,1895,1655],{"class":1082},[39,1897,1647],{"class":760},[39,1899,1900],{"class":914}," Map",[39,1902,1903],{"class":777},"\u003C",[39,1905,110],{"class":767},[39,1907,661],{"class":777},[39,1909,110],{"class":767},[39,1911,1912],{"class":777},"> ",[39,1914,1915],{"class":760},"=>\n",[39,1917,1918,1921,1924,1926],{"class":756,"line":1112},[39,1919,1920],{"class":914},"  toTypeString",[39,1922,1923],{"class":777},"(val) ",[39,1925,1540],{"class":760},[39,1927,1928],{"class":1100}," '[object Map]'\n",[39,1930,1931,1933,1935,1938,1940,1942,1944,1946,1948,1950,1952,1954,1956,1959,1961,1963,1965],{"class":756,"line":1118},[39,1932,761],{"class":760},[39,1934,764],{"class":760},[39,1936,1937],{"class":914}," isSet",[39,1939,1067],{"class":760},[39,1941,1815],{"class":777},[39,1943,1680],{"class":1082},[39,1945,771],{"class":760},[39,1947,1889],{"class":767},[39,1949,1306],{"class":777},[39,1951,771],{"class":760},[39,1953,1655],{"class":1082},[39,1955,1647],{"class":760},[39,1957,1958],{"class":914}," Set",[39,1960,1903],{"class":777},[39,1962,110],{"class":767},[39,1964,1912],{"class":777},[39,1966,1915],{"class":760},[39,1968,1969,1971,1973,1975],{"class":756,"line":1124},[39,1970,1920],{"class":914},[39,1972,1923],{"class":777},[39,1974,1540],{"class":760},[39,1976,1977],{"class":1100}," '[object Set]'\n",[39,1979,1980],{"class":756,"line":1131},[39,1981,1128],{"emptyLinePlaceholder":1127},[39,1983,1984,1986,1988,1991,1993,1995,1997,1999,2001,2003,2005,2007,2009,2012],{"class":756,"line":1143},[39,1985,761],{"class":760},[39,1987,764],{"class":760},[39,1989,1990],{"class":914}," isDate",[39,1992,1067],{"class":760},[39,1994,1815],{"class":777},[39,1996,1680],{"class":1082},[39,1998,771],{"class":760},[39,2000,1889],{"class":767},[39,2002,1306],{"class":777},[39,2004,771],{"class":760},[39,2006,1655],{"class":1082},[39,2008,1647],{"class":760},[39,2010,2011],{"class":914}," Date",[39,2013,2014],{"class":760}," =>\n",[39,2016,2017,2019,2021,2023],{"class":756,"line":1150},[39,2018,1920],{"class":914},[39,2020,1923],{"class":777},[39,2022,1540],{"class":760},[39,2024,2025],{"class":1100}," '[object Date]'\n",[39,2027,2028,2030,2032,2035,2037,2039,2041,2043,2045,2047,2049,2051,2053,2056],{"class":756,"line":1165},[39,2029,761],{"class":760},[39,2031,764],{"class":760},[39,2033,2034],{"class":914}," isRegExp",[39,2036,1067],{"class":760},[39,2038,1815],{"class":777},[39,2040,1680],{"class":1082},[39,2042,771],{"class":760},[39,2044,1889],{"class":767},[39,2046,1306],{"class":777},[39,2048,771],{"class":760},[39,2050,1655],{"class":1082},[39,2052,1647],{"class":760},[39,2054,2055],{"class":914}," RegExp",[39,2057,2014],{"class":760},[39,2059,2060,2062,2064,2066],{"class":756,"line":1182},[39,2061,1920],{"class":914},[39,2063,1923],{"class":777},[39,2065,1540],{"class":760},[39,2067,2068],{"class":1100}," '[object RegExp]'\n",[39,2070,2071,2073,2075,2078,2080,2082,2084,2086,2088,2090,2092,2094,2096,2099],{"class":756,"line":1187},[39,2072,761],{"class":760},[39,2074,764],{"class":760},[39,2076,2077],{"class":914}," isFunction",[39,2079,1067],{"class":760},[39,2081,1815],{"class":777},[39,2083,1680],{"class":1082},[39,2085,771],{"class":760},[39,2087,1889],{"class":767},[39,2089,1306],{"class":777},[39,2091,771],{"class":760},[39,2093,1655],{"class":1082},[39,2095,1647],{"class":760},[39,2097,2098],{"class":914}," Function",[39,2100,2014],{"class":760},[39,2102,2103,2106,2109,2111],{"class":756,"line":1192},[39,2104,2105],{"class":760},"  typeof",[39,2107,2108],{"class":777}," val ",[39,2110,1540],{"class":760},[39,2112,2113],{"class":1100}," 'function'\n",[39,2115,2116,2118,2120,2123,2125,2127,2129,2131,2133,2135,2137,2139,2141,2143,2145,2147,2149,2151],{"class":756,"line":1197},[39,2117,761],{"class":760},[39,2119,764],{"class":760},[39,2121,2122],{"class":914}," isString",[39,2124,1067],{"class":760},[39,2126,1815],{"class":777},[39,2128,1680],{"class":1082},[39,2130,771],{"class":760},[39,2132,1889],{"class":767},[39,2134,1306],{"class":777},[39,2136,771],{"class":760},[39,2138,1655],{"class":1082},[39,2140,1647],{"class":760},[39,2142,1627],{"class":767},[39,2144,1314],{"class":760},[39,2146,774],{"class":760},[39,2148,2108],{"class":777},[39,2150,1540],{"class":760},[39,2152,2153],{"class":1100}," 'string'\n",[39,2155,2156,2158,2160,2163,2165,2167,2169,2171,2173,2175,2177,2179,2181,2183,2185,2187,2189,2191],{"class":756,"line":1213},[39,2157,761],{"class":760},[39,2159,764],{"class":760},[39,2161,2162],{"class":914}," isSymbol",[39,2164,1067],{"class":760},[39,2166,1815],{"class":777},[39,2168,1680],{"class":1082},[39,2170,771],{"class":760},[39,2172,1889],{"class":767},[39,2174,1306],{"class":777},[39,2176,771],{"class":760},[39,2178,1655],{"class":1082},[39,2180,1647],{"class":760},[39,2182,1633],{"class":767},[39,2184,1314],{"class":760},[39,2186,774],{"class":760},[39,2188,2108],{"class":777},[39,2190,1540],{"class":760},[39,2192,2193],{"class":1100}," 'symbol'\n",[39,2195,2196,2198,2200,2203,2205,2207,2209,2211,2213,2215,2217,2219,2221,2224,2226,2228,2230,2232,2234],{"class":756,"line":1218},[39,2197,761],{"class":760},[39,2199,764],{"class":760},[39,2201,2202],{"class":914}," isObject",[39,2204,1067],{"class":760},[39,2206,1815],{"class":777},[39,2208,1680],{"class":1082},[39,2210,771],{"class":760},[39,2212,1889],{"class":767},[39,2214,1306],{"class":777},[39,2216,771],{"class":760},[39,2218,1655],{"class":1082},[39,2220,1647],{"class":760},[39,2222,2223],{"class":914}," Record",[39,2225,1903],{"class":777},[39,2227,110],{"class":767},[39,2229,661],{"class":777},[39,2231,110],{"class":767},[39,2233,1912],{"class":777},[39,2235,1915],{"class":760},[39,2237,2238,2241,2244,2247,2250,2252,2254,2256],{"class":756,"line":1224},[39,2239,2240],{"class":777},"  val ",[39,2242,2243],{"class":760},"!==",[39,2245,2246],{"class":767}," null",[39,2248,2249],{"class":760}," &&",[39,2251,774],{"class":760},[39,2253,2108],{"class":777},[39,2255,1540],{"class":760},[39,2257,2258],{"class":1100}," 'object'\n",[10,2260,2261,2263,2264,335],{},[82,2262,617],{}," 依赖于 ",[82,2265,2266],{},"Object.prototype.toString.call(val)",[14,2268,2269,2283],{},[17,2270,2271,2274,2275,2278,2279,2282],{},[44,2272,2273],{},"核心优势："," 这是 JavaScript 规范中",[44,2276,2277],{},"最可靠、最稳定的","获取对象内部 ",[82,2280,2281],{},"[[Class]]"," 属性（或称内部标签）的方法。",[17,2284,2285,2288,2289,2292,2293,2296,2297,827,2300],{},[44,2286,2287],{},"返回值："," 对于",[44,2290,2291],{},"几乎所有内置类型","，它都会返回一个形如 ",[82,2294,2295],{},"[object TypeName]"," 的",[44,2298,2299],{},"字符串",[14,2301,2302,2308,2314,2320],{},[17,2303,2304,2305],{},"Map 实例 → ",[82,2306,2307],{},"[object Map]",[17,2309,2310,2311],{},"Date 实例 → ",[82,2312,2313],{},"[object Date]",[17,2315,2316,2317],{},"数组 → ",[82,2318,2319],{},"[object Array]",[17,2321,2322,2323],{},"普通对象 → ",[82,2324,2325],{},"[object Object]",[10,2327,2328,2329,2332,2333,2335,2336,2339,2340,2343,2344,2347,2348,2351,2352,335],{},"​\t因此，",[82,2330,2331],{},"toTypeString(val) === '[object Map]'"," 是确保 ",[82,2334,1680],{}," 是一个真正的 ",[82,2337,2338],{},"Map"," 实例的",[44,2341,2342],{},"最可靠、最跨环境","的方式。",[82,2345,2346],{},"val is Map\u003Cany, any>"," 的作用（类型安全）这部分是纯粹的 ",[44,2349,2350],{},"TypeScript 语法","，被称为 ",[44,2353,2354],{},"类型谓词（Type Predicate）",[10,2356,2357,2358,2360,2392,2393,335],{},"**",[82,2359,2346],{},[44,2361,2362,2363,2366,2367,381,2369,2372,2373,2376,2377,2380,2381,2384,2385,2387,2388,2391],{},"这是一个特殊的返回类型。它告诉 TypeScript 编译器：“如果这个函数返回 ",[82,2364,2365],{},"true","，那么你可以保证传入的参数 ",[82,2368,1680],{},[44,2370,2371],{},"就是","一个 ",[82,2374,2375],{},"Map\u003Cany, any>"," 类型的值。”",[44,2378,2379],{},"使用场景","当我们在代码中调用 ",[82,2382,2383],{},"if (isMap(someValue))"," 时，在 ",[82,2386,1456],{}," 块内部，",[82,2389,2390],{},"someValue"," 的类型将","自动被收窄（Narrowing）**为 ",[82,2394,2375],{},[10,2396,2397,2398,2400,2401,2404,2405,2407,2408,2411,2412,335],{},"​\t你觉得 ",[82,2399,1680],{}," 设置为 ",[82,2402,2403],{},"unknown"," 并且使用 ",[82,2406,617],{}," 是多此一举，是因为你可能主要从运行时 JavaScript 的角度来看。但是，在 TypeScript 层面，这种写法是",[44,2409,2410],{},"必须的","，也是",[44,2413,2414],{},"最有意义的",[2416,2417],"hr",{},[325,2419,2421,2422,2425],{"id":2420},"为什么-val-unknown-并非多余","为什么 ",[82,2423,2424],{},"val: unknown"," 并非多余？",[574,2427,2429,2430,2432],{"id":2428},"_1-unknown-是最安全的类型","1. ",[82,2431,2403],{}," 是最安全的类型",[10,2434,2435],{},"在 TypeScript 中：",[14,2437,2438,2448,2455],{},[17,2439,2440,2444,2445,335],{},[44,2441,2442],{},[82,2443,2403],{}," 类型代表",[44,2446,2447],{},"任何值",[17,2449,2450,2451,2454],{},"它是",[44,2452,2453],{},"顶级类型","，意味着你可以将任何值赋给它。",[17,2456,2457,2458,2464],{},"它的安全性在于：",[44,2459,2460,2461,2463],{},"如果你不先进行类型检查（即类型收窄），你就不能对 ",[82,2462,2403],{}," 类型的值执行任何操作","（除了相等性检查）。",[10,2466,2467,2468,2472],{},"当我们在 Vue 源码中定义一个通用工具函数时，我们不知道用户会传入什么类型的值，所以使用 ",[44,2469,2470],{},[82,2471,2424],{}," 是最正确的选择，因为它：",[2474,2475,2476],"blockquote",{},[10,2477,2478],{},[44,2479,2480],{},"“我不知道你传的是什么，但我要对你进行检查。”",[574,2482,2484,2485,2487],{"id":2483},"_2-运行时-javascript-代码totypestring的必要性","2. 运行时 JavaScript 代码（",[82,2486,617],{},"）的必要性",[10,2489,2490,2491,2493,2494,2496,2497,2500],{},"因为 ",[82,2492,1680],{}," 是 ",[82,2495,2403],{},"，我们必须使用 ",[44,2498,2499],{},"运行时"," 的 JavaScript 代码来判断它的实际类型。",[10,2502,2503,2504,2506],{},"toTypeString(val)===′",[39,2505,107],{},"′",[14,2508,2509,2519],{},[17,2510,2511,2512,2515,2516,2518],{},"这行代码是 ",[44,2513,2514],{},"JavaScript 运行时"," 的逻辑，它判断 ",[82,2517,1680],{}," 是否真的是一个 Map 实例。",[17,2520,2521,2522,971,2524,2526,2527,2530],{},"这个判断的结果（",[82,2523,2365],{},[82,2525,436],{},"）决定了 ",[44,2528,2529],{},"TypeScript 编译器"," 如何处理后续的代码。",[2416,2532],{},[574,2534,2536,2537,2539],{"id":2535},"_3-为什么-val-is-mapany-any-才是核心价值","3. 为什么 ",[82,2538,2346],{}," 才是核心价值？",[10,2541,2542,2543,381,2546,2548],{},"这里的核心价值在于 ",[44,2544,2545],{},"类型谓词",[82,2547,2346],{},"。它负责将运行时的检查结果反馈给编译时的 TypeScript 系统。",[337,2550,2551,2564],{},[340,2552,2553],{},[343,2554,2555,2558,2561],{},[346,2556,2557],{},"步骤",[346,2559,2560],{},"环境",[346,2562,2563],{},"解释",[356,2565,2566,2587,2604],{},[343,2567,2568,2573,2576],{},[361,2569,2570],{},[44,2571,2572],{},"输入",[361,2574,2575],{},"TypeScript 编译时",[361,2577,2578,2580,2581,2583,2584,335],{},[82,2579,1680],{}," 的类型是 ",[82,2582,2403],{},"。编译器不允许你访问 ",[82,2585,2586],{},"val.size",[343,2588,2589,2594,2596],{},[361,2590,2591],{},[44,2592,2593],{},"执行",[361,2595,2514],{},[361,2597,2598,2600,2601,2603],{},[82,2599,617],{}," 检查 ",[82,2602,1680],{}," 的实际值。",[343,2605,2606,2611,2613],{},[361,2607,2608],{},[44,2609,2610],{},"返回",[361,2612,2575],{},[361,2614,2615,2616,2618,2619,381,2622,2624,2625,335],{},"如果函数返回 ",[82,2617,2365],{},"，编译器相信了类型谓词，并",[44,2620,2621],{},"收窄",[82,2623,1680],{}," 的类型到 ",[82,2626,2338],{},[325,2628,2630],{"id":2629},"鸭子类型duck-typing检查","**鸭子类型（Duck Typing）**检查",[10,2632,2633],{},"它的实现策略是进行**鸭子类型（Duck Typing）**检查，这在 JavaScript 库中是一种常见且灵活的做法。",[10,2635,2636,2637,2639,2640,2643,2644,2647,2648,2650,2651,335],{},"​\t",[82,2638,716],{}," 函数详解:  该函数没有使用 ",[82,2641,2642],{},"val instanceof Promise","，而是执行了一系列",[44,2645,2646],{},"运行时检查","，以确定 ",[82,2649,1680],{}," 是否具备 ",[44,2652,2653],{},"Promise 的行为特征",[337,2655,2656,2665],{},[340,2657,2658],{},[343,2659,2660,2663],{},[346,2661,2662],{},"部分",[346,2664,936],{},[356,2666,2667,2679,2700],{},[343,2668,2669,2674],{},[361,2670,2671],{},[44,2672,2673],{},"签名",[361,2675,2676],{},[82,2677,2678],{},"\u003CT = any>(val: unknown): val is Promise\u003CT>",[343,2680,2681,2685],{},[361,2682,2683],{},[44,2684,2545],{},[361,2686,2687,2690,2691,2693,2694,2696,2697,335],{},[82,2688,2689],{},"val is Promise\u003CT>"," 告诉 TypeScript 编译器，如果此函数返回 ",[82,2692,2365],{},"，则 ",[82,2695,1680],{}," 的类型被收窄为 ",[82,2698,2699],{},"Promise\u003CT>",[343,2701,2702,2707],{},[361,2703,2704],{},[44,2705,2706],{},"输入类型",[361,2708,2709,2711],{},[82,2710,2424],{}," 表明它接受任何类型的值，并对其进行动态检查。",[10,2713,2714,2715,2717,2718,2721],{},"鸭子类型（Duck Typing）检查逻辑，该函数返回 ",[82,2716,2365],{}," 的条件是所有子条件都成立（使用 ",[82,2719,2720],{},"&&"," 连接）：",[2723,2724,2726],"h4",{"id":2725},"a-检查基本类型","A. 检查基本类型",[10,2728,2729],{},"​\t\t\t(isObject(val) || isFunction(val))",[14,2731,2732,2741],{},[17,2733,2734,2737,2738,2740],{},[44,2735,2736],{},"目的："," 确保 ",[82,2739,1680],{}," 是一个复合类型，因为 Promise（或 Thenable）必须是一个对象或函数。",[17,2742,2743,2746,2747,661,2750,661,2753,661,2756,661,2758,661,2760,2763],{},[44,2744,2745],{},"排除项："," 排除原始类型（如 ",[82,2748,2749],{},"string",[82,2751,2752],{},"number",[82,2754,2755],{},"boolean",[82,2757,701],{},[82,2759,1002],{},[82,2761,2762],{},"symbol","），这些类型不可能是 Promise。",[2723,2765,2767,2768,2770],{"id":2766},"b-检查-then-方法","B. 检查 ",[82,2769,725],{}," 方法",[10,2772,2773],{},"​\t\t\tisFuction((val as any).then)",[14,2775,2776,2790],{},[17,2777,2778,2600,2780,2782,2783,2787,2788,335],{},[44,2779,2736],{},[82,2781,1680],{}," 是否具有一个名为 ",[44,2784,2785],{},[82,2786,725],{}," 的属性，并且该属性是一个",[44,2789,601],{},[17,2791,2792,2793,2796,2797,2800,2801,2803,2804,335],{},"这是识别 Thenable 对象的",[44,2794,2795],{},"关键","。根据 ",[44,2798,2799],{},"Promise\u002FA+ 规范","，任何具有 ",[82,2802,725],{}," 方法的对象都被视为 ",[44,2805,2806],{},"Promise-like 对象",[2723,2808,2810,2811,2813],{"id":2809},"c-检查-catch-方法-辅助性检查","C. 检查 ",[82,2812,729],{}," 方法 (辅助性检查)",[10,2815,2816],{},"​\t\t\tisFunction((val as any).catch)",[14,2818,2819,2831],{},[17,2820,2821,2600,2823,2782,2825,2787,2829,335],{},[44,2822,2736],{},[82,2824,1680],{},[44,2826,2827],{},[82,2828,729],{},[44,2830,601],{},[17,2832,2833,2834,2836,2837,2839,2840,2842],{},"虽然理论上 Thenable 只需要 ",[82,2835,725],{}," 方法，但实际应用中的 Promise 几乎总是具有 ",[82,2838,729],{}," 方法。 Vue 在此加入 ",[82,2841,729],{}," 检查，是为了提高判断的准确性，确保它能被当作一个完整的 Promise 实例来处理。",[10,2844,2845,2848],{},[44,2846,2847],{},"鸭子类型 (Duck Typing)"," 的哲学是：“如果它走起来像鸭子，叫起来像鸭子，那么它就是一只鸭子。”",[10,2850,2851],{},"在这种情况下：",[14,2853,2854,2875],{},[17,2855,2856,2859,2860,482,2867,2870,2871,2874],{},[44,2857,2858],{},"优点："," 这种方法",[44,2861,2862,2863,2866],{},"不依赖于全局的 ",[82,2864,2865],{},"Promise"," 构造函数",[82,2868,2869],{},"instanceof Promise","）。它能识别出",[44,2872,2873],{},"所有","遵循 Promise 约定的对象，包括自定义的 Promise 实现（如一些库中的 Thenable 对象），从而提高了框架的兼容性和灵活性。",[17,2876,2877,2883,2884,2493,2886,2888,2889,2892,2893,726,2896,2899],{},[44,2878,2879,2882],{},[82,2880,2881],{},"as any"," 的使用："," 由于 ",[82,2885,1680],{},[82,2887,2403],{},"，TypeScript 不允许直接访问其属性。",[82,2890,2891],{},"val as any"," 暂时绕过了 TypeScript 的静态检查，以允许在运行时执行属性检查 (",[82,2894,2895],{},".then",[82,2897,2898],{},".catch",")。因为这是在类型检查工具函数内部，这种逃逸是合理的。",[325,2901,2903,2906],{"id":2902},"最精确最可靠的运行时类型检测的基础工具函数",[44,2904,2905],{},"最精确、最可靠的运行时类型检测","的基础工具函数",[747,2908,2910],{"className":902,"code":2909,"language":904,"meta":214,"style":214},"export const objectToString: typeof Object.prototype.toString =\n  Object.prototype.toString\nexport const toTypeString = (value: unknown): string =>\n  objectToString.call(value)\n\n",[82,2911,2912,2937,2949,2977],{"__ignoreMap":214},[39,2913,2914,2916,2918,2921,2923,2925,2927,2929,2931,2934],{"class":756,"line":757},[39,2915,761],{"class":760},[39,2917,764],{"class":760},[39,2919,2920],{"class":767}," objectToString",[39,2922,771],{"class":760},[39,2924,774],{"class":760},[39,2926,1581],{"class":767},[39,2928,1584],{"class":777},[39,2930,1587],{"class":767},[39,2932,2933],{"class":777},".toString ",[39,2935,2936],{"class":760},"=\n",[39,2938,2939,2942,2944,2946],{"class":756,"line":1073},[39,2940,2941],{"class":767},"  Object",[39,2943,1584],{"class":777},[39,2945,1587],{"class":767},[39,2947,2948],{"class":777},".toString\n",[39,2950,2951,2953,2955,2958,2960,2962,2965,2967,2969,2971,2973,2975],{"class":756,"line":1089},[39,2952,761],{"class":760},[39,2954,764],{"class":760},[39,2956,2957],{"class":914}," toTypeString",[39,2959,1067],{"class":760},[39,2961,1815],{"class":777},[39,2963,2964],{"class":1082},"value",[39,2966,771],{"class":760},[39,2968,1889],{"class":767},[39,2970,1306],{"class":777},[39,2972,771],{"class":760},[39,2974,1627],{"class":767},[39,2976,2014],{"class":760},[39,2978,2979,2982,2984],{"class":756,"line":1112},[39,2980,2981],{"class":777},"  objectToString.",[39,2983,1663],{"class":914},[39,2985,2986],{"class":777},"(value)\n",[10,2988,2989,2992],{},[82,2990,2991],{},"objectToString","：缓存原生方法",[747,2994,2996],{"className":902,"code":2995,"language":904,"meta":214,"style":214},"export const objectToString: typeof Object.prototype.toString =\n  Object.prototype.toString\n",[82,2997,2998,3020],{"__ignoreMap":214},[39,2999,3000,3002,3004,3006,3008,3010,3012,3014,3016,3018],{"class":756,"line":757},[39,3001,761],{"class":760},[39,3003,764],{"class":760},[39,3005,2920],{"class":767},[39,3007,771],{"class":760},[39,3009,774],{"class":760},[39,3011,1581],{"class":767},[39,3013,1584],{"class":777},[39,3015,1587],{"class":767},[39,3017,2933],{"class":777},[39,3019,2936],{"class":760},[39,3021,3022,3024,3026,3028],{"class":756,"line":1073},[39,3023,2941],{"class":767},[39,3025,1584],{"class":777},[39,3027,1587],{"class":767},[39,3029,2948],{"class":777},[10,3031,3032,3034,3035,3038,3039,730],{},[44,3033,2736],{}," 这行代码是为了",[44,3036,3037],{},"缓存（Caching）和安全","地获取原生的 ",[82,3040,3041],{},"toString",[14,3043,3044,3059],{},[17,3045,3046,3049,3050,3052,3053,3055,3056,335],{},[44,3047,3048],{},"缓存："," 将 ",[82,3051,591],{}," 赋值给一个常量 ",[82,3054,2991],{}," 并导出。在后续代码中，可以直接使用这个常量，而不是每次都访问 ",[82,3057,3058],{},"Object.prototype",[17,3060,3061,3064,3065,3068,3069,3071,3072,3074,3075,381,3078,3080,3081,335],{},[44,3062,3063],{},"安全："," 它避免了直接在目标对象上调用 ",[82,3066,3067],{},"value.toString()","。如果 ",[82,3070,2964],{}," 上有自定义的 ",[82,3073,3041],{}," 方法，直接调用会执行自定义方法，导致类型检测失败。通过",[44,3076,3077],{},"借用",[82,3079,591],{},"，我们可以",[44,3082,3083],{},"保证执行的是原生方法",[10,3085,3086,3088],{},[82,3087,617],{},"：实现精确类型检查",[747,3090,3092],{"className":902,"code":3091,"language":904,"meta":214,"style":214},"export const toTypeString = (value: unknown): string =>\n  objectToString.call(value)\n",[82,3093,3094,3120],{"__ignoreMap":214},[39,3095,3096,3098,3100,3102,3104,3106,3108,3110,3112,3114,3116,3118],{"class":756,"line":757},[39,3097,761],{"class":760},[39,3099,764],{"class":760},[39,3101,2957],{"class":914},[39,3103,1067],{"class":760},[39,3105,1815],{"class":777},[39,3107,2964],{"class":1082},[39,3109,771],{"class":760},[39,3111,1889],{"class":767},[39,3113,1306],{"class":777},[39,3115,771],{"class":760},[39,3117,1627],{"class":767},[39,3119,2014],{"class":760},[39,3121,3122,3124,3126],{"class":756,"line":1073},[39,3123,2981],{"class":777},[39,3125,1663],{"class":914},[39,3127,2986],{"class":777},[10,3129,3130,3132,3133,3139,3140,3143],{},[44,3131,2736],{}," 获取值的 ",[44,3134,3135,3136,3138],{},"内部 ",[82,3137,2281],{}," 标签","（Internal Tag），返回一个形如 ",[82,3141,3142],{},"\"[object TypeName]\""," 的字符串。",[10,3145,3146],{},[44,3147,3148],{},"原理（借用调用）：",[14,3150,3151,3156,3174],{},[17,3152,3153,3154,335],{},"使用缓存的 ",[82,3155,2991],{},[17,3157,541,3158,381,3161,3164,3165,3167,3168,3171,3172,335],{},[82,3159,3160],{},".call(value)",[44,3162,3163],{},"强制","将 ",[82,3166,3041],{}," 方法的 ",[82,3169,3170],{},"this"," 上下文设置为要检查的值 ",[82,3173,2964],{},[17,3175,3176,3177,3179,3180],{},"当 ",[82,3178,591],{}," 在任何对象上被调用时，",[44,3181,3182],{},"它会读取该对象的内部属性，并返回一个特定格式的字符串。",[10,3184,3185,3186,3189],{},"这是 JavaScript 规范中",[44,3187,3188],{},"最可靠","的类型检测机制。例如：",[337,3191,3192,3210],{},[340,3193,3194],{},[343,3195,3196,3201,3207],{},[346,3197,3198,3199,1306],{},"值 (",[82,3200,2964],{},[346,3202,3203,3206],{},[82,3204,3205],{},"objectToString.call(value)"," 的返回值",[346,3208,3209],{},"实际类型",[356,3211,3212,3227,3241,3256,3272,3286],{},[343,3213,3214,3220,3224],{},[361,3215,3216,3219],{},[82,3217,3218],{},"[1, 2]"," (数组)",[361,3221,3222],{},[82,3223,629],{},[361,3225,3226],{},"Array",[343,3228,3229,3234,3239],{},[361,3230,3231],{},[82,3232,3233],{},"new Map()",[361,3235,3236],{},[82,3237,3238],{},"\"[object Map]\"",[361,3240,2338],{},[343,3242,3243,3248,3253],{},[361,3244,3245],{},[82,3246,3247],{},"new Date()",[361,3249,3250],{},[82,3251,3252],{},"\"[object Date]\"",[361,3254,3255],{},"Date",[343,3257,3258,3264,3269],{},[361,3259,3260,3263],{},[82,3261,3262],{},"{ a: 1 }"," (纯对象)",[361,3265,3266],{},[82,3267,3268],{},"\"[object Object]\"",[361,3270,3271],{},"Object",[343,3273,3274,3278,3283],{},[361,3275,3276],{},[82,3277,701],{},[361,3279,3280],{},[82,3281,3282],{},"\"[object Null]\"",[361,3284,3285],{},"Null",[343,3287,3288,3292,3297],{},[361,3289,3290],{},[82,3291,1002],{},[361,3293,3294],{},[82,3295,3296],{},"\"[object Undefined]\"",[361,3298,3299],{},"Undefined",[325,3301,3303,3304,3307],{"id":3302},"获取值-原始类型名称raw-type-name-的工具函数","获取值 ",[44,3305,3306],{},"原始类型名称（Raw Type Name）"," 的工具函数",[747,3309,3311],{"className":902,"code":3310,"language":904,"meta":214,"style":214},"export const toRawType = (value: unknown): string => {\n  \u002F\u002F extract \"RawType\" from strings like \"[object RawType]\"\n  return toTypeString(value).slice(8, -1)\n}\n\n",[82,3312,3313,3342,3347,3374],{"__ignoreMap":214},[39,3314,3315,3317,3319,3322,3324,3326,3328,3330,3332,3334,3336,3338,3340],{"class":756,"line":757},[39,3316,761],{"class":760},[39,3318,764],{"class":760},[39,3320,3321],{"class":914}," toRawType",[39,3323,1067],{"class":760},[39,3325,1815],{"class":777},[39,3327,2964],{"class":1082},[39,3329,771],{"class":760},[39,3331,1889],{"class":767},[39,3333,1306],{"class":777},[39,3335,771],{"class":760},[39,3337,1627],{"class":767},[39,3339,1314],{"class":760},[39,3341,1070],{"class":777},[39,3343,3344],{"class":756,"line":1073},[39,3345,3346],{"class":1146},"  \u002F\u002F extract \"RawType\" from strings like \"[object RawType]\"\n",[39,3348,3349,3352,3354,3357,3360,3362,3365,3367,3370,3372],{"class":756,"line":1089},[39,3350,3351],{"class":760},"  return",[39,3353,2957],{"class":914},[39,3355,3356],{"class":777},"(value).",[39,3358,3359],{"class":914},"slice",[39,3361,1079],{"class":777},[39,3363,3364],{"class":767},"8",[39,3366,661],{"class":777},[39,3368,3369],{"class":760},"-",[39,3371,1352],{"class":767},[39,3373,1369],{"class":777},[39,3375,3376],{"class":756,"line":1112},[39,3377,1378],{"class":777},[10,3379,3380,3382,3383,3385],{},[82,3381,638],{}," 的目的就是从 ",[82,3384,617],{}," 返回的格式化字符串中，提取出纯粹的类型名称。",[574,3387,3388],{"id":3388},"工作原理",[337,3390,3391,3402],{},[340,3392,3393],{},[343,3394,3395,3397,3400],{},[346,3396,2557],{},[346,3398,3399],{},"代码",[346,3401,2563],{},[356,3403,3404,3426],{},[343,3405,3406,3411,3417],{},[361,3407,3408],{},[44,3409,3410],{},"A. 获取格式化字符串",[361,3412,3413,3414],{},"隐式调用 ",[82,3415,3416],{},"toTypeString(value)",[361,3418,3419,3420,3422,3423,335],{},"获取 ",[82,3421,625],{}," 的结果，格式为 ",[82,3424,3425],{},"\"[object RawType]\"",[343,3427,3428,3433,3438],{},[361,3429,3430],{},[44,3431,3432],{},"B. 截取字符串",[361,3434,3435],{},[82,3436,3437],{},".slice(8, -1)",[361,3439,3440,3441,3443],{},"使用 JavaScript 的 ",[82,3442,3359],{}," 方法进行高效截取。",[574,3445,3447,3448,1306],{"id":3446},"截取的位置-slice8-1","截取的位置 (",[82,3449,3437],{},[10,3451,3452,3453,3455],{},"这个数字不是随意取的，它基于 ",[82,3454,3425],{}," 这个固定格式的字符串：",[14,3457,3458,3515,3530],{},[17,3459,3460,3465,3466,827,3469],{},[44,3461,3462],{},[82,3463,3464],{},"[object ","：这部分字符串固定占用 ",[44,3467,3468],{},"8 个字符",[14,3470,3471,3477,3483,3489,3495,3501,3507,3512],{},[17,3472,3473,3476],{},[82,3474,3475],{},"["," 占 1 位 (索引 0)",[17,3478,3479,3482],{},[82,3480,3481],{},"o"," 占 1 位 (索引 1)",[17,3484,3485,3488],{},[82,3486,3487],{},"b"," 占 1 位 (索引 2)",[17,3490,3491,3494],{},[82,3492,3493],{},"j"," 占 1 位 (索引 3)",[17,3496,3497,3500],{},[82,3498,3499],{},"e"," 占 1 位 (索引 4)",[17,3502,3503,3506],{},[82,3504,3505],{},"c"," 占 1 位 (索引 5)",[17,3508,3509,3511],{},[82,3510,93],{}," 占 1 位 (索引 6)",[17,3513,3514],{},"空格 占 1 位 (索引 7)",[17,3516,3517,3522,3523,3525,3526,3529],{},[44,3518,3519,3521],{},[82,3520,3364],{}," (开始索引)："," 从索引 8 开始截取，正好跳过 ",[82,3524,3464],{},"，开始于 **",[82,3527,3528],{},"R","**awType。",[17,3531,3532,3537,3538,335],{},[44,3533,3534,3536],{},[82,3535,1440],{}," (结束索引)："," 截取到倒数第一个字符之前，正好跳过末尾的 ",[44,3539,3540],{},[82,3541,3542],{},"]",[325,3544,3546],{"id":3545},"准确检查一个值是否为普通的-javascript-对象","准确检查一个值是否为普通的 JavaScript 对象",[10,3548,3549,3550,3552,3553,702],{},"​\t它排除了像数组、Date、Map 等所有其他内置对象类型，只接受那些直接或间接继承自 ",[82,3551,3058],{}," 且内部标签为 ",[82,3554,2325],{},[747,3556,3558],{"className":902,"code":3557,"language":904,"meta":214,"style":214},"export const isPlainObject = (val: unknown): val is object =>\n  toTypeString(val) === '[object Object]'\n",[82,3559,3560,3591],{"__ignoreMap":214},[39,3561,3562,3564,3566,3569,3571,3573,3575,3577,3579,3581,3583,3585,3587,3589],{"class":756,"line":757},[39,3563,761],{"class":760},[39,3565,764],{"class":760},[39,3567,3568],{"class":914}," isPlainObject",[39,3570,1067],{"class":760},[39,3572,1815],{"class":777},[39,3574,1680],{"class":1082},[39,3576,771],{"class":760},[39,3578,1889],{"class":767},[39,3580,1306],{"class":777},[39,3582,771],{"class":760},[39,3584,1655],{"class":1082},[39,3586,1647],{"class":760},[39,3588,1614],{"class":767},[39,3590,2014],{"class":760},[39,3592,3593,3595,3597,3599],{"class":756,"line":1073},[39,3594,1920],{"class":914},[39,3596,1923],{"class":777},[39,3598,1540],{"class":760},[39,3600,3601],{"class":1100}," '[object Object]'\n",[10,3603,3604,3605,335],{},"这段代码是确保一个对象是“普通对象”的最可靠方式，因为 ",[44,3606,3607,3609],{},[82,3608,685],{}," 运算符在这个场景中是不可靠的",[337,3611,3612,3625],{},[340,3613,3614],{},[343,3615,3616,3619,3622],{},[346,3617,3618],{},"检查方式",[346,3620,3621],{},"结果",[346,3623,3624],{},"问题",[356,3626,3627,3659],{},[343,3628,3629,3634,3638],{},[361,3630,3631],{},[82,3632,3633],{},"typeof val === 'object'",[361,3635,3636],{},[82,3637,2365],{},[361,3639,3640,3641,486,3645,486,3648,486,3650,486,3653,3655,3656,3658],{},"对于 ",[44,3642,3643],{},[82,3644,701],{},[44,3646,3647],{},"数组",[44,3649,3255],{},[44,3651,3652],{},"RegExp",[44,3654,2338],{}," 等都会返回 ",[82,3657,2365],{},"，太宽泛。",[343,3660,3661,3666,3670],{},[361,3662,3663],{},[82,3664,3665],{},"val instanceof Object",[361,3667,3668],{},[82,3669,2365],{},[361,3671,3672,3673,3675,3676,335],{},"对于数组、Date 等所有继承自 ",[82,3674,3271],{}," 的对象都会返回 ",[82,3677,2365],{},[574,3679,3681,3682],{"id":3680},"运行时可靠性totypestring","运行时可靠性：",[82,3683,617],{},[10,3685,2503,3686,2506],{},[39,3687,149],{},[14,3689,3690,3701],{},[17,3691,3692,3695,3696,3698,3699,960],{},[44,3693,3694],{},"依赖："," 它依赖于 ",[82,3697,617],{},"（即借用 ",[82,3700,2266],{},[17,3702,3703,3706,3707,3710,3711,3714,3715,3717,3718,827,3720],{},[44,3704,3705],{},"排除所有内置类型："," 只有通过 ",[82,3708,3709],{},"{}"," 字面量创建的，或通过 ",[82,3712,3713],{},"new Object()"," 创建的对象，以及那些没有被指定特定 ",[82,3716,2281],{}," 内部标签的对象，才会返回 ",[82,3719,2325],{},[14,3721,3722],{},[17,3723,3724,381,3727,3729,3730,3732,3733,3729,3735,3737],{},[44,3725,3726],{},"例：",[82,3728,3247],{}," 返回 ",[82,3731,2313],{},"，",[82,3734,527],{},[82,3736,2319],{},"。因此，这种方法可以准确地将普通对象与其他内置类型区分开。",[325,3739,3740],{"id":3740},"判断一个值是否可以作为有效的非负整数键",[747,3742,3744],{"className":902,"code":3743,"language":904,"meta":214,"style":214},"export const isIntegerKey = (key: unknown): boolean =>\n  isString(key) &&\n  key !== 'NaN' &&\n  key[0] !== '-' &&\n  '' + parseInt(key, 10) === key\n\n",[82,3745,3746,3774,3785,3798,3815],{"__ignoreMap":214},[39,3747,3748,3750,3752,3755,3757,3759,3761,3763,3765,3767,3769,3772],{"class":756,"line":757},[39,3749,761],{"class":760},[39,3751,764],{"class":760},[39,3753,3754],{"class":914}," isIntegerKey",[39,3756,1067],{"class":760},[39,3758,1815],{"class":777},[39,3760,1822],{"class":1082},[39,3762,771],{"class":760},[39,3764,1889],{"class":767},[39,3766,1306],{"class":777},[39,3768,771],{"class":760},[39,3770,3771],{"class":767}," boolean",[39,3773,2014],{"class":760},[39,3775,3776,3779,3782],{"class":756,"line":1073},[39,3777,3778],{"class":914},"  isString",[39,3780,3781],{"class":777},"(key) ",[39,3783,3784],{"class":760},"&&\n",[39,3786,3787,3790,3792,3795],{"class":756,"line":1089},[39,3788,3789],{"class":777},"  key ",[39,3791,2243],{"class":760},[39,3793,3794],{"class":1100}," 'NaN'",[39,3796,3797],{"class":760}," &&\n",[39,3799,3800,3803,3805,3808,3810,3813],{"class":756,"line":1112},[39,3801,3802],{"class":777},"  key[",[39,3804,155],{"class":767},[39,3806,3807],{"class":777},"] ",[39,3809,2243],{"class":760},[39,3811,3812],{"class":1100}," '-'",[39,3814,3797],{"class":760},[39,3816,3817,3820,3823,3826,3829,3832,3834,3836],{"class":756,"line":1118},[39,3818,3819],{"class":1100},"  ''",[39,3821,3822],{"class":760}," +",[39,3824,3825],{"class":914}," parseInt",[39,3827,3828],{"class":777},"(key, ",[39,3830,3831],{"class":767},"10",[39,3833,1825],{"class":777},[39,3835,1540],{"class":760},[39,3837,3838],{"class":777}," key\n",[10,3840,3841,3842,3844,3845,3848],{},"这个函数接收一个值 ",[82,3843,1822],{},"，并执行了一系列",[44,3846,3847],{},"严格的检查","来确定它是否是一个合格的整数键。",[574,3850,3852,3853,1306],{"id":3851},"_1-检查是否为字符串-isstringkey","1. 检查是否为字符串 (",[82,3854,3855],{},"isString(key)",[10,3857,3855],{},[14,3859,3860,3871],{},[17,3861,3862,3864,3865,3867,3868,3870],{},[44,3863,2736],{}," 强制要求 ",[82,3866,1822],{}," 必须是",[44,3869,2299],{},"类型。在 JavaScript 中，对象键和数组索引最终都会被转换为字符串进行访问。",[17,3872,3873,3876,3877,661,3879,661,3881,493],{},[44,3874,3875],{},"排除："," 排除了所有非字符串类型（如 ",[82,3878,2752],{},[82,3880,2762],{},[82,3882,966],{},[574,3884,3886,3887,3890],{"id":3885},"_2-排除-nan-字符串","2. 排除 ",[82,3888,3889],{},"'NaN'"," 字符串",[10,3892,3893],{},"key!==′NaN′",[14,3895,3896],{},[17,3897,3898,3900,3901,3903,3904,3907,3908,3911],{},[44,3899,2736],{}," 排除字符串 ",[82,3902,3889],{},"。虽然 ",[82,3905,3906],{},"parseInt('NaN', 10)"," 会返回 ",[82,3909,3910],{},"NaN","，但这个显式检查是为了确保排除这个特殊值。",[574,3913,3915],{"id":3914},"_3-排除负号开头","3. 排除负号开头",[10,3917,1822,3918,3920],{},[39,3919,155],{},"!==′−′;",[14,3922,3923,3928],{},[17,3924,3925,3927],{},[44,3926,2736],{}," 排除所有以负号开头的字符串。数组索引必须是非负整数。",[17,3929,3930,3932,3933,486,3936,335],{},[44,3931,3875],{}," 例如，排除了字符串 ",[82,3934,3935],{},"'-1'",[82,3937,3938],{},"'-100'",[574,3940,3942],{"id":3941},"_4-核心检查是否为纯粹的整数字符串","4. 核心检查：是否为纯粹的整数字符串",[10,3944,3945],{},"” + parseInt(key,10)===key",[10,3947,3948,3949,3952],{},"这是最关键的一步，用于检查字符串是否",[44,3950,3951],{},"完全","由整数数字组成，且没有多余的字符。",[14,3954,3955,4009,4042],{},[17,3956,3957,3962,3963,3965,3966],{},[44,3958,3959,544],{},[82,3960,3961],{},"parseInt(key, 10)"," 尝试将字符串 ",[82,3964,1822],{}," 解析为十进制（基数 10）整数。\n",[14,3967,3968,3982,3998],{},[17,3969,3970,3978,3979,335],{},[44,3971,3972,3973,2493,3975,544],{},"如果 ",[82,3974,1822],{},[82,3976,3977],{},"'123'"," 解析结果是数字 ",[82,3980,3981],{},"123",[17,3983,3984,3978,3991,3993,3994,3997],{},[44,3985,3972,3986,2493,3988,544],{},[82,3987,1822],{},[82,3989,3990],{},"'123a'",[82,3992,3981],{},"（",[82,3995,3996],{},"parseInt"," 会停止于非数字字符）。",[17,3999,4000,3978,4007,335],{},[44,4001,3972,4002,2493,4004,544],{},[82,4003,1822],{},[82,4005,4006],{},"'01'",[82,4008,1352],{},[17,4010,4011,4016,4017,827,4020],{},[44,4012,4013,544],{},[82,4014,4015],{},"'' + ..."," 将解析后的数字",[44,4018,4019],{},"重新转换回字符串",[14,4021,4022,4029,4035],{},[17,4023,4024,4026,4027],{},[82,4025,3981],{}," → ",[82,4028,3977],{},[17,4030,4031,4026,4033],{},[82,4032,3981],{},[82,4034,3977],{},[17,4036,4037,4026,4039],{},[82,4038,1352],{},[82,4040,4041],{},"'1'",[17,4043,4044,4049,4050,4053,4054,4059],{},[44,4045,4046,544],{},[82,4047,4048],{},"=== key"," 将这个",[44,4051,4052],{},"重新转换的字符串","与",[44,4055,4056,4057,3890],{},"原始 ",[82,4058,1822],{},"进行严格比较。",[337,4061,4062,4086],{},[340,4063,4064],{},[343,4065,4066,4070,4075,4078,4081],{},[346,4067,4056,4068],{},[82,4069,1822],{},[346,4071,4072,4074],{},[82,4073,3996],{}," 结果",[346,4076,4077],{},"重新转换字符串",[346,4079,4080],{},"比较结果",[346,4082,4083],{},[44,4084,4085],{},"判断",[356,4087,4088,4113,4138,4162],{},[343,4089,4090,4096,4100,4104,4110],{},[361,4091,4092],{},[44,4093,4094],{},[82,4095,3977],{},[361,4097,4098],{},[82,4099,3981],{},[361,4101,4102],{},[82,4103,3977],{},[361,4105,4106,4109],{},[82,4107,4108],{},"'123' === '123'"," (true)",[361,4111,4112],{},"✅",[343,4114,4115,4121,4125,4129,4135],{},[361,4116,4117],{},[44,4118,4119],{},[82,4120,3990],{},[361,4122,4123],{},[82,4124,3981],{},[361,4126,4127],{},[82,4128,3977],{},[361,4130,4131,4134],{},[82,4132,4133],{},"'123' === '123a'"," (false)",[361,4136,4137],{},"❌",[343,4139,4140,4146,4150,4154,4159],{},[361,4141,4142],{},[44,4143,4144],{},[82,4145,4006],{},[361,4147,4148],{},[82,4149,1352],{},[361,4151,4152],{},[82,4153,4041],{},[361,4155,4156,4134],{},[82,4157,4158],{},"'1' === '01'",[361,4160,4161],{},"❌ (排除前导零)",[343,4163,4164,4171,4175,4179,4184],{},[361,4165,4166],{},[44,4167,4168],{},[82,4169,4170],{},"'1.2'",[361,4172,4173],{},[82,4174,1352],{},[361,4176,4177],{},[82,4178,4041],{},[361,4180,4181,4134],{},[82,4182,4183],{},"'1' === '1.2'",[361,4185,4137],{},[325,4187,4189,4190,4192,4193],{"id":4188},"高效地检查一个属性名key是否是-vue-框架内部保留使用的属性","高效地检查一个属性名（",[82,4191,1822],{},"）是否是 ",[44,4194,4195],{},"Vue 框架内部保留使用的属性",[747,4197,4199],{"className":902,"code":4198,"language":904,"meta":214,"style":214},"export const isReservedProp: (key: string) => boolean = \u002F*@__PURE__*\u002F makeMap(\n  \u002F\u002F the leading comma is intentional so empty string \"\" is also included\n  ',key,ref,ref_for,ref_key,' +\n    'onVnodeBeforeMount,onVnodeMounted,' +\n    'onVnodeBeforeUpdate,onVnodeUpdated,' +\n    'onVnodeBeforeUnmount,onVnodeUnmounted',\n)\n",[82,4200,4201,4237,4242,4250,4257,4264,4271],{"__ignoreMap":214},[39,4202,4203,4205,4207,4210,4212,4214,4216,4218,4220,4222,4224,4226,4228,4231,4234],{"class":756,"line":757},[39,4204,761],{"class":760},[39,4206,764],{"class":760},[39,4208,4209],{"class":914}," isReservedProp",[39,4211,771],{"class":760},[39,4213,1815],{"class":777},[39,4215,1822],{"class":1082},[39,4217,771],{"class":760},[39,4219,1627],{"class":767},[39,4221,1825],{"class":777},[39,4223,1726],{"class":760},[39,4225,3771],{"class":767},[39,4227,1067],{"class":760},[39,4229,4230],{"class":1146}," \u002F*@__PURE__*\u002F",[39,4232,4233],{"class":914}," makeMap",[39,4235,4236],{"class":777},"(\n",[39,4238,4239],{"class":756,"line":1073},[39,4240,4241],{"class":1146},"  \u002F\u002F the leading comma is intentional so empty string \"\" is also included\n",[39,4243,4244,4247],{"class":756,"line":1089},[39,4245,4246],{"class":1100},"  ',key,ref,ref_for,ref_key,'",[39,4248,4249],{"class":760}," +\n",[39,4251,4252,4255],{"class":756,"line":1112},[39,4253,4254],{"class":1100},"    'onVnodeBeforeMount,onVnodeMounted,'",[39,4256,4249],{"class":760},[39,4258,4259,4262],{"class":756,"line":1118},[39,4260,4261],{"class":1100},"    'onVnodeBeforeUpdate,onVnodeUpdated,'",[39,4263,4249],{"class":760},[39,4265,4266,4269],{"class":756,"line":1124},[39,4267,4268],{"class":1100},"    'onVnodeBeforeUnmount,onVnodeUnmounted'",[39,4270,1617],{"class":777},[39,4272,4273],{"class":756,"line":1131},[39,4274,1369],{"class":777},[10,4276,4277,4280,4281,4284,4285,4288],{},[82,4278,4279],{},"isReservedProp"," 检查的属性是 Vue 内部使用的特殊键，它们",[44,4282,4283],{},"不应该","被视为普通的组件 ",[82,4286,4287],{},"prop"," 或传递给子组件。",[10,4290,4291],{},"这个列表主要包含两类属性：",[337,4293,4294,4306],{},[340,4295,4296],{},[343,4297,4298,4301,4304],{},[346,4299,4300],{},"类型",[346,4302,4303],{},"属性示例",[346,4305,351],{},[356,4307,4308,4334],{},[343,4309,4310,4315,4328],{},[361,4311,4312],{},[44,4313,4314],{},"内部控制键",[361,4316,4317,661,4319,661,4322,661,4325],{},[82,4318,1822],{},[82,4320,4321],{},"ref",[82,4323,4324],{},"ref_for",[82,4326,4327],{},"ref_key",[361,4329,4330,4331],{},"用于",[44,4332,4333],{},"虚拟 DOM（VNode）的差异对比和模板引用的核心属性。",[343,4335,4336,4341,4350],{},[361,4337,4338],{},[44,4339,4340],{},"VNode 生命周期钩子",[361,4342,4343,661,4346,4349],{},[82,4344,4345],{},"onVnodeBeforeMount",[82,4347,4348],{},"onVnodeMounted",", 等",[361,4351,4330,4352,4355,4356,4358],{},[44,4353,4354],{},"监听 VNode 自身生命周期的特殊钩子","，不能作为普通 ",[82,4357,4287],{}," 传递。",[10,4360,4361,4362,4365,4366,4368,4369,4371],{},"如果 Vue 在模板中发现一个",[44,4363,4364],{},"属性是保留属性","，它会对其进行特殊处理（例如，将 ",[82,4367,1822],{}," 属性附加到 VNode 上，而不是作为组件 ",[82,4370,4287],{}," 传递下去）。",[325,4373,4374],{"id":4374},"性能与代码结构分析",[574,4376,4378,4379,4382],{"id":4377},"a-使用-makemap-高性能查找","A. 使用 ",[82,4380,4381],{},"makeMap"," (高性能查找)",[10,4384,4385,4386,4390],{},"export const isReservedProp: (key: string) => boolean=\u002F",[35,4387,162,4388],{},[44,4389,165],{},"\u002FmakeMap(…)",[14,4392,4393,4408],{},[17,4394,4395,381,4398,4400,4401,3993,4404,4407],{},[44,4396,4397],{},"机制：",[82,4399,4381],{}," 将长字符串列表转换为一个内部的 ",[44,4402,4403],{},"哈希表",[82,4405,4406],{},"Object.create(null)"," 字典）。",[17,4409,4410,4413,4414,4417],{},[44,4411,4412],{},"效果："," 检查一个属性是否保留，从 O(N)（遍历数组）优化为平均 ",[44,4415,4416],{},"O(1)（常数时间）"," 的哈希表查找，保证了运行时的极高效率。",[574,4419,4421,4422,4425],{"id":4420},"b-__pure__-构建时优化","B. ",[82,4423,4424],{},"\u002F*@__PURE__*\u002F"," (构建时优化)",[14,4427,4428,4437],{},[17,4429,4430,4433,4434,335],{},[44,4431,4432],{},"魔术注释："," 这是告诉 Tree-Shaking 工具（如 Rollup\u002FWebpack）这个函数调用 ",[44,4435,4436],{},"没有副作用",[17,4438,4439,4441,4442,4444],{},[44,4440,4412],{}," 如果 Vue 应用程序没有用到 ",[82,4443,4279],{}," 检查的某些功能（尽管不太可能），或者打包器能够确定它的结果是常量，就可以安全地进行优化或移除。",[574,4446,4448],{"id":4447},"c-列表内容与特殊处理","C. 列表内容与特殊处理",[10,4450,4451],{},"’,key,ref,ref_for,ref_key,...’",[14,4453,4454],{},[17,4455,4456,4459,4460,335],{},[44,4457,4458],{},"前导逗号（Leading Comma）："," 源码注释中提到了 ",[82,4461,4462],{},"\u002F\u002F the leading comma is intentional so empty string \"\" is also included",[325,4464,4466,4467,4192,4469],{"id":4465},"检查一个属性名key是否是-vue-框架内置的指令","检查一个属性名（",[82,4468,1822],{},[44,4470,4471],{},"Vue 框架内置的指令",[747,4473,4475],{"className":902,"code":4474,"language":904,"meta":214,"style":214},"export const isBuiltInDirective: (key: string) => boolean =\n  \u002F*@__PURE__*\u002F makeMap(\n    'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo',\n  )\n\n",[82,4476,4477,4505,4514,4521],{"__ignoreMap":214},[39,4478,4479,4481,4483,4486,4488,4490,4492,4494,4496,4498,4500,4502],{"class":756,"line":757},[39,4480,761],{"class":760},[39,4482,764],{"class":760},[39,4484,4485],{"class":914}," isBuiltInDirective",[39,4487,771],{"class":760},[39,4489,1815],{"class":777},[39,4491,1822],{"class":1082},[39,4493,771],{"class":760},[39,4495,1627],{"class":767},[39,4497,1825],{"class":777},[39,4499,1726],{"class":760},[39,4501,3771],{"class":767},[39,4503,4504],{"class":760}," =\n",[39,4506,4507,4510,4512],{"class":756,"line":1073},[39,4508,4509],{"class":1146},"  \u002F*@__PURE__*\u002F",[39,4511,4233],{"class":914},[39,4513,4236],{"class":777},[39,4515,4516,4519],{"class":756,"line":1089},[39,4517,4518],{"class":1100},"    'bind,cloak,else-if,else,for,html,if,model,on,once,pre,show,slot,text,memo'",[39,4520,1617],{"class":777},[39,4522,4523],{"class":756,"line":1112},[39,4524,4525],{"class":777},"  )\n",[10,4527,4528,4531],{},[82,4529,4530],{},"isBuiltInDirective"," 用于在 Vue 模板编译器或运行时识别那些不需要作为普通组件属性或 HTML 属性处理的特殊指令。",[10,4533,4534],{},"当模板编译器解析到一个属性时，它会首先检查这个属性是否是内置指令：",[14,4536,4537,4551],{},[17,4538,4539,4542,4543,4546,4547,4550],{},[44,4540,4541],{},"如果是内置指令","：它会被编译成特定的渲染函数逻辑（例如 ",[82,4544,4545],{},"v-if"," 编译成三元表达式，",[82,4548,4549],{},"v-model"," 编译成属性设置和事件监听）。",[17,4552,4553,4556,4557,4560,4561,4563],{},[44,4554,4555],{},"如果不是内置指令","：它可能是一个自定义指令（如 ",[82,4558,4559],{},"v-focus","）或一个普通的组件 ",[82,4562,4287],{},"\u002FHTML 属性。",[574,4565,4567],{"id":4566},"_2-列表内容","2. 列表内容",[10,4569,4570,4571,4574,4575,4577],{},"列表中包含了 Vue 提供的所有核心指令（在模板中通常以 ",[82,4572,4573],{},"v-"," 开头，但在内部存储时，",[82,4576,4573],{}," 前缀被移除）：",[14,4579,4580,4596,4607,4631,4642],{},[17,4581,4582,381,4585,661,4587,661,4590,661,4593],{},[44,4583,4584],{},"结构化指令 (Structural):",[82,4586,1456],{},[82,4588,4589],{},"else-if",[82,4591,4592],{},"else",[82,4594,4595],{},"for",[17,4597,4598,381,4601,661,4604],{},[44,4599,4600],{},"内容绑定指令 (Content):",[82,4602,4603],{},"html",[82,4605,4606],{},"text",[17,4608,4609,381,4612,4615,4616,4619,4620,4615,4623,4619,4626,4615,4629,1306],{},[44,4610,4611],{},"属性绑定指令 (Attribute):",[82,4613,4614],{},"bind"," (对应 ",[82,4617,4618],{},":prop","), ",[82,4621,4622],{},"on",[82,4624,4625],{},"@event",[82,4627,4628],{},"model",[82,4630,4549],{},[17,4632,4633,381,4636,661,4639],{},[44,4634,4635],{},"修改指令 (Modifier):",[82,4637,4638],{},"once",[82,4640,4641],{},"memo",[17,4643,4644,381,4647,661,4650,661,4653,661,4655],{},[44,4645,4646],{},"控制流指令 (Control):",[82,4648,4649],{},"show",[82,4651,4652],{},"cloak",[82,4654,747],{},[82,4656,4657],{},"slot",[574,4659,4661,4662,4664],{"id":4660},"_3-性能优化-和-isreservedprop-相同","3. 性能优化 (和 ",[82,4663,4279],{}," 相同)",[10,4666,4667,4668,4390],{},"export const isBuiltInDirective: (key: string) => boolean=\u002F",[35,4669,162,4670],{},[44,4671,165],{},[14,4673,4674,4690],{},[17,4675,4676,4680,4681,3993,4683,4685,4686,4689],{},[44,4677,4678,544],{},[82,4679,4381],{}," 将所有内置指令名转换为一个",[44,4682,4403],{},[82,4684,4406],{}," 字典），确保对任何键的查找都是平均 ",[44,4687,4688],{},"O(1)"," 的常数时间，速度极快。",[17,4691,4692,4697,4698,4700],{},[44,4693,4694,544],{},[82,4695,4696],{},"\u002F\\*@__PURE__\\*\u002F"," 告诉构建工具，这个函数调用",[44,4699,4436],{},"。这使得 Tree-Shaking 能够在最终的生产包中安全地移除任何未使用的相关代码。",[10,4702,4703],{},"简而言之，这段代码是为了让 Vue 能够以最高的效率，在数千次的模板解析中，快速准确地判断一个指令是否是它自己内置的核心功能。",[325,4705,4707,4710],{"id":4706},"记忆化memoization-模式",[44,4708,4709],{},"记忆化（Memoization）"," 模式",[747,4712,4714],{"className":902,"code":4713,"language":904,"meta":214,"style":214},"const cacheStringFunction = \u003CT extends (str: string) => string>(fn: T): T => {\n  const cache: Record\u003Cstring, string> = Object.create(null)\n  return ((str: string) => {\n    const hit = cache[str]\n    return hit || (cache[str] = fn(str))\n  }) as T\n}\n",[82,4715,4716,4765,4800,4819,4832,4854,4865],{"__ignoreMap":214},[39,4717,4718,4720,4723,4725,4727,4729,4732,4734,4736,4738,4740,4742,4744,4746,4748,4751,4753,4755,4757,4759,4761,4763],{"class":756,"line":757},[39,4719,1061],{"class":760},[39,4721,4722],{"class":914}," cacheStringFunction",[39,4724,1067],{"class":760},[39,4726,1279],{"class":777},[39,4728,1282],{"class":914},[39,4730,4731],{"class":760}," extends",[39,4733,1815],{"class":777},[39,4735,180],{"class":1082},[39,4737,771],{"class":760},[39,4739,1627],{"class":767},[39,4741,1825],{"class":777},[39,4743,1726],{"class":760},[39,4745,1627],{"class":767},[39,4747,1285],{"class":777},[39,4749,4750],{"class":1082},"fn",[39,4752,771],{"class":760},[39,4754,1293],{"class":914},[39,4756,1306],{"class":777},[39,4758,771],{"class":760},[39,4760,1293],{"class":914},[39,4762,1314],{"class":760},[39,4764,1070],{"class":777},[39,4766,4767,4769,4772,4774,4776,4778,4780,4782,4784,4786,4788,4791,4794,4796,4798],{"class":756,"line":1073},[39,4768,1321],{"class":760},[39,4770,4771],{"class":767}," cache",[39,4773,771],{"class":760},[39,4775,2223],{"class":914},[39,4777,1903],{"class":777},[39,4779,2749],{"class":767},[39,4781,661],{"class":777},[39,4783,2749],{"class":767},[39,4785,1912],{"class":777},[39,4787,781],{"class":760},[39,4789,4790],{"class":777}," Object.",[39,4792,4793],{"class":914},"create",[39,4795,1079],{"class":777},[39,4797,701],{"class":767},[39,4799,1369],{"class":777},[39,4801,4802,4804,4807,4809,4811,4813,4815,4817],{"class":756,"line":1089},[39,4803,3351],{"class":760},[39,4805,4806],{"class":777}," ((",[39,4808,180],{"class":1082},[39,4810,771],{"class":760},[39,4812,1627],{"class":767},[39,4814,1825],{"class":777},[39,4816,1726],{"class":760},[39,4818,1070],{"class":777},[39,4820,4821,4824,4827,4829],{"class":756,"line":1112},[39,4822,4823],{"class":760},"    const",[39,4825,4826],{"class":767}," hit",[39,4828,1067],{"class":760},[39,4830,4831],{"class":777}," cache[str]\n",[39,4833,4834,4837,4840,4843,4846,4848,4851],{"class":756,"line":1118},[39,4835,4836],{"class":760},"    return",[39,4838,4839],{"class":777}," hit ",[39,4841,4842],{"class":760},"||",[39,4844,4845],{"class":777}," (cache[str] ",[39,4847,781],{"class":760},[39,4849,4850],{"class":914}," fn",[39,4852,4853],{"class":777},"(str))\n",[39,4855,4856,4859,4862],{"class":756,"line":1124},[39,4857,4858],{"class":777},"  }) ",[39,4860,4861],{"class":760},"as",[39,4863,4864],{"class":914}," T\n",[39,4866,4867],{"class":756,"line":1131},[39,4868,1378],{"class":777},[10,4870,4871,4872,4874,4875,335],{},"该函数接收一个字符串处理函数 ",[82,4873,4750],{},"，并返回一个新的、",[44,4876,4877],{},"带有缓存功能的函数",[10,4879,4880],{},[44,4881,4882],{},"工作原理：",[4884,4885,4886,4910,4927],"ol",{},[17,4887,4888,4891,4892,4894,4895,4898,4899,4902,4903,4905,4906,4909],{},[44,4889,4890],{},"第一次调用："," 当新的字符串 ",[82,4893,180],{}," 传入时，它会在内部的 ",[82,4896,4897],{},"cache"," 中查找。由于第一次找不到（",[82,4900,4901],{},"hit"," 为 ",[82,4904,1002],{},"），它会执行原始函数 ",[82,4907,4908],{},"fn(str)"," 来计算结果。",[17,4911,4912,4915,4916,4919,4920,4923,4924,4926],{},[44,4913,4914],{},"存储结果："," 结果会被赋值给 ",[82,4917,4918],{},"cache[str]","，同时作为整个表达式的值被返回 (",[82,4921,4922],{},"cache[str] = fn(str)"," 的结果就是赋给 ",[82,4925,4918],{}," 的值)。",[17,4928,4929,4932,4933,4935,4936,4938,4939,4941,4942,4945,4946,4948],{},[44,4930,4931],{},"后续调用："," 再次传入相同的 ",[82,4934,180],{}," 时，",[82,4937,4918],{}," 会立即命中（",[82,4940,4901],{}," 有值），直接返回缓存的结果，",[44,4943,4944],{},"跳过","原始函数 ",[82,4947,4750],{}," 的重复计算。",[337,4950,4951,4964],{},[340,4952,4953],{},[343,4954,4955,4958,4961],{},[346,4956,4957],{},"代码段",[346,4959,4960],{},"机制",[346,4962,4963],{},"作用和优化",[356,4965,4966,4995,5018,5035,5048],{},[343,4967,4968,4975,4980],{},[361,4969,4970],{},[44,4971,4972],{},[82,4973,4974],{},"\u003CT extends (str: string) => string>(fn: T): T",[361,4976,4977],{},[44,4978,4979],{},"泛型与类型安全",[361,4981,4982,4983,4985,4986,4988,4989,4991,4992,4994],{},"确保了传入的 ",[82,4984,4750],{}," 和返回的函数 ",[82,4987,1282],{}," 具有完全相同的签名（输入 ",[82,4990,2749],{},"，输出 ",[82,4993,2749],{},"），保证了类型安全。",[343,4996,4997,5004,5009],{},[361,4998,4999],{},[44,5000,5001],{},[82,5002,5003],{},"const cache = Object.create(null)",[361,5005,5006],{},[44,5007,5008],{},"高性能哈希表",[361,5010,541,5011,5013,5014,5017],{},[82,5012,4406],{}," 创建一个",[44,5015,5016],{},"没有原型链的纯净对象","作为缓存容器。这使得查找速度最快（平均 O(1)），避免了原型链查找的开销。",[343,5019,5020,5027,5032],{},[361,5021,5022],{},[44,5023,5024],{},[82,5025,5026],{},"const hit = cache[str]",[361,5028,5029],{},[44,5030,5031],{},"快速查找",[361,5033,5034],{},"直接在哈希表中查找结果。",[343,5036,5037,5040,5042],{},[361,5038,5039],{},"**`return hit",[361,5041],{},[361,5043,5044,5045,5047],{},"(cache",[39,5046,180],{}," = fn(str))`**",[343,5049,5050,5055,5060],{},[361,5051,5052],{},[44,5053,5054],{},"闭包",[361,5056,5057],{},[44,5058,5059],{},"状态保持",[361,5061,5062,5063,5065,5066,5068],{},"内部的匿名函数通过 ",[44,5064,5054],{}," 机制，保持对外部 ",[82,5067,4897],{}," 变量的引用，确保了缓存状态的持久性。",[10,5070,5071,5072,5075,5076,5079,5080,5086,5087,5090,5091,5094],{},"Vue 源码中的 ",[82,5073,5074],{},"cacheStringFunction"," 所实现的作用，与 Python 标准库 ",[82,5077,5078],{},"functools"," 中的 ",[44,5081,5082,5085],{},[82,5083,5084],{},"@lru_cache"," 装饰器"," 所提供的 ",[44,5088,5089],{},"记忆化（Memoization）功能"," 是",[44,5092,5093],{},"完全一致的","，尽管实现细节和环境有所不同。",[574,5096,5098],{"id":5097},"关键区别lru-策略","关键区别：LRU 策略",[10,5100,5101],{},"这是它们之间最大的技术区别：",[14,5103,5104,5119],{},[17,5105,5106,5110,5111,5114,5115,5118],{},[44,5107,5108],{},[82,5109,5084],{},"：默认或配置后具有 ",[44,5112,5113],{},"LRU (Least Recently Used)"," 策略。这意味着当缓存达到最大容量时，它会自动丢弃",[44,5116,5117],{},"最久未使用","的条目，从而控制内存占用。",[17,5120,5121,5125,5126,5129],{},[44,5122,5123],{},[82,5124,5074],{},"：Vue 的这个简单实现",[44,5127,5128],{},"没有"," LRU 策略。它会为遇到的每个不同的输入字符串都保留一个缓存条目。",[574,5131,5133],{"id":5132},"为什么-vue-不用-lru","为什么 Vue 不用 LRU？",[10,5135,5136,5137,486,5140,5143],{},"在 Vue 的特定场景中，",[82,5138,5139],{},"camelize",[82,5141,5142],{},"hyphenate"," 等函数处理的键通常是：",[4884,5145,5146,5152],{},[17,5147,5148,5149,5151],{},"组件的 ",[82,5150,4287],{}," 名。",[17,5153,5154],{},"HTML 属性名\u002F事件名。",[10,5156,5157,5158,5161,5162,5165],{},"这些名字的集合在实际应用中是",[44,5159,5160],{},"有限且相对稳定","的。由于这些键会被反复使用，Vue 倾向于",[44,5163,5164],{},"永久缓存","它们，以获得最高的查找速度，而不需要复杂的 LRU 逻辑来管理一个不会无限膨胀的集合，从而避免了额外的性能开销。",[325,5167,5169,5172],{"id":5168},"字符串格式化连字符式与驼峰式互相转换",[44,5170,5171],{},"字符串格式化","（连字符式与驼峰式互相转换）",[747,5174,5176],{"className":902,"code":5175,"language":904,"meta":214,"style":214},"const camelizeRE = \u002F-\\w\u002Fg\n\u002F**\n * @private\n *\u002F\nexport const camelize: (str: string) => string = cacheStringFunction(\n  (str: string): string => {\n    return str.replace(camelizeRE, c => c.slice(1).toUpperCase())\n  },\n)\n\nconst hyphenateRE = \u002F\\B([A-Z])\u002Fg\n\u002F**\n * @private\n *\u002F\nexport const hyphenate: (str: string) => string = cacheStringFunction(\n  (str: string) => str.replace(hyphenateRE, '-$1').toLowerCase(),\n)\n",[82,5177,5178,5202,5207,5215,5220,5251,5272,5307,5312,5316,5320,5345,5349,5355,5359,5390,5422],{"__ignoreMap":214},[39,5179,5180,5182,5185,5187,5190,5193,5196,5199],{"class":756,"line":757},[39,5181,1061],{"class":760},[39,5183,5184],{"class":767}," camelizeRE",[39,5186,1067],{"class":760},[39,5188,5189],{"class":1100}," \u002F",[39,5191,3369],{"class":5192},"sA_wV",[39,5194,5195],{"class":767},"\\w",[39,5197,5198],{"class":1100},"\u002F",[39,5200,5201],{"class":760},"g\n",[39,5203,5204],{"class":756,"line":1073},[39,5205,5206],{"class":1146},"\u002F**\n",[39,5208,5209,5212],{"class":756,"line":1089},[39,5210,5211],{"class":1146}," * ",[39,5213,5214],{"class":760},"@private\n",[39,5216,5217],{"class":756,"line":1112},[39,5218,5219],{"class":1146}," *\u002F\n",[39,5221,5222,5224,5226,5229,5231,5233,5235,5237,5239,5241,5243,5245,5247,5249],{"class":756,"line":1118},[39,5223,761],{"class":760},[39,5225,764],{"class":760},[39,5227,5228],{"class":914}," camelize",[39,5230,771],{"class":760},[39,5232,1815],{"class":777},[39,5234,180],{"class":1082},[39,5236,771],{"class":760},[39,5238,1627],{"class":767},[39,5240,1825],{"class":777},[39,5242,1726],{"class":760},[39,5244,1627],{"class":767},[39,5246,1067],{"class":760},[39,5248,4722],{"class":914},[39,5250,4236],{"class":777},[39,5252,5253,5256,5258,5260,5262,5264,5266,5268,5270],{"class":756,"line":1124},[39,5254,5255],{"class":777},"  (",[39,5257,180],{"class":1082},[39,5259,771],{"class":760},[39,5261,1627],{"class":767},[39,5263,1306],{"class":777},[39,5265,771],{"class":760},[39,5267,1627],{"class":767},[39,5269,1314],{"class":760},[39,5271,1070],{"class":777},[39,5273,5274,5276,5279,5282,5285,5287,5289,5292,5294,5296,5298,5301,5304],{"class":756,"line":1131},[39,5275,4836],{"class":760},[39,5277,5278],{"class":777}," str.",[39,5280,5281],{"class":914},"replace",[39,5283,5284],{"class":777},"(camelizeRE, ",[39,5286,3505],{"class":1082},[39,5288,1314],{"class":760},[39,5290,5291],{"class":777}," c.",[39,5293,3359],{"class":914},[39,5295,1079],{"class":777},[39,5297,1352],{"class":767},[39,5299,5300],{"class":777},").",[39,5302,5303],{"class":914},"toUpperCase",[39,5305,5306],{"class":777},"())\n",[39,5308,5309],{"class":756,"line":1143},[39,5310,5311],{"class":777},"  },\n",[39,5313,5314],{"class":756,"line":1150},[39,5315,1369],{"class":777},[39,5317,5318],{"class":756,"line":1165},[39,5319,1128],{"emptyLinePlaceholder":1127},[39,5321,5322,5324,5327,5329,5331,5334,5336,5339,5341,5343],{"class":756,"line":1182},[39,5323,1061],{"class":760},[39,5325,5326],{"class":767}," hyphenateRE",[39,5328,1067],{"class":760},[39,5330,5189],{"class":1100},[39,5332,5333],{"class":760},"\\B",[39,5335,1079],{"class":5192},[39,5337,5338],{"class":767},"[A-Z]",[39,5340,1306],{"class":5192},[39,5342,5198],{"class":1100},[39,5344,5201],{"class":760},[39,5346,5347],{"class":756,"line":1187},[39,5348,5206],{"class":1146},[39,5350,5351,5353],{"class":756,"line":1192},[39,5352,5211],{"class":1146},[39,5354,5214],{"class":760},[39,5356,5357],{"class":756,"line":1197},[39,5358,5219],{"class":1146},[39,5360,5361,5363,5365,5368,5370,5372,5374,5376,5378,5380,5382,5384,5386,5388],{"class":756,"line":1213},[39,5362,761],{"class":760},[39,5364,764],{"class":760},[39,5366,5367],{"class":914}," hyphenate",[39,5369,771],{"class":760},[39,5371,1815],{"class":777},[39,5373,180],{"class":1082},[39,5375,771],{"class":760},[39,5377,1627],{"class":767},[39,5379,1825],{"class":777},[39,5381,1726],{"class":760},[39,5383,1627],{"class":767},[39,5385,1067],{"class":760},[39,5387,4722],{"class":914},[39,5389,4236],{"class":777},[39,5391,5392,5394,5396,5398,5400,5402,5404,5406,5408,5411,5414,5416,5419],{"class":756,"line":1218},[39,5393,5255],{"class":777},[39,5395,180],{"class":1082},[39,5397,771],{"class":760},[39,5399,1627],{"class":767},[39,5401,1825],{"class":777},[39,5403,1726],{"class":760},[39,5405,5278],{"class":777},[39,5407,5281],{"class":914},[39,5409,5410],{"class":777},"(hyphenateRE, ",[39,5412,5413],{"class":1100},"'-$1'",[39,5415,5300],{"class":777},[39,5417,5418],{"class":914},"toLowerCase",[39,5420,5421],{"class":777},"(),\n",[39,5423,5424],{"class":756,"line":1224},[39,5425,1369],{"class":777},[10,5427,5428,5429,5433],{},"它们都是通过 ",[44,5430,5431],{},[82,5432,5074],{}," 进行封装的，以实现高性能的缓存。",[325,5435,5437],{"id":5436},"字符串首字母大写capitalize的工具函数","字符串**首字母大写（Capitalize）**的工具函数",[747,5439,5441],{"className":902,"code":5440,"language":904,"meta":214,"style":214},"\u002F**\n * @private\n *\u002F\nexport const capitalize: \u003CT extends string>(str: T) => Capitalize\u003CT> =\n  cacheStringFunction(\u003CT extends string>(str: T) => {\n    return (str.charAt(0).toUpperCase() + str.slice(1)) as Capitalize\u003CT>\n  })\n\n",[82,5442,5443,5447,5453,5457,5499,5527,5573],{"__ignoreMap":214},[39,5444,5445],{"class":756,"line":757},[39,5446,5206],{"class":1146},[39,5448,5449,5451],{"class":756,"line":1073},[39,5450,5211],{"class":1146},[39,5452,5214],{"class":760},[39,5454,5455],{"class":756,"line":1089},[39,5456,5219],{"class":1146},[39,5458,5459,5461,5463,5466,5468,5470,5472,5474,5476,5478,5480,5482,5484,5486,5488,5491,5493,5495,5497],{"class":756,"line":1112},[39,5460,761],{"class":760},[39,5462,764],{"class":760},[39,5464,5465],{"class":914}," capitalize",[39,5467,771],{"class":760},[39,5469,1279],{"class":777},[39,5471,1282],{"class":914},[39,5473,4731],{"class":760},[39,5475,1627],{"class":767},[39,5477,1285],{"class":777},[39,5479,180],{"class":1082},[39,5481,771],{"class":760},[39,5483,1293],{"class":914},[39,5485,1825],{"class":777},[39,5487,1726],{"class":760},[39,5489,5490],{"class":914}," Capitalize",[39,5492,1903],{"class":777},[39,5494,1282],{"class":914},[39,5496,1912],{"class":777},[39,5498,2936],{"class":760},[39,5500,5501,5504,5507,5509,5511,5513,5515,5517,5519,5521,5523,5525],{"class":756,"line":1118},[39,5502,5503],{"class":914},"  cacheStringFunction",[39,5505,5506],{"class":777},"(\u003C",[39,5508,1282],{"class":914},[39,5510,4731],{"class":760},[39,5512,1627],{"class":767},[39,5514,1285],{"class":777},[39,5516,180],{"class":1082},[39,5518,771],{"class":760},[39,5520,1293],{"class":914},[39,5522,1825],{"class":777},[39,5524,1726],{"class":760},[39,5526,1070],{"class":777},[39,5528,5529,5531,5534,5537,5539,5541,5543,5545,5548,5551,5553,5555,5557,5559,5562,5564,5566,5568,5570],{"class":756,"line":1124},[39,5530,4836],{"class":760},[39,5532,5533],{"class":777}," (str.",[39,5535,5536],{"class":914},"charAt",[39,5538,1079],{"class":777},[39,5540,155],{"class":767},[39,5542,5300],{"class":777},[39,5544,5303],{"class":914},[39,5546,5547],{"class":777},"() ",[39,5549,5550],{"class":760},"+",[39,5552,5278],{"class":777},[39,5554,3359],{"class":914},[39,5556,1079],{"class":777},[39,5558,1352],{"class":767},[39,5560,5561],{"class":777},")) ",[39,5563,4861],{"class":760},[39,5565,5490],{"class":914},[39,5567,1903],{"class":777},[39,5569,1282],{"class":914},[39,5571,5572],{"class":777},">\n",[39,5574,5575],{"class":756,"line":1131},[39,5576,5577],{"class":777},"  })\n",[325,5579,5581,482,5584,5587,5588,482,5591,5594],{"id":5580},"普通事件名如-click转换为-标准事件处理函数属性名如-onclick的工具函数",[44,5582,5583],{},"普通事件名",[82,5585,5586],{},"'click'","）转换为 ",[44,5589,5590],{},"标准事件处理函数属性名",[82,5592,5593],{},"'onClick'","）的工具函数",[747,5596,5598],{"className":902,"code":5597,"language":904,"meta":214,"style":214},"\u002F**\n * @private\n *\u002F\nexport const toHandlerKey: \u003CT extends string>(\n  str: T,\n) => T extends '' ? '' : `on${Capitalize\u003CT>}` = cacheStringFunction(\n  \u003CT extends string>(str: T) => {\n    const s = str ? `on${capitalize(str)}` : ``\n    return s as T extends '' ? '' : `on${Capitalize\u003CT>}`\n  },\n)\n\n",[82,5599,5600,5604,5610,5614,5636,5647,5688,5713,5746,5780,5784],{"__ignoreMap":214},[39,5601,5602],{"class":756,"line":757},[39,5603,5206],{"class":1146},[39,5605,5606,5608],{"class":756,"line":1073},[39,5607,5211],{"class":1146},[39,5609,5214],{"class":760},[39,5611,5612],{"class":756,"line":1089},[39,5613,5219],{"class":1146},[39,5615,5616,5618,5620,5623,5625,5627,5629,5631,5633],{"class":756,"line":1112},[39,5617,761],{"class":760},[39,5619,764],{"class":760},[39,5621,5622],{"class":914}," toHandlerKey",[39,5624,771],{"class":760},[39,5626,1279],{"class":777},[39,5628,1282],{"class":914},[39,5630,4731],{"class":760},[39,5632,1627],{"class":767},[39,5634,5635],{"class":777},">(\n",[39,5637,5638,5641,5643,5645],{"class":756,"line":1118},[39,5639,5640],{"class":1082},"  str",[39,5642,771],{"class":760},[39,5644,1293],{"class":914},[39,5646,1617],{"class":777},[39,5648,5649,5651,5653,5655,5657,5660,5663,5665,5668,5671,5674,5676,5678,5680,5682,5684,5686],{"class":756,"line":1124},[39,5650,1825],{"class":777},[39,5652,1726],{"class":760},[39,5654,1293],{"class":914},[39,5656,4731],{"class":760},[39,5658,5659],{"class":1100}," ''",[39,5661,5662],{"class":760}," ?",[39,5664,5659],{"class":1100},[39,5666,5667],{"class":760}," :",[39,5669,5670],{"class":1100}," `on${",[39,5672,5673],{"class":914},"Capitalize",[39,5675,1903],{"class":1100},[39,5677,1282],{"class":914},[39,5679,1346],{"class":1100},[39,5681,1106],{"class":1100},[39,5683,1067],{"class":760},[39,5685,4722],{"class":914},[39,5687,4236],{"class":777},[39,5689,5690,5693,5695,5697,5699,5701,5703,5705,5707,5709,5711],{"class":756,"line":1131},[39,5691,5692],{"class":777},"  \u003C",[39,5694,1282],{"class":914},[39,5696,4731],{"class":760},[39,5698,1627],{"class":767},[39,5700,1285],{"class":777},[39,5702,180],{"class":1082},[39,5704,771],{"class":760},[39,5706,1293],{"class":914},[39,5708,1825],{"class":777},[39,5710,1726],{"class":760},[39,5712,1070],{"class":777},[39,5714,5715,5717,5720,5722,5725,5728,5730,5733,5735,5737,5739,5741,5743],{"class":756,"line":1143},[39,5716,4823],{"class":760},[39,5718,5719],{"class":767}," s",[39,5721,1067],{"class":760},[39,5723,5724],{"class":777}," str ",[39,5726,5727],{"class":760},"?",[39,5729,5670],{"class":1100},[39,5731,5732],{"class":914},"capitalize",[39,5734,1079],{"class":1100},[39,5736,180],{"class":777},[39,5738,1306],{"class":1100},[39,5740,1106],{"class":1100},[39,5742,5667],{"class":760},[39,5744,5745],{"class":1100}," ``\n",[39,5747,5748,5750,5753,5755,5757,5759,5761,5763,5765,5767,5769,5771,5773,5775,5777],{"class":756,"line":1150},[39,5749,4836],{"class":760},[39,5751,5752],{"class":777}," s ",[39,5754,4861],{"class":760},[39,5756,1293],{"class":914},[39,5758,4731],{"class":760},[39,5760,5659],{"class":1100},[39,5762,5662],{"class":760},[39,5764,5659],{"class":1100},[39,5766,5667],{"class":760},[39,5768,5670],{"class":1100},[39,5770,5673],{"class":914},[39,5772,1903],{"class":1100},[39,5774,1282],{"class":914},[39,5776,1346],{"class":1100},[39,5778,5779],{"class":1100},"}`\n",[39,5781,5782],{"class":756,"line":1165},[39,5783,5311],{"class":777},[39,5785,5786],{"class":756,"line":1182},[39,5787,1369],{"class":777},[574,5789,5791,5794],{"id":5790},"tohandlerkey-的核心作用",[82,5792,5793],{},"toHandlerKey"," 的核心作用",[10,5796,5797,5799,5800],{},[82,5798,5793],{}," 的作用是：",[44,5801,5802],{},"统一处理组件事件名与 VNode 属性名的转换。",[10,5804,5805,5806,971,5809,5812,5813,5816,5817,335],{},"当你在 Vue 模板中使用 ",[82,5807,5808],{},"@click",[82,5810,5811],{},"v-on:click"," 时，模板编译器",[44,5814,5815],{},"需要将这个事件名转换为一个 JavaScript 对象属性","，以便在 ",[44,5818,5819],{},"VNode 上存储事件监听器",[574,5821,5823],{"id":5822},"运行时-javascript-逻辑","运行时 JavaScript 逻辑",[10,5825,5826,5827,5829],{},"核心逻辑位于 ",[82,5828,5074],{}," 内部的匿名函数中：",[747,5831,5835],{"className":5832,"code":5833,"language":5834,"meta":214,"style":214},"language-javascript shiki shiki-themes github-light github-dark","(str: T) => {\n  const s = str ? `on${capitalize(str)}` : ``\n  return s as T extends '' ? '' : `on${Capitalize\u003CT>}`\n}\n","javascript",[82,5836,5837,5853,5881,5913],{"__ignoreMap":214},[39,5838,5839,5841,5843,5845,5847,5849,5851],{"class":756,"line":757},[39,5840,1079],{"class":777},[39,5842,180],{"class":1082},[39,5844,771],{"class":760},[39,5846,1293],{"class":914},[39,5848,1825],{"class":777},[39,5850,1726],{"class":760},[39,5852,1070],{"class":777},[39,5854,5855,5857,5859,5861,5863,5865,5867,5869,5871,5873,5875,5877,5879],{"class":756,"line":1073},[39,5856,1321],{"class":760},[39,5858,5719],{"class":767},[39,5860,1067],{"class":760},[39,5862,5724],{"class":777},[39,5864,5727],{"class":760},[39,5866,5670],{"class":1100},[39,5868,5732],{"class":914},[39,5870,1079],{"class":1100},[39,5872,180],{"class":777},[39,5874,1306],{"class":1100},[39,5876,1106],{"class":1100},[39,5878,5667],{"class":760},[39,5880,5745],{"class":1100},[39,5882,5883,5885,5887,5889,5891,5893,5895,5897,5899,5901,5903,5905,5907,5909,5911],{"class":756,"line":1089},[39,5884,3351],{"class":760},[39,5886,5752],{"class":777},[39,5888,4861],{"class":760},[39,5890,1293],{"class":914},[39,5892,4731],{"class":760},[39,5894,5659],{"class":1100},[39,5896,5662],{"class":760},[39,5898,5659],{"class":1100},[39,5900,5667],{"class":760},[39,5902,5670],{"class":1100},[39,5904,5673],{"class":914},[39,5906,1903],{"class":1100},[39,5908,1282],{"class":914},[39,5910,1346],{"class":1100},[39,5912,5779],{"class":1100},[39,5914,5915],{"class":756,"line":1112},[39,5916,1378],{"class":777},[4884,5918,5919,5938,5975],{},[17,5920,5921,381,5924,5927],{},[44,5922,5923],{},"空字符串检查：",[82,5925,5926],{},"str ? ... : \"\"",[14,5928,5929],{},[17,5930,5931,5932,5934,5935,335],{},"如果输入 ",[82,5933,180],{}," 是空字符串，则直接返回空字符串 ",[82,5936,5937],{},"\"\"",[17,5939,5940,381,5943,5945],{},[44,5941,5942],{},"转换逻辑：",[82,5944,244],{},[14,5946,5947,5963],{},[17,5948,5949,5954,5955,5957,5958,4026,5960,960],{},[44,5950,5951,544],{},[82,5952,5953],{},"capitalize(str)"," 调用了前面定义的 ",[82,5956,5732],{}," 函数，将输入字符串的首字母大写（如 ",[82,5959,5586],{},[82,5961,5962],{},"'Click'",[17,5964,5965,5968,5969,5972,5973,960],{},[44,5966,5967],{},"模板字面量："," 在首字母大写的字符串前添加前缀 ",[82,5970,5971],{},"'on'","，得到最终的处理函数键（如 ",[82,5974,5593],{},[17,5976,5977,5980,5981,5983,5984,5986],{},[44,5978,5979],{},"高性能缓存："," 整个函数被 ",[82,5982,5074],{}," 封装，确保任何事件名（如 ",[82,5985,5586],{},"）的转换只计算一次，后续调用直接从缓存中获取结果。",[10,5988,5989,5996,5997,544],{},[44,5990,5991,5992,5995],{},"条件类型 (",[82,5993,5994],{},"T extends '' ? '' : ...",")："," 这是一个类型级别的",[44,5998,5999],{},"三元表达式",[14,6001,6002,6017],{},[17,6003,6004,6007,6008,6010,6011,6014,6015,335],{},[44,6005,6006],{},"如果"," 输入类型 ",[82,6009,1282],{}," 是空字符串字面量类型 (",[82,6012,6013],{},"''",")，则返回类型是 ",[82,6016,6013],{},[17,6018,6019,6022,6023,6025],{},[44,6020,6021],{},"否则","（如果 ",[82,6024,1282],{}," 是任何非空字符串），则执行下一个类型构造。",[10,6027,6028],{},[44,6029,6030,6031,6033],{},"模板字面量类型 (",[82,6032,237],{},"):",[14,6035,6036,6046],{},[17,6037,6038,6039,6041,6042,6045],{},"它告诉 TypeScript 编译器：返回的类型是字符串 ",[82,6040,5971],{}," 后面连接着一个由 ",[82,6043,6044],{},"Capitalize\u003CT>"," 工具类型处理后的字符串（即首字母大写的输入类型）。",[17,6047,6048,6051,6052,6055,6056,335],{},[44,6049,6050],{},"例如："," 如果传入的类型是 ",[82,6053,6054],{},"'foo'","，编译器推断返回的类型是 ",[82,6057,6058],{},"'onFoo'",[325,6060,6061],{"id":6061},"安全地比较两个值是否发生变化",[747,6063,6065],{"className":902,"code":6064,"language":904,"meta":214,"style":214},"\u002F\u002F compare whether a value has changed, accounting for NaN.\nexport const hasChanged = (value: any, oldValue: any): boolean =>\n  !Object.is(value, oldValue)\n\n",[82,6066,6067,6072,6109],{"__ignoreMap":214},[39,6068,6069],{"class":756,"line":757},[39,6070,6071],{"class":1146},"\u002F\u002F compare whether a value has changed, accounting for NaN.\n",[39,6073,6074,6076,6078,6081,6083,6085,6087,6089,6092,6094,6097,6099,6101,6103,6105,6107],{"class":756,"line":1073},[39,6075,761],{"class":760},[39,6077,764],{"class":760},[39,6079,6080],{"class":914}," hasChanged",[39,6082,1067],{"class":760},[39,6084,1815],{"class":777},[39,6086,2964],{"class":1082},[39,6088,771],{"class":760},[39,6090,6091],{"class":767}," any",[39,6093,661],{"class":777},[39,6095,6096],{"class":1082},"oldValue",[39,6098,771],{"class":760},[39,6100,6091],{"class":767},[39,6102,1306],{"class":777},[39,6104,771],{"class":760},[39,6106,3771],{"class":767},[39,6108,2014],{"class":760},[39,6110,6111,6114,6116,6119],{"class":756,"line":1089},[39,6112,6113],{"class":760},"  !",[39,6115,911],{"class":777},[39,6117,6118],{"class":914},"is",[39,6120,6121],{"class":777},"(value, oldValue)\n",[574,6123,6125,6126,6129,6130,6132],{"id":6124},"为什么要用-objectis-而不是","为什么要用 ",[82,6127,6128],{},"!Object.is()"," 而不是 ",[82,6131,2243],{},"？",[10,6134,6135,6136,6139,6140,6143,6144,6147,6148,6150],{},"在大多数情况下，",[82,6137,6138],{},"!Object.is(a, b)"," 的结果与 ",[82,6141,6142],{},"a !== b"," 是一致的。然而，",[82,6145,6146],{},"Object.is()"," 解决了标准 JavaScript 严格相等性（",[82,6149,1540],{},"）的两个关键缺陷：",[337,6152,6153,6177],{},[340,6154,6155],{},[343,6156,6157,6160,6165,6169,6174],{},[346,6158,6159],{},"场景",[346,6161,6162,6163,1306],{},"标准比较 (",[82,6164,1540],{},[346,6166,6167],{},[82,6168,6146],{},[346,6170,6171,4074],{},[82,6172,6173],{},"hasChanged",[346,6175,6176],{},"目的",[356,6178,6179,6224,6265],{},[343,6180,6181,6185,6194,6203,6209],{},[361,6182,6183],{},[44,6184,3910],{},[361,6186,6187,4902,6190],{},[82,6188,6189],{},"NaN === NaN",[44,6191,6192],{},[82,6193,436],{},[361,6195,6196,4902,6199],{},[82,6197,6198],{},"Object.is(NaN, NaN)",[44,6200,6201],{},[82,6202,2365],{},[361,6204,6205],{},[44,6206,6207],{},[82,6208,436],{},[361,6210,6211,6214,6215,6217,6218,3732,6220,6223],{},[44,6212,6213],{},"核心目的："," 确保如果响应式值从 ",[82,6216,3910],{}," 变为 ",[82,6219,3910],{},[44,6221,6222],{},"不","触发更新。",[343,6225,6226,6231,6240,6249,6255],{},[361,6227,6228],{},[44,6229,6230],{},"有符号零",[361,6232,6233,4902,6236],{},[82,6234,6235],{},"-0 === +0",[44,6237,6238],{},[82,6239,2365],{},[361,6241,6242,4902,6245],{},[82,6243,6244],{},"Object.is(-0, +0)",[44,6246,6247],{},[82,6248,436],{},[361,6250,6251],{},[44,6252,6253],{},[82,6254,2365],{},[361,6256,6257,6258,726,6261,6264],{},"允许 Vue 在极少数需要区分 ",[82,6259,6260],{},"-0",[82,6262,6263],{},"+0"," 的场景下，正确识别为“已变化”。",[343,6266,6267,6272,6279,6286,6292],{},[361,6268,6269],{},[44,6270,6271],{},"其他值",[361,6273,6274,4902,6277],{},[82,6275,6276],{},"1 === 1",[82,6278,2365],{},[361,6280,6281,4902,6284],{},[82,6282,6283],{},"Object.is(1, 1)",[82,6285,2365],{},[361,6287,6288],{},[44,6289,6290],{},[82,6291,436],{},[361,6293,6294],{},"正常判断值未变化。",[574,6296,6298],{"id":6297},"核心价值处理-nan","核心价值：处理 NaN",[10,6300,6301,6302,6304,6305,6307,6308,335],{},"在响应式系统中，一个值从 ",[82,6303,3910],{}," 变为另一个 ",[82,6306,3910],{},"，从用户的角度来看，它",[44,6309,6310],{},"没有发生有意义的变化",[14,6312,6313,6325],{},[17,6314,6315,6316,6318,6319,4902,6322,6324],{},"如果使用 ",[82,6317,2243],{},"，由于 ",[82,6320,6321],{},"NaN !== NaN",[82,6323,2365],{},"，系统会错误地认为值已变化并触发不必要的更新。",[17,6326,541,6327,6318,6329,4902,6331,6333,6334,3729,6337,3732,6341,335],{},[82,6328,6128],{},[82,6330,6198],{},[82,6332,2365],{},"，所以 ",[82,6335,6336],{},"!Object.is(...)",[44,6338,6339],{},[82,6340,436],{},[44,6342,6343],{},"正确地阻止了不必要的更新",[325,6345,6347,6350],{"id":6346},"按顺序安全地调用一个函数数组中的所有函数并将相同的参数传递给它们",[44,6348,6349],{},"按顺序、安全地调用一个函数数组中的所有函数","，并将相同的参数传递给它们",[747,6352,6354],{"className":902,"code":6353,"language":904,"meta":214,"style":214},"export const invokeArrayFns = (fns: Function[], ...arg: any[]): void => {\n  for (let i = 0; i \u003C fns.length; i++) {\n    fns[i](...arg)\n  }\n}\n",[82,6355,6356,6398,6435,6445,6449],{"__ignoreMap":214},[39,6357,6358,6360,6362,6365,6367,6369,6372,6374,6376,6378,6380,6383,6385,6387,6390,6392,6394,6396],{"class":756,"line":757},[39,6359,761],{"class":760},[39,6361,764],{"class":760},[39,6363,6364],{"class":914}," invokeArrayFns",[39,6366,1067],{"class":760},[39,6368,1815],{"class":777},[39,6370,6371],{"class":914},"fns",[39,6373,771],{"class":760},[39,6375,2098],{"class":914},[39,6377,1296],{"class":777},[39,6379,921],{"class":760},[39,6381,6382],{"class":1082},"arg",[39,6384,771],{"class":760},[39,6386,6091],{"class":767},[39,6388,6389],{"class":777},"[])",[39,6391,771],{"class":760},[39,6393,1311],{"class":767},[39,6395,1314],{"class":760},[39,6397,1070],{"class":777},[39,6399,6400,6403,6405,6408,6411,6413,6416,6419,6421,6424,6427,6430,6433],{"class":756,"line":1073},[39,6401,6402],{"class":760},"  for",[39,6404,1815],{"class":777},[39,6406,6407],{"class":760},"let",[39,6409,6410],{"class":777}," i ",[39,6412,781],{"class":760},[39,6414,6415],{"class":767}," 0",[39,6417,6418],{"class":777},"; i ",[39,6420,1903],{"class":760},[39,6422,6423],{"class":777}," fns.",[39,6425,6426],{"class":767},"length",[39,6428,6429],{"class":777},"; i",[39,6431,6432],{"class":760},"++",[39,6434,1086],{"class":777},[39,6436,6437,6440,6442],{"class":756,"line":1089},[39,6438,6439],{"class":777},"    fns[i](",[39,6441,921],{"class":760},[39,6443,6444],{"class":777},"arg)\n",[39,6446,6447],{"class":756,"line":1112},[39,6448,1115],{"class":777},[39,6450,6451],{"class":756,"line":1118},[39,6452,1378],{"class":777},[10,6454,6455,6456,6459],{},"该函数专门用于处理 Vue 内部存储的",[44,6457,6458],{},"回调函数列表","。在 Vue 的生命周期、响应式系统的副作用（effect）清理、或 VNode 钩子等场景中，一个事件或一个状态变化可能需要触发多个注册的回调函数。",[337,6461,6462,6473],{},[340,6463,6464],{},[343,6465,6466,6468],{},[346,6467,6159],{},[346,6469,6470,6472],{},[82,6471,6371],{}," 数组中存储的内容",[356,6474,6475,6492,6506],{},[343,6476,6477,6482],{},[361,6478,6479],{},[44,6480,6481],{},"生命周期",[361,6483,6484,6485,971,6488,6491],{},"组件注册的所有 ",[82,6486,6487],{},"onMounted",[82,6489,6490],{},"onUpdated"," 钩子函数。",[343,6493,6494,6499],{},[361,6495,6496],{},[44,6497,6498],{},"副作用",[361,6500,6501,6502,6505],{},"响应式系统 ",[82,6503,6504],{},"effect"," 依赖变化时需要重新执行的所有函数。",[343,6507,6508,6513],{},[361,6509,6510],{},[44,6511,6512],{},"VNode 钩子",[361,6514,6515],{},"在 VNode 挂载、更新或卸载时需要运行的函数。",[325,6517,6519,6522],{"id":6518},"安全且不可见地给对象添加新属性",[44,6520,6521],{},"安全且不可见地","给对象添加新属性",[747,6524,6526],{"className":902,"code":6525,"language":904,"meta":214,"style":214},"export const def = (\n  obj: object,\n  key: string | symbol,\n  value: any,\n  writable = false,\n): void => {\n  Object.defineProperty(obj, key, {\n    configurable: true,\n    enumerable: false,\n    writable,\n    value,\n  })\n}\n\n",[82,6527,6528,6541,6552,6566,6577,6589,6601,6612,6621,6630,6635,6640,6644],{"__ignoreMap":214},[39,6529,6530,6532,6534,6537,6539],{"class":756,"line":757},[39,6531,761],{"class":760},[39,6533,764],{"class":760},[39,6535,6536],{"class":914}," def",[39,6538,1067],{"class":760},[39,6540,1604],{"class":777},[39,6542,6543,6546,6548,6550],{"class":756,"line":1073},[39,6544,6545],{"class":1082},"  obj",[39,6547,771],{"class":760},[39,6549,1614],{"class":767},[39,6551,1617],{"class":777},[39,6553,6554,6556,6558,6560,6562,6564],{"class":756,"line":1089},[39,6555,1622],{"class":1082},[39,6557,771],{"class":760},[39,6559,1627],{"class":767},[39,6561,1630],{"class":760},[39,6563,1633],{"class":767},[39,6565,1617],{"class":777},[39,6567,6568,6571,6573,6575],{"class":756,"line":1112},[39,6569,6570],{"class":1082},"  value",[39,6572,771],{"class":760},[39,6574,6091],{"class":767},[39,6576,1617],{"class":777},[39,6578,6579,6582,6584,6587],{"class":756,"line":1118},[39,6580,6581],{"class":777},"  writable ",[39,6583,781],{"class":760},[39,6585,6586],{"class":767}," false",[39,6588,1617],{"class":777},[39,6590,6591,6593,6595,6597,6599],{"class":756,"line":1124},[39,6592,1306],{"class":777},[39,6594,771],{"class":760},[39,6596,1311],{"class":767},[39,6598,1314],{"class":760},[39,6600,1070],{"class":777},[39,6602,6603,6606,6609],{"class":756,"line":1131},[39,6604,6605],{"class":777},"  Object.",[39,6607,6608],{"class":914},"defineProperty",[39,6610,6611],{"class":777},"(obj, key, {\n",[39,6613,6614,6617,6619],{"class":756,"line":1143},[39,6615,6616],{"class":777},"    configurable: ",[39,6618,2365],{"class":767},[39,6620,1617],{"class":777},[39,6622,6623,6626,6628],{"class":756,"line":1150},[39,6624,6625],{"class":777},"    enumerable: ",[39,6627,436],{"class":767},[39,6629,1617],{"class":777},[39,6631,6632],{"class":756,"line":1165},[39,6633,6634],{"class":777},"    writable,\n",[39,6636,6637],{"class":756,"line":1182},[39,6638,6639],{"class":777},"    value,\n",[39,6641,6642],{"class":756,"line":1187},[39,6643,5577],{"class":777},[39,6645,6646],{"class":756,"line":1192},[39,6647,1378],{"class":777},[574,6649,2429,6651,6654],{"id":6650},"_1-def-函数的核心目的",[82,6652,6653],{},"def"," 函数的核心目的",[10,6656,6657,6659,6660,6663,6664,6667,6668,335],{},[82,6658,6653],{}," 函数的目的是在不影响对象",[44,6661,6662],{},"可迭代性","和",[44,6665,6666],{},"响应式","的前提下，",[44,6669,6670],{},"为对象定义一个新属性",[10,6672,6673],{},"它在 Vue 内部有两个主要应用场景：",[4884,6675,6676,6689],{},[17,6677,6678,6681,6682,6685,6686,335],{},[44,6679,6680],{},"添加元数据（Metadata）："," 用于给响应式对象（由 ",[82,6683,6684],{},"Proxy"," 代理的对象）添加 ",[44,6687,6688],{},"Vue 内部的元数据或特殊标记",[17,6690,6691,6694,6695,6698,6699,6702,6703,335],{},[44,6692,6693],{},"避免枚举："," 确保添加的属性不会出现在 ",[82,6696,6697],{},"for...in"," 循环或 ",[82,6700,6701],{},"Object.keys()"," 的结果中，从而",[44,6704,6705],{},"保持数据的纯净",[2416,6707],{},[574,6709,6711,6712,6715],{"id":6710},"_2-objectdefineproperty-参数分析","2. ",[82,6713,6714],{},"Object.defineProperty"," 参数分析",[10,6717,6718,6720,6721,335],{},[82,6719,6653],{}," 函数接收四个参数，并在内部调用 ",[82,6722,6723],{},"Object.defineProperty(obj, key, descriptor)",[337,6725,6726,6737],{},[340,6727,6728],{},[343,6729,6730,6732,6735],{},[346,6731,933],{},[346,6733,6734],{},"值",[346,6736,936],{},[356,6738,6739,6754,6768,6782],{},[343,6740,6741,6748,6751],{},[361,6742,6743],{},[44,6744,6745],{},[82,6746,6747],{},"obj",[361,6749,6750],{},"传入的对象",[361,6752,6753],{},"目标对象，要添加属性的对象。",[343,6755,6756,6762,6765],{},[361,6757,6758],{},[44,6759,6760],{},[82,6761,1822],{},[361,6763,6764],{},"传入的键",[361,6766,6767],{},"要定义或修改的属性的名称。",[343,6769,6770,6776,6779],{},[361,6771,6772],{},[44,6773,6774],{},[82,6775,2964],{},[361,6777,6778],{},"传入的值",[361,6780,6781],{},"属性的值。",[343,6783,6784,6791,6796],{},[361,6785,6786],{},[44,6787,6788],{},[82,6789,6790],{},"writable",[361,6792,6793,6794,1042],{},"传入的布尔值（默认为 ",[82,6795,436],{},[361,6797,6798],{},"控制属性是否可被重新赋值。",[574,6800,6802],{"id":6801},"描述符descriptor的设置","描述符（Descriptor）的设置",[10,6804,6805,6807,6808,6811],{},[82,6806,6653],{}," 函数的强大之处在于它对属性描述符的",[44,6809,6810],{},"硬编码","设置，这决定了新属性的行为：",[337,6813,6814,6827],{},[340,6815,6816],{},[343,6817,6818,6821,6824],{},[346,6819,6820],{},"描述符",[346,6822,6823],{},"设置值",[346,6825,6826],{},"效果",[356,6828,6829,6851,6887,6911],{},[343,6830,6831,6838,6842],{},[361,6832,6833],{},[44,6834,6835],{},[82,6836,6837],{},"configurable",[361,6839,6840],{},[82,6841,2365],{},[361,6843,6844,6847,6848,6850],{},[44,6845,6846],{},"可配置。"," 允许在将来通过 ",[82,6849,6608],{}," 再次修改描述符，或删除该属性。这提供了灵活性。",[343,6852,6853,6860,6866],{},[361,6854,6855],{},[44,6856,6857],{},[82,6858,6859],{},"enumerable",[361,6861,6862],{},[44,6863,6864],{},[82,6865,436],{},[361,6867,6868,381,6871,6874,6875,6877,6878,971,6880,6883,6884,335],{},[44,6869,6870],{},"不可枚举。",[44,6872,6873],{},"这是关键！"," 这意味着属性不会出现在 ",[82,6876,6697],{}," 循环、",[82,6879,6701],{},[82,6881,6882],{},"JSON.stringify()"," 的结果中。确保了 Vue 内部属性的",[44,6885,6886],{},"隐蔽性",[343,6888,6889,6895,6900],{},[361,6890,6891],{},[44,6892,6893],{},[82,6894,6790],{},[361,6896,6897,6899],{},[82,6898,6790],{}," 变量",[361,6901,6902,6905,6906,6908,6909,335],{},[44,6903,6904],{},"可写性。"," 默认为 ",[82,6907,436],{},"（只读）。如果需要修改，调用者可以显式传入 ",[82,6910,2365],{},[343,6912,6913,6919,6923],{},[361,6914,6915],{},[44,6916,6917],{},[82,6918,2964],{},[361,6920,6921,6899],{},[82,6922,2964],{},[361,6924,6925],{},"属性的实际值。",[574,6927,6929],{"id":6928},"_3-为什么在响应式系统中使用它","3. 为什么在响应式系统中使用它？",[10,6931,6932,6933,6935,6936,6941],{},"在 Vue 2 的响应式系统中，",[82,6934,6714],{}," 是实现响应式的核心。但在 Vue 3 中，它主要用于 ",[44,6937,6938,6940],{},[82,6939,6684],{}," 无法接管或不需要响应式处理","的场景：",[4884,6943,6944,6954],{},[17,6945,6946,6949,6950,6953],{},[44,6947,6948],{},"防止响应式追踪："," 由于不可枚举 (",[82,6951,6952],{},"enumerable: false",")，当遍历对象进行响应式追踪时，这些内部属性会被跳过。",[17,6955,6956,6959,6960,6963],{},[44,6957,6958],{},"避免泄露："," 内部状态（如 ",[82,6961,6962],{},"__v_isRef"," 等标记）不会污染用户的数据迭代结果。",[10,6965,496,6966,6968,6969,6971],{},[82,6967,6653],{}," 是一种创建**“隐形”",[44,6970,6663],{},"“只读”**内部属性的标准化、安全且高效的方式。",[325,6973,6975,6976,6979],{"id":6974},"尝试将给定的值宽松地转换为数字","尝试将给定的值",[44,6977,6978],{},"宽松地","转换为数字",[747,6981,6983],{"className":902,"code":6982,"language":904,"meta":214,"style":214},"\u002F**\n * \"123-foo\" will be parsed to 123\n * This is used for the .number modifier in v-model\n *\u002F\nexport const looseToNumber = (val: any): any => {\n  const n = parseFloat(val)\n  return isNaN(n) ? val : n\n}\n\n",[82,6984,6985,6989,6994,6999,7003,7032,7047,7066],{"__ignoreMap":214},[39,6986,6987],{"class":756,"line":757},[39,6988,5206],{"class":1146},[39,6990,6991],{"class":756,"line":1073},[39,6992,6993],{"class":1146}," * \"123-foo\" will be parsed to 123\n",[39,6995,6996],{"class":756,"line":1089},[39,6997,6998],{"class":1146}," * This is used for the .number modifier in v-model\n",[39,7000,7001],{"class":756,"line":1112},[39,7002,5219],{"class":1146},[39,7004,7005,7007,7009,7012,7014,7016,7018,7020,7022,7024,7026,7028,7030],{"class":756,"line":1118},[39,7006,761],{"class":760},[39,7008,764],{"class":760},[39,7010,7011],{"class":914}," looseToNumber",[39,7013,1067],{"class":760},[39,7015,1815],{"class":777},[39,7017,1680],{"class":1082},[39,7019,771],{"class":760},[39,7021,6091],{"class":767},[39,7023,1306],{"class":777},[39,7025,771],{"class":760},[39,7027,6091],{"class":767},[39,7029,1314],{"class":760},[39,7031,1070],{"class":777},[39,7033,7034,7036,7039,7041,7044],{"class":756,"line":1124},[39,7035,1321],{"class":760},[39,7037,7038],{"class":767}," n",[39,7040,1067],{"class":760},[39,7042,7043],{"class":914}," parseFloat",[39,7045,7046],{"class":777},"(val)\n",[39,7048,7049,7051,7054,7057,7059,7061,7063],{"class":756,"line":1131},[39,7050,3351],{"class":760},[39,7052,7053],{"class":914}," isNaN",[39,7055,7056],{"class":777},"(n) ",[39,7058,5727],{"class":760},[39,7060,2108],{"class":777},[39,7062,771],{"class":760},[39,7064,7065],{"class":777}," n\n",[39,7067,7068],{"class":756,"line":1143},[39,7069,1378],{"class":777},[10,7071,7072,7073,7076,7077,7080],{},"在 Vue 中，当用户在 ",[82,7074,7075],{},"\u003Cinput>"," 上使用 ",[82,7078,7079],{},"v-model.number"," 时，Vue 需要确保输入的值（通常是字符串）被转换为真正的 JavaScript 数字类型。然而，这个转换是“宽松”的：",[14,7082,7083,7089],{},[17,7084,7085,7088],{},[44,7086,7087],{},"如果值以数字开头","，它应该被解析成数字。",[17,7090,7091,7094,7095,7098],{},[44,7092,7093],{},"如果值无法解析为数字","（例如，一个非数字字符串），则应",[44,7096,7097],{},"保持原样","（字符串）。",[10,7100,7101,7104],{},[82,7102,7103],{},"looseToNumber"," 函数正是实现了这种宽松转换的逻辑。",[574,7106,7107],{"id":7107},"代码逻辑分析",[10,7109,7110],{},"export const looseToNumber=(val:any):any⇒{…}",[4884,7112,7113,7170],{},[17,7114,7115,7120],{},[44,7116,7117],{},[82,7118,7119],{},"const n = parseFloat(val)",[14,7121,7122,7133],{},[17,7123,7124,7125,7130,7131,335],{},"使用 JavaScript 的内置函数 ",[44,7126,7127],{},[82,7128,7129],{},"parseFloat()"," 尝试解析输入值 ",[82,7132,1680],{},[17,7134,7135,7140,7141],{},[44,7136,7137,7139],{},[82,7138,7129],{}," 的特性："," 它会从字符串的开头开始解析数字，遇到第一个非数字字符时停止。\n",[14,7142,7143,7149,7156,7163],{},[17,7144,7145,4026,7147],{},[82,7146,3977],{},[82,7148,3981],{},[17,7150,7151,4026,7154],{},[82,7152,7153],{},"'123-foo'",[82,7155,3981],{},[17,7157,7158,4026,7161],{},[82,7159,7160],{},"'foo123'",[82,7162,3910],{},[17,7164,7165,7167,7168],{},[82,7166,6013],{}," (空字符串) → ",[82,7169,3910],{},[17,7171,7172,7177],{},[44,7173,7174],{},[82,7175,7176],{},"return isNaN(n) ? val : n",[14,7178,7179,7199,7221],{},[17,7180,7181,7184,7185,2600,7188,7191,7192,7195,7196,7198],{},[44,7182,7183],{},"检查结果："," 使用 ",[82,7186,7187],{},"isNaN()",[82,7189,7190],{},"parseFloat"," 的结果 ",[82,7193,7194],{},"n"," 是否为 ",[82,7197,3910],{},"（Not a Number）。",[17,7200,7201,7206,7207,7209,7210,971,7212,7214,7215,7220],{},[44,7202,7203,7204,544],{},"如果是 ",[82,7205,3910],{}," 说明 ",[82,7208,1680],{}," 无法从开头解析出任何有效的数字（如 ",[82,7211,6054],{},[82,7213,6013],{},"）。此时，函数返回",[44,7216,7217,7218],{},"原始值 ",[82,7219,1680],{},"，保持其类型不变（例如，仍是字符串）。",[17,7222,7223,7228,7229,335],{},[44,7224,7225,7226,544],{},"如果不是 ",[82,7227,3910],{}," 说明成功解析出了数字。此时，函数返回",[44,7230,7231,7232],{},"解析后的数字 ",[82,7233,7194],{},[337,7235,7236,7264],{},[340,7237,7238],{},[343,7239,7240,7245,7251,7256,7259],{},[346,7241,7242,7243,1306],{},"输入值 (",[82,7244,1680],{},[346,7246,7247,7250],{},[82,7248,7249],{},"parseFloat(val)"," (n)",[346,7252,7253],{},[82,7254,7255],{},"isNaN(n)",[346,7257,7258],{},"返回值",[346,7260,7261],{},[44,7262,7263],{},"用途",[356,7265,7266,7286,7308,7327],{},[343,7267,7268,7272,7276,7278,7283],{},[361,7269,7270],{},[82,7271,3977],{},[361,7273,7274],{},[82,7275,3981],{},[361,7277,436],{},[361,7279,7280,7282],{},[82,7281,3981],{}," (number)",[361,7284,7285],{},"成功转换",[343,7287,7288,7292,7296,7298,7302],{},[361,7289,7290],{},[82,7291,7153],{},[361,7293,7294],{},[82,7295,3981],{},[361,7297,436],{},[361,7299,7300,7282],{},[82,7301,3981],{},[361,7303,7304,7307],{},[44,7305,7306],{},"宽松转换","（忽略后缀）",[343,7309,7310,7314,7318,7320,7325],{},[361,7311,7312],{},[82,7313,6054],{},[361,7315,7316],{},[82,7317,3910],{},[361,7319,2365],{},[361,7321,7322,7324],{},[82,7323,6054],{}," (string)",[361,7326,7097],{},[343,7328,7329,7333,7337,7339,7343],{},[361,7330,7331],{},[82,7332,6013],{},[361,7334,7335],{},[82,7336,3910],{},[361,7338,2365],{},[361,7340,7341,7324],{},[82,7342,6013],{},[361,7344,7097],{},[10,7346,7347,7348,7350,7351,971,7354,7357,7358,7360],{},"这种宽松的转换对于 ",[82,7349,7079],{}," 非常实用，它能处理像用户输入 ",[82,7352,7353],{},"$123",[82,7355,7356],{},"123px"," 时，仍然能提取出前面的数字部分（尽管通常 ",[82,7359,4549],{}," 建议输入纯数字）。",[574,7362,400,7364,7367],{"id":7363},"与-tonumber-的区别",[82,7365,7366],{},"toNumber"," 的区别",[10,7369,7370,7371,7373,7374,7376],{},"在 Vue 源码中通常还有一个 ",[82,7372,7366],{}," 函数，它与 ",[82,7375,7103],{}," 的区别在于严格程度：",[14,7378,7379,7393],{},[17,7380,7381,7386,7387,7389,7390,7392],{},[44,7382,7383,7385],{},[82,7384,7366],{}," (严格)："," 只有当字符串",[44,7388,3951],{},"是一个数字时才返回数字，否则返回 ",[82,7391,3910],{}," 或原始值。",[17,7394,7395,7400,7401,7404],{},[44,7396,7397,7399],{},[82,7398,7103],{}," (宽松)："," 只要字符串",[44,7402,7403],{},"以数字开头","，就会解析并返回这个数字。",[325,7406,7408,7409,7412],{"id":7407},"解决-typescript-在非-nodejs-环境下编译时的类型检查问题","解决 TypeScript 在",[44,7410,7411],{},"非 Node.js 环境","下编译时的类型检查问题。",[747,7414,7416],{"className":902,"code":7415,"language":904,"meta":214,"style":214},"\u002F\u002F for typeof global checks without @types\u002Fnode\ndeclare var global: {}\n\n",[82,7417,7418,7423],{"__ignoreMap":214},[39,7419,7420],{"class":756,"line":757},[39,7421,7422],{"class":1146},"\u002F\u002F for typeof global checks without @types\u002Fnode\n",[39,7424,7425,7428,7431,7434,7436],{"class":756,"line":1073},[39,7426,7427],{"class":760},"declare",[39,7429,7430],{"class":760}," var",[39,7432,7433],{"class":777}," global",[39,7435,771],{"class":760},[39,7437,7438],{"class":777}," {}\n",[10,7440,7441],{},"你提供的这行代码：",[10,7443,7444],{},"TypeScript",[747,7446,7450],{"className":7447,"code":7449,"language":4606},[7448],"language-text","declare var global: {}\n",[82,7451,7449],{"__ignoreMap":214},[10,7453,7454,7455,7458,7459,7462,7463,7412],{},"它不是 Vue 源码的",[44,7456,7457],{},"执行逻辑","，而是一个纯粹的 ",[44,7460,7461],{},"TypeScript 声明（Declaration）","，目的是为了解决 TypeScript 在",[44,7464,7411],{},[2416,7466],{},[325,7468,7470,7473],{"id":7469},"declare-var-global-详解",[82,7471,7472],{},"declare var global: {}"," 详解",[574,7475,7477],{"id":7476},"_1-目的解决-typescript-编译时的类型错误","1. 目的：解决 TypeScript 编译时的类型错误",[10,7479,7480],{},"在 JavaScript 生态中，存在多种全局对象：",[14,7482,7483,7495],{},[17,7484,7485,7488,7489,971,7492,335],{},[44,7486,7487],{},"浏览器环境："," 全局对象是 ",[82,7490,7491],{},"window",[82,7493,7494],{},"self",[17,7496,7497,7488,7500,335],{},[44,7498,7499],{},"Node.js 环境：",[82,7501,7502],{},"global",[10,7504,7505,7506,7508,7509,5079,7512,7515,7516,7519,7520],{},"当你编写一个需要在 Node.js 中运行的模块时，你需要访问 ",[82,7507,7502],{},"。但是，如果你的 TypeScript 项目配置（例如，",[82,7510,7511],{},"tsconfig.json",[82,7513,7514],{},"lib"," 属性）没有包含 Node.js 的类型定义（通常来自 ",[82,7517,7518],{},"@types\u002Fnode","），那么 TypeScript 编译器会报告一个错误：",[44,7521,7522],{},"“找不到名称 ‘global’”。",[10,7524,7525,7526,7528,7529,7532],{},"这个 ",[82,7527,7472],{}," 就是用来",[44,7530,7531],{},"欺骗"," TypeScript 编译器的。",[574,7534,6711,7536,7538],{"id":7535},"_2-declare-关键字的作用",[82,7537,7427],{}," 关键字的作用",[14,7540,7541,7553],{},[17,7542,7543,7545,7546,7552],{},[82,7544,7427],{}," 告诉 TypeScript 编译器：“",[44,7547,7548,7549,7551],{},"别担心，在程序实际运行时，这个变量（",[82,7550,7502],{},"）已经存在于环境中。","”",[17,7554,7555,7556,7559,7560,7562,7563,335],{},"它只提供了",[44,7557,7558],{},"类型信息","（在这个例子中是空对象 ",[82,7561,3709],{},"），而",[44,7564,7565],{},"不生成任何实际的 JavaScript 代码",[574,7567,7569,7570,7573],{"id":7568},"_3-global-的意义","3. ",[82,7571,7572],{},"global: {}"," 的意义",[14,7575,7576,7585],{},[17,7577,7578,7581,7582,7584],{},[82,7579,7580],{},"var global",": 声明了一个名为 ",[82,7583,7502],{}," 的全局变量。",[17,7586,7587,7589],{},[82,7588,3709],{},": 简单地将它的类型定义为一个空对象。这是一种宽松的类型定义，表示它是一个对象，但不关心它内部有什么属性。",[574,7591,7593],{"id":7592},"_4-在-vue-源码中的上下文","4. 在 Vue 源码中的上下文",[10,7595,7596,7597,7600],{},"在 Vue 源码（尤其是用于寻找全局对象的 ",[82,7598,7599],{},"getGlobalThis"," 函数）中，这段声明的作用是：",[2474,7602,7603],{},[10,7604,7605,7606,7608,7609,7612,7613,7615],{},"确保即使开发者没有安装或配置 ",[82,7607,7518],{},"，代码中的运行时检查（例如：",[82,7610,7611],{},"typeof global !== 'undefined'","）也不会导致 TypeScript 编译器报错。它让 Vue 的工具函数在进行跨环境兼容性检查时，可以安全地引用 ",[82,7614,7502],{}," 这个标识符。",[325,7617,7619],{"id":7618},"可靠地找到所有可能的-javascript-环境浏览器nodejsweb-worker-等中的全局对象","可靠地找到所有可能的 JavaScript 环境（浏览器、Node.js、Web Worker 等）中的全局对象。",[747,7621,7623],{"className":902,"code":7622,"language":904,"meta":214,"style":214},"let _globalThis: any\nexport const getGlobalThis = (): any => {\n  return (\n    _globalThis ||\n    (_globalThis =\n      typeof globalThis !== 'undefined'\n        ? globalThis\n        : typeof self !== 'undefined'\n          ? self\n          : typeof window !== 'undefined'\n            ? window\n            : typeof global !== 'undefined'\n              ? global\n              : {})\n  )\n}\n",[82,7624,7625,7637,7659,7665,7673,7680,7693,7701,7715,7723,7737,7745,7759,7767,7775,7779],{"__ignoreMap":214},[39,7626,7627,7629,7632,7634],{"class":756,"line":757},[39,7628,6407],{"class":760},[39,7630,7631],{"class":777}," _globalThis",[39,7633,771],{"class":760},[39,7635,7636],{"class":767}," any\n",[39,7638,7639,7641,7643,7646,7648,7651,7653,7655,7657],{"class":756,"line":1073},[39,7640,761],{"class":760},[39,7642,764],{"class":760},[39,7644,7645],{"class":914}," getGlobalThis",[39,7647,1067],{"class":760},[39,7649,7650],{"class":777}," ()",[39,7652,771],{"class":760},[39,7654,6091],{"class":767},[39,7656,1314],{"class":760},[39,7658,1070],{"class":777},[39,7660,7661,7663],{"class":756,"line":1089},[39,7662,3351],{"class":760},[39,7664,1604],{"class":777},[39,7666,7667,7670],{"class":756,"line":1112},[39,7668,7669],{"class":777},"    _globalThis ",[39,7671,7672],{"class":760},"||\n",[39,7674,7675,7678],{"class":756,"line":1118},[39,7676,7677],{"class":777},"    (_globalThis ",[39,7679,2936],{"class":760},[39,7681,7682,7685,7688,7690],{"class":756,"line":1124},[39,7683,7684],{"class":760},"      typeof",[39,7686,7687],{"class":777}," globalThis ",[39,7689,2243],{"class":760},[39,7691,7692],{"class":1100}," 'undefined'\n",[39,7694,7695,7698],{"class":756,"line":1131},[39,7696,7697],{"class":760},"        ?",[39,7699,7700],{"class":777}," globalThis\n",[39,7702,7703,7706,7708,7711,7713],{"class":756,"line":1143},[39,7704,7705],{"class":760},"        :",[39,7707,774],{"class":760},[39,7709,7710],{"class":777}," self ",[39,7712,2243],{"class":760},[39,7714,7692],{"class":1100},[39,7716,7717,7720],{"class":756,"line":1150},[39,7718,7719],{"class":760},"          ?",[39,7721,7722],{"class":777}," self\n",[39,7724,7725,7728,7730,7733,7735],{"class":756,"line":1165},[39,7726,7727],{"class":760},"          :",[39,7729,774],{"class":760},[39,7731,7732],{"class":777}," window ",[39,7734,2243],{"class":760},[39,7736,7692],{"class":1100},[39,7738,7739,7742],{"class":756,"line":1182},[39,7740,7741],{"class":760},"            ?",[39,7743,7744],{"class":777}," window\n",[39,7746,7747,7750,7752,7755,7757],{"class":756,"line":1187},[39,7748,7749],{"class":760},"            :",[39,7751,774],{"class":760},[39,7753,7754],{"class":777}," global ",[39,7756,2243],{"class":760},[39,7758,7692],{"class":1100},[39,7760,7761,7764],{"class":756,"line":1192},[39,7762,7763],{"class":760},"              ?",[39,7765,7766],{"class":777}," global\n",[39,7768,7769,7772],{"class":756,"line":1197},[39,7770,7771],{"class":760},"              :",[39,7773,7774],{"class":777}," {})\n",[39,7776,7777],{"class":756,"line":1213},[39,7778,4525],{"class":777},[39,7780,7781],{"class":756,"line":1218},[39,7782,1378],{"class":777},[10,7784,7785,7786,7790,7791],{},"这段代码定义了 ",[44,7787,7788],{},[82,7789,7599],{}," 工具函数，它在像 Vue.js 这样的 JavaScript 库中至关重要，目的是",[44,7792,7619],{},[10,7794,7795,7796,7799],{},"这个函数结合了特定的检查顺序和",[44,7797,7798],{},"缓存机制","，以确保最大的兼容性和效率。",[574,7801,7803],{"id":7802},"_1-核心目的通用全局对象访问","1. 核心目的：通用全局对象访问",[10,7805,7806],{},"这个函数解决的核心问题是 JavaScript 环境中全局对象名称的不一致性：",[337,7808,7809,7818],{},[340,7810,7811],{},[343,7812,7813,7815],{},[346,7814,2560],{},[346,7816,7817],{},"全局对象名称",[356,7819,7820,7833,7844,7855],{},[343,7821,7822,7827],{},[361,7823,7824],{},[44,7825,7826],{},"现代标准 JS",[361,7828,7829,7832],{},[82,7830,7831],{},"globalThis"," (ES2020 标准)",[343,7834,7835,7840],{},[361,7836,7837],{},[44,7838,7839],{},"Web Worker\u002FService Worker",[361,7841,7842],{},[82,7843,7494],{},[343,7845,7846,7851],{},[361,7847,7848],{},[44,7849,7850],{},"浏览器窗口",[361,7852,7853],{},[82,7854,7491],{},[343,7856,7857,7862],{},[361,7858,7859],{},[44,7860,7861],{},"Node.js",[361,7863,7864],{},[82,7865,7502],{},[10,7867,7868,7870,7871,482,7874,486,7877,493],{},[82,7869,7599],{}," 按",[44,7872,7873],{},"优先级顺序系统地检查这些名称，直到找到一个，确保库无论在哪里运行都能正确访问全局 API",[82,7875,7876],{},"setTimeout",[82,7878,2865],{},[2416,7880],{},[574,7882,7884],{"id":7883},"_2-代码逻辑和回退链","2. 代码逻辑和回退链",[10,7886,7887,7888,7890,7891,7894,7895,544],{},"该函数使用逻辑 OR 运算符 (",[82,7889,4842],{},") 和一系列嵌套的三元运算符 (",[82,7892,7893],{},"? :",") 构成一个",[44,7896,7897],{},"有优先级的回退链",[4884,7899,7900,7956,7979,8004,8029,8054],{},[17,7901,7902,7905,7908,7909,7930],{},[44,7903,7904],{},"缓存检查（记忆化）：",[7906,7907],"br",{},"JavaScript",[747,7910,7912],{"className":749,"code":7911,"language":751,"meta":214,"style":214},"_globalThis || ( \u002F* ... 回退逻辑 ... *\u002F )\n",[82,7913,7914],{"__ignoreMap":214},[39,7915,7916,7919,7921,7924,7927],{"class":756,"line":757},[39,7917,7918],{"class":777},"_globalThis ",[39,7920,4842],{"class":760},[39,7922,7923],{"class":777}," ( ",[39,7925,7926],{"class":1146},"\u002F* ... 回退逻辑 ... *\u002F",[39,7928,7929],{"class":777}," )\n",[14,7931,7932,7939,7949],{},[17,7933,7934,7935,7938],{},"首先检查缓存变量 ",[82,7936,7937],{},"_globalThis"," 是否已被赋值。",[17,7940,7941,7942,7945,7946,7948],{},"如果已赋值，立即返回该值，",[44,7943,7944],{},"跳过所有后续的环境检查","。这是",[44,7947,7798],{},"，确保函数只在第一次运行时执行耗时的环境检查。",[17,7950,3972,7951,7953,7954,335],{},[82,7952,7937],{}," 是未定义的，则继续执行回退逻辑，并将结果赋值给 ",[82,7955,7937],{},[17,7957,7958,7961,7908,7963,7969],{},[44,7959,7960],{},"现代标准检查（ES2020）：",[7906,7962],{},[747,7964,7967],{"className":7965,"code":7966,"language":4606},[7448],"typeof globalThis !== 'undefined' ? globalThis : \u002F* ... *\u002F\n",[82,7968,7966],{"__ignoreMap":214},[14,7970,7971],{},[17,7972,7973,7974,7978],{},"优先尝试使用 ",[44,7975,7976],{},[82,7977,7831],{}," 变量。这是访问全局对象的官方标准化方式。",[17,7980,7981,7984,7908,7986,7992],{},[44,7982,7983],{},"Web Worker 检查：",[7906,7985],{},[747,7987,7990],{"className":7988,"code":7989,"language":4606},[7448],"typeof self !== 'undefined' ? self : \u002F* ... *\u002F\n",[82,7991,7989],{"__ignoreMap":214},[14,7993,7994],{},[17,7995,3972,7996,7998,7999,8003],{},[82,7997,7831],{}," 未定义，则检查 ",[44,8000,8001],{},[82,8002,7494],{},"，它通常是 Web Worker 和 Service Worker 中的全局对象。",[17,8005,8006,8009,7908,8011,8017],{},[44,8007,8008],{},"浏览器窗口检查：",[7906,8010],{},[747,8012,8015],{"className":8013,"code":8014,"language":4606},[7448],"typeof window !== 'undefined' ? window : \u002F* ... *\u002F\n",[82,8016,8014],{"__ignoreMap":214},[14,8018,8019],{},[17,8020,3972,8021,8023,8024,8028],{},[82,8022,7494],{}," 也未定义，则检查 ",[44,8025,8026],{},[82,8027,7491],{},"，这是标准浏览器环境中的经典全局对象。",[17,8030,8031,8034,7908,8036,8042],{},[44,8032,8033],{},"Node.js 检查：",[7906,8035],{},[747,8037,8040],{"className":8038,"code":8039,"language":4606},[7448],"typeof global !== 'undefined' ? global : \u002F* ... *\u002F\n",[82,8041,8039],{"__ignoreMap":214},[14,8043,8044],{},[17,8045,3972,8046,8048,8049,8053],{},[82,8047,7491],{}," 也缺失，则检查 ",[44,8050,8051],{},[82,8052,7502],{},"，这是 Node.js 中使用的全局对象。",[17,8055,8056,8059,7908,8061,8067],{},[44,8057,8058],{},"最终回退：",[7906,8060],{},[747,8062,8065],{"className":8063,"code":8064,"language":4606},[7448],": {}\n",[82,8066,8064],{"__ignoreMap":214},[14,8068,8069],{},[17,8070,6006,8071,8074,8075,8080],{},[44,8072,8073],{},"所有检查都失败","（在实际环境中极不可能），则返回一个",[44,8076,8077,8078,1306],{},"空对象 (",[82,8079,3709],{}," 作为最终、无害的回退，防止运行时错误。",[2416,8082],{},[574,8084,8086,8087,1306],{"id":8085},"_3-缓存机制-_globalthis","3. 缓存机制 (",[82,8088,7937],{},[10,8090,8091,8092,8095],{},"该函数是 ",[44,8093,8094],{},"延迟初始化（Lazy Initialization）结合记忆化"," 的典型例子：",[747,8097,8099],{"className":749,"code":8098,"language":751,"meta":214,"style":214},"_globalThis || (_globalThis = \u002F* 结果 *\u002F)\n",[82,8100,8101],{"__ignoreMap":214},[39,8102,8103,8105,8107,8110,8112,8115],{"class":756,"line":757},[39,8104,7918],{"class":777},[39,8106,4842],{"class":760},[39,8108,8109],{"class":777}," (_globalThis ",[39,8111,781],{"class":760},[39,8113,8114],{"class":1146}," \u002F* 结果 *\u002F",[39,8116,1369],{"class":777},[10,8118,8119,8120,8123,8124,8126,8127,8129],{},"第一次调用 ",[82,8121,8122],{},"getGlobalThis()"," 时，它执行完整的环境检查链，并将最终结果存储在 ",[82,8125,7937],{}," 中。所有后续调用都直接从 ",[82,8128,7937],{}," 中以 O(1) 的时间复杂度返回缓存值，保证了极高的效率。",[325,8131,8133,335],{"id":8132},"生成访问组件-props-对象的-javascript-表达式字符串",[44,8134,8135,8136,8139],{},"生成访问组件 ",[82,8137,8138],{},"props"," 对象的 JavaScript 表达式字符串",[747,8141,8143],{"className":902,"code":8142,"language":904,"meta":214,"style":214},"export function genPropsAccessExp(name: string): string {\n  return identRE.test(name)\n    ? `__props.${name}`\n    : `__props[${JSON.stringify(name)}]`\n}\n",[82,8144,8145,8172,8185,8197,8222],{"__ignoreMap":214},[39,8146,8147,8149,8152,8155,8157,8160,8162,8164,8166,8168,8170],{"class":756,"line":757},[39,8148,761],{"class":760},[39,8150,8151],{"class":760}," function",[39,8153,8154],{"class":914}," genPropsAccessExp",[39,8156,1079],{"class":777},[39,8158,8159],{"class":1082},"name",[39,8161,771],{"class":760},[39,8163,1627],{"class":767},[39,8165,1306],{"class":777},[39,8167,771],{"class":760},[39,8169,1627],{"class":767},[39,8171,1070],{"class":777},[39,8173,8174,8176,8179,8182],{"class":756,"line":1073},[39,8175,3351],{"class":760},[39,8177,8178],{"class":777}," identRE.",[39,8180,8181],{"class":914},"test",[39,8183,8184],{"class":777},"(name)\n",[39,8186,8187,8190,8193,8195],{"class":756,"line":1089},[39,8188,8189],{"class":760},"    ?",[39,8191,8192],{"class":1100}," `__props.${",[39,8194,8159],{"class":777},[39,8196,5779],{"class":1100},[39,8198,8199,8202,8205,8208,8210,8213,8215,8217,8219],{"class":756,"line":1112},[39,8200,8201],{"class":760},"    :",[39,8203,8204],{"class":1100}," `__props[${",[39,8206,8207],{"class":767},"JSON",[39,8209,1584],{"class":1100},[39,8211,8212],{"class":914},"stringify",[39,8214,1079],{"class":1100},[39,8216,8159],{"class":777},[39,8218,1306],{"class":1100},[39,8220,8221],{"class":1100},"}]`\n",[39,8223,8224],{"class":756,"line":1118},[39,8225,1378],{"class":777},[10,8227,8228,8229,8231,8232,8234],{},"它的核心目的是根据 ",[82,8230,4287],{}," 名称（",[82,8233,8159],{},"）的有效性，选择最快、最简洁的属性访问方式。",[2416,8236],{},[574,8238,8240,8243],{"id":8239},"genpropsaccessexp-函数详解",[82,8241,8242],{},"genPropsAccessExp"," 函数详解",[10,8245,8246,8247,8231,8249,8251,8252,8255],{},"该函数接收一个 ",[82,8248,4287],{},[82,8250,8159],{},"），并返回一个表示如何从内部的 ",[82,8253,8254],{},"__props"," 对象中读取该属性值的字符串。",[337,8257,8258,8266],{},[340,8259,8260],{},[343,8261,8262,8264],{},[346,8263,2662],{},[346,8265,936],{},[356,8267,8268,8289,8301],{},[343,8269,8270,8274],{},[361,8271,8272],{},[44,8273,2572],{},[361,8275,8276,8279,8280,661,8283,8285,8286,335],{},[82,8277,8278],{},"name: string","，要访问的属性名，例如 ",[82,8281,8282],{},"'id'",[82,8284,5593],{},", 或 ",[82,8287,8288],{},"'data-abc'",[343,8290,8291,8296],{},[361,8292,8293],{},[44,8294,8295],{},"输出",[361,8297,8298,8300],{},[82,8299,2749],{},"，可直接在生成的渲染函数中使用的 JavaScript 表达式。",[343,8302,8303,8308],{},[361,8304,8305],{},[44,8306,8307],{},"依赖",[361,8309,8310,8313,8314,8317],{},[82,8311,8312],{},"identRE","（未在提供的代码块中定义，但通常是一个",[44,8315,8316],{},"正则表达式","，用于检查字符串是否为有效的 JavaScript 标识符）。",[574,8319,8321,8322,1306],{"id":8320},"_1-检查是否为有效标识符-identretestname","1. 检查是否为有效标识符 (",[82,8323,8324],{},"identRE.test(name)",[10,8326,8327,8329,8330,8332],{},[82,8328,8312],{}," 通常用于检查 ",[82,8331,8159],{}," 是否符合 JavaScript 中变量或属性名的命名规范：",[14,8334,8335,8346,8349],{},[17,8336,8337,8338,8341,8342,8345],{},"以字母、下划线（",[82,8339,8340],{},"_","）或美元符号（",[82,8343,8344],{},"$","）开头。",[17,8347,8348],{},"后续字符可以是字母、数字、下划线或美元符号。",[17,8350,8351,8352,8354],{},"不能包含连字符（",[82,8353,3369],{},"）、空格或保留关键字。",[574,8356,8358],{"id":8357},"_2-生成点式访问dot-notation","2. 生成点式访问（Dot Notation）",[10,8360,8361,8362,8365],{},"$$\\text{? ",[82,8363,8364],{},"\\_\\_props.${name}","}$$",[14,8367,8368,8381,8390],{},[17,8369,8370,8373,8374,8376,8377,661,8379,960],{},[44,8371,8372],{},"条件："," 当 ",[82,8375,8159],{}," 是一个有效的 JavaScript 标识符时（例如 ",[82,8378,8282],{},[82,8380,5593],{},[17,8382,8383,8386,8387,335],{},[44,8384,8385],{},"结果："," 返回点式访问字符串，例如 ",[82,8388,8389],{},"__props.id",[17,8391,8392,381,8395,8398,8399,8402],{},[44,8393,8394],{},"优势：",[44,8396,8397],{},"点式访问","是 JavaScript 中",[44,8400,8401],{},"最快、最简洁","的属性访问方式，也是 Vue 优先选择的方式。",[574,8404,8406],{"id":8405},"_3-生成方括号访问bracket-notation","3. 生成方括号访问（Bracket Notation）",[10,8408,8409,8410,8365],{},"$$\\text{: ",[82,8411,8412],{},"\\_\\_props[${JSON.stringify(name)}]",[14,8414,8415,8431,8439],{},[17,8416,8417,8373,8419,381,8421,8424,8425,661,8427,8430],{},[44,8418,8372],{},[82,8420,8159],{},[44,8422,8423],{},"不是","一个有效的 JavaScript 标识符时（例如 ",[82,8426,8288],{},[82,8428,8429],{},"'aria-label'",", 或带有空格的键）。",[17,8432,8433,8435,8436,335],{},[44,8434,8385],{}," 返回方括号访问字符串，例如 ",[82,8437,8438],{},"__props[\"data-abc\"]",[17,8440,8441,2737,8447,8449,8450,8452,8453,8456,8457,8460],{},[44,8442,8443,8446],{},[82,8444,8445],{},"JSON.stringify(name)"," 的作用：",[82,8448,8159],{}," 字符串被正确地用引号包裹，如果 ",[82,8451,8159],{}," 字符串本身包含引号或其他特殊字符，",[82,8454,8455],{},"JSON.stringify"," 会进行适当的转义，以保证生成的表达式是",[44,8458,8459],{},"语法正确","的 JavaScript 字符串。",[574,8462,8463],{"id":8463},"示例对比",[337,8465,8466,8485],{},[340,8467,8468],{},[343,8469,8470,8475,8479,8482],{},[346,8471,8472,8473],{},"输入 ",[82,8474,8159],{},[346,8476,8477],{},[82,8478,8324],{},[346,8480,8481],{},"输出表达式",[346,8483,8484],{},"访问方式",[356,8486,8487,8504,8521,8543,8562],{},[343,8488,8489,8493,8497,8501],{},[361,8490,8491],{},[82,8492,8282],{},[361,8494,8495],{},[82,8496,2365],{},[361,8498,8499],{},[82,8500,8389],{},[361,8502,8503],{},"点式",[343,8505,8506,8510,8514,8519],{},[361,8507,8508],{},[82,8509,5593],{},[361,8511,8512],{},[82,8513,2365],{},[361,8515,8516],{},[82,8517,8518],{},"__props.onClick",[361,8520,8503],{},[343,8522,8523,8528,8535,8540],{},[361,8524,8525],{},[82,8526,8527],{},"'data-test'",[361,8529,8530,8532,8533,1306],{},[82,8531,436],{}," (包含连字符 ",[82,8534,3369],{},[361,8536,8537],{},[82,8538,8539],{},"__props[\"data-test\"]",[361,8541,8542],{},"方括号式",[343,8544,8545,8549,8555,8560],{},[361,8546,8547],{},[82,8548,8429],{},[361,8550,8551,8532,8553,1306],{},[82,8552,436],{},[82,8554,3369],{},[361,8556,8557],{},[82,8558,8559],{},"__props[\"aria-label\"]",[361,8561,8542],{},[343,8563,8564,8569,8574,8579],{},[361,8565,8566],{},[82,8567,8568],{},"'for'",[361,8570,8571,8573],{},[82,8572,436],{}," (保留关键字)",[361,8575,8576],{},[82,8577,8578],{},"__props[\"for\"]",[361,8580,8542],{},[8582,8583,8584],"style",{},"html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}html pre.shiki code .sA_wV, html code.shiki .sA_wV{--shiki-default:#032F62;--shiki-dark:#DBEDFF}",{"title":214,"searchDepth":1073,"depth":1073,"links":8586},[8587,8590,8596,8602,8604,8605,8614,8615,8617,8623,8627,8635,8637,8644,8650,8655,8657,8658,8664,8669,8671,8679,8684,8686,8695,8701],{"id":327,"depth":1073,"text":328,"children":8588},[8589],{"id":576,"depth":1089,"text":577},{"id":580,"depth":1073,"text":581,"children":8591},[8592,8594],{"id":893,"depth":1089,"text":8593},"Object.assign 的函数签名（Signature）",{"id":1038,"depth":1089,"text":8595},"Mixin 的实现方式（通常使用 Object.assign）",{"id":1260,"depth":1073,"text":1260,"children":8597},[8598,8600],{"id":1381,"depth":1089,"text":8599},"步骤 A: 查找元素的位置 (indexOf)",{"id":1443,"depth":1089,"text":8601},"步骤 B: 执行删除 (splice)",{"id":1560,"depth":1073,"text":8603},"安全且高效地检查对象自身是否包含某个属性的关键函数。",{"id":1836,"depth":1073,"text":1839},{"id":2420,"depth":1073,"text":8606,"children":8607},"为什么 val: unknown 并非多余？",[8608,8610,8612],{"id":2428,"depth":1089,"text":8609},"1. unknown 是最安全的类型",{"id":2483,"depth":1089,"text":8611},"2. 运行时 JavaScript 代码（toTypeString）的必要性",{"id":2535,"depth":1089,"text":8613},"3. 为什么 val is Map\u003Cany, any> 才是核心价值？",{"id":2629,"depth":1073,"text":2630},{"id":2902,"depth":1073,"text":8616},"最精确、最可靠的运行时类型检测的基础工具函数",{"id":3302,"depth":1073,"text":8618,"children":8619},"获取值 原始类型名称（Raw Type Name） 的工具函数",[8620,8621],{"id":3388,"depth":1089,"text":3388},{"id":3446,"depth":1089,"text":8622},"截取的位置 (.slice(8, -1))",{"id":3545,"depth":1073,"text":3546,"children":8624},[8625],{"id":3680,"depth":1089,"text":8626},"运行时可靠性：toTypeString",{"id":3740,"depth":1073,"text":3740,"children":8628},[8629,8631,8633,8634],{"id":3851,"depth":1089,"text":8630},"1. 检查是否为字符串 (isString(key))",{"id":3885,"depth":1089,"text":8632},"2. 排除 'NaN' 字符串",{"id":3914,"depth":1089,"text":3915},{"id":3941,"depth":1089,"text":3942},{"id":4188,"depth":1073,"text":8636},"高效地检查一个属性名（key）是否是 Vue 框架内部保留使用的属性",{"id":4374,"depth":1073,"text":4374,"children":8638},[8639,8641,8643],{"id":4377,"depth":1089,"text":8640},"A. 使用 makeMap (高性能查找)",{"id":4420,"depth":1089,"text":8642},"B. \u002F*@__PURE__*\u002F (构建时优化)",{"id":4447,"depth":1089,"text":4448},{"id":4465,"depth":1073,"text":8645,"children":8646},"检查一个属性名（key）是否是 Vue 框架内置的指令",[8647,8648],{"id":4566,"depth":1089,"text":4567},{"id":4660,"depth":1089,"text":8649},"3. 性能优化 (和 isReservedProp 相同)",{"id":4706,"depth":1073,"text":8651,"children":8652},"记忆化（Memoization） 模式",[8653,8654],{"id":5097,"depth":1089,"text":5098},{"id":5132,"depth":1089,"text":5133},{"id":5168,"depth":1073,"text":8656},"字符串格式化（连字符式与驼峰式互相转换）",{"id":5436,"depth":1073,"text":5437},{"id":5580,"depth":1073,"text":8659,"children":8660},"普通事件名（如 'click'）转换为 标准事件处理函数属性名（如 'onClick'）的工具函数",[8661,8663],{"id":5790,"depth":1089,"text":8662},"toHandlerKey 的核心作用",{"id":5822,"depth":1089,"text":5823},{"id":6061,"depth":1073,"text":6061,"children":8665},[8666,8668],{"id":6124,"depth":1089,"text":8667},"为什么要用 !Object.is() 而不是 !==？",{"id":6297,"depth":1089,"text":6298},{"id":6346,"depth":1073,"text":8670},"按顺序、安全地调用一个函数数组中的所有函数，并将相同的参数传递给它们",{"id":6518,"depth":1073,"text":6518,"children":8672},[8673,8675,8677,8678],{"id":6650,"depth":1089,"text":8674},"1. def 函数的核心目的",{"id":6710,"depth":1089,"text":8676},"2. Object.defineProperty 参数分析",{"id":6801,"depth":1089,"text":6802},{"id":6928,"depth":1089,"text":6929},{"id":6974,"depth":1073,"text":6974,"children":8680},[8681,8682],{"id":7107,"depth":1089,"text":7107},{"id":7363,"depth":1089,"text":8683},"与 toNumber 的区别",{"id":7407,"depth":1073,"text":8685},"解决 TypeScript 在非 Node.js 环境下编译时的类型检查问题。",{"id":7469,"depth":1073,"text":8687,"children":8688},"declare var global: {} 详解",[8689,8690,8692,8694],{"id":7476,"depth":1089,"text":7477},{"id":7535,"depth":1089,"text":8691},"2. declare 关键字的作用",{"id":7568,"depth":1089,"text":8693},"3. global: {} 的意义",{"id":7592,"depth":1089,"text":7593},{"id":7618,"depth":1073,"text":7619,"children":8696},[8697,8698,8699],{"id":7802,"depth":1089,"text":7803},{"id":7883,"depth":1089,"text":7884},{"id":8085,"depth":1089,"text":8700},"3. 缓存机制 (_globalThis)",{"id":8132,"depth":1073,"text":8702,"children":8703},"生成访问组件 props 对象的 JavaScript 表达式字符串。",[8704,8706,8708,8709,8710],{"id":8239,"depth":1089,"text":8705},"genPropsAccessExp 函数详解",{"id":8320,"depth":1089,"text":8707},"1. 检查是否为有效标识符 (identRE.test(name))",{"id":8357,"depth":1089,"text":8358},{"id":8405,"depth":1089,"text":8406},{"id":8463,"depth":1089,"text":8463},"md",{},"\u002Fvue\u002Fvue源码解读-通用工具函数",{"description":12},"Vue\u002Fvue源码解读-通用工具函数","PljNIp0tpyhY27K1348_0054A1WW25s8Lhw1XUsJbV4",1791042470888]