[{"data":1,"prerenderedAt":1240},["ShallowReactive",2],{"\u002Fposts\u002Fdifferent-prototypes":3,"surround:\u002Fposts\u002Fdifferent-prototypes":1231},{"id":4,"title":5,"body":6,"createdAt":1224,"description":16,"extension":1225,"meta":1226,"navigation":427,"path":1227,"seo":1228,"stem":1229,"__hash__":1230},"posts\u002Fposts\u002F2022\u002Fdifferent-prototypes.md","什么？不同函数的 prototype 竟然会表现不同？",{"type":7,"value":8,"toc":1216},"minimark",[9,13,17,83,90,98,104,192,218,232,242,300,303,309,315,342,349,447,453,456,523,533,546,574,577,603,606,629,633,644,683,698,734,745,758,792,805,815,850,853,870,880,905,915,921,946,954,984,992,1024,1027,1081,1087,1130,1133,1137,1148,1164,1174,1195,1212],[10,11,5],"h1",{"id":12},"什么不同函数的-prototype-竟然会表现不同",[14,15,16],"p",{},"之前在 Code Review 的时候发现了这样的代码：",[18,19,24],"pre",{"className":20,"code":21,"language":22,"meta":23,"style":23},"language-js shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","const formatter = options?.formatter ?? Function.prototype\nconst value = formatter(data)\n","js","",[25,26,27,66],"code",{"__ignoreMap":23},[28,29,32,36,40,44,47,50,53,56,60,63],"span",{"class":30,"line":31},"line",1,[28,33,35],{"class":34},"spNyl","const",[28,37,39],{"class":38},"sTEyZ"," formatter ",[28,41,43],{"class":42},"sMK4o","=",[28,45,46],{"class":38}," options",[28,48,49],{"class":42},"?.",[28,51,52],{"class":38},"formatter ",[28,54,55],{"class":42},"??",[28,57,59],{"class":58},"sBMFI"," Function",[28,61,62],{"class":42},".",[28,64,65],{"class":38},"prototype\n",[28,67,69,71,74,76,80],{"class":30,"line":68},2,[28,70,35],{"class":34},[28,72,73],{"class":38}," value ",[28,75,43],{"class":42},[28,77,79],{"class":78},"s2Zo4"," formatter",[28,81,82],{"class":38},"(data)\n",[14,84,85,86,89],{},"你能理解这里的 ",[25,87,88],{},"Function.prototype"," 的含义吗？",[91,92,94,95,23],"h2",{"id":93},"primitive-prototypes","基本类型的 ",[25,96,97],{},"prototype",[14,99,100,101,103],{},"在上面的代码里，",[25,102,88],{}," 实际上起到了 noop 的作用。可以打开控制台试一下：",[18,105,109],{"className":106,"code":107,"language":108,"meta":23,"style":23},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight","Function.prototype() \u002F\u002F undefined\nFunction.prototype(1) \u002F\u002F undefined\nFunction.prototype(1, 2) \u002F\u002F undefined\n;(0, Function.prototype)() \u002F\u002F undefined\n","javascript",[25,110,111,127,147,170],{"__ignoreMap":23},[28,112,113,116,118,120,123],{"class":30,"line":31},[28,114,115],{"class":58},"Function",[28,117,62],{"class":42},[28,119,97],{"class":78},[28,121,122],{"class":38},"() ",[28,124,126],{"class":125},"sHwdD","\u002F\u002F undefined\n",[28,128,129,131,133,135,138,142,145],{"class":30,"line":68},[28,130,115],{"class":58},[28,132,62],{"class":42},[28,134,97],{"class":78},[28,136,137],{"class":38},"(",[28,139,141],{"class":140},"sbssI","1",[28,143,144],{"class":38},") ",[28,146,126],{"class":125},[28,148,150,152,154,156,158,160,163,166,168],{"class":30,"line":149},3,[28,151,115],{"class":58},[28,153,62],{"class":42},[28,155,97],{"class":78},[28,157,137],{"class":38},[28,159,141],{"class":140},[28,161,162],{"class":42},",",[28,164,165],{"class":140}," 2",[28,167,144],{"class":38},[28,169,126],{"class":125},[28,171,173,176,178,181,183,185,187,190],{"class":30,"line":172},4,[28,174,175],{"class":42},";",[28,177,137],{"class":38},[28,179,180],{"class":140},"0",[28,182,162],{"class":42},[28,184,59],{"class":58},[28,186,62],{"class":42},[28,188,189],{"class":38},"prototype)() ",[28,191,126],{"class":125},[14,193,194,195,199,200,203,204,206,207,209,210,213,214,217],{},"在 JavaScript 里面，",[196,197,198],"strong",{},"基本类型的原型都是该函数的实例","。但是请注意，我们是不能用 ",[25,201,202],{},"instanceof"," 来验证的，因为 ",[25,205,202],{}," 只检查该对象的原型与函数的 ",[25,208,97],{}," 的关系，因此 ",[25,211,212],{},"Foo.prototype instanceof Foo"," 总是 ",[25,215,216],{},"false","。",[14,219,220,221,223,224,227,228,231],{},"那 ",[25,222,88],{}," 的行为是一个巧合吗？比如 ",[25,225,226],{},"Number"," 或者 ",[25,229,230],{},"String"," 呢？",[14,233,234,235,238,239,241],{},"对于几个基本类型的包装对象，我们可以通过 ",[25,236,237],{},".valueOf()"," 来获取其原始值。我们可以对 ",[25,240,97],{}," 也做类似的操作：",[18,243,245],{"className":106,"code":244,"language":108,"meta":23,"style":23},"Number.prototype.valueOf() \u002F\u002F 0\nString.prototype.valueOf() \u002F\u002F ''\nBoolean.prototype.valueOf() \u002F\u002F false\n",[25,246,247,265,282],{"__ignoreMap":23},[28,248,249,251,253,255,257,260,262],{"class":30,"line":31},[28,250,226],{"class":58},[28,252,62],{"class":42},[28,254,97],{"class":38},[28,256,62],{"class":42},[28,258,259],{"class":78},"valueOf",[28,261,122],{"class":38},[28,263,264],{"class":125},"\u002F\u002F 0\n",[28,266,267,269,271,273,275,277,279],{"class":30,"line":68},[28,268,230],{"class":58},[28,270,62],{"class":42},[28,272,97],{"class":38},[28,274,62],{"class":42},[28,276,259],{"class":78},[28,278,122],{"class":38},[28,280,281],{"class":125},"\u002F\u002F ''\n",[28,283,284,287,289,291,293,295,297],{"class":30,"line":149},[28,285,286],{"class":58},"Boolean",[28,288,62],{"class":42},[28,290,97],{"class":38},[28,292,62],{"class":42},[28,294,259],{"class":78},[28,296,122],{"class":38},[28,298,299],{"class":125},"\u002F\u002F false\n",[14,301,302],{},"好像……还挺符合直觉的？这些原型的值都是空值，也就是 falsy 的。",[91,304,306,307,23],{"id":305},"non-primitive-prototypes","非基本类型的 ",[25,308,97],{},[14,310,311,312,314],{},"对于非基本类型，情况会不同吗？比如我们熟悉的数组。尽管不能使用 ",[25,313,237],{}," 检查了，但对于数组我们还有一个大杀器：",[18,316,318],{"className":106,"code":317,"language":108,"meta":23,"style":23},"Array.isArray(Array.prototype) \u002F\u002F true\n",[25,319,320],{"__ignoreMap":23},[28,321,322,325,327,330,332,334,336,339],{"class":30,"line":31},[28,323,324],{"class":38},"Array",[28,326,62],{"class":42},[28,328,329],{"class":78},"isArray",[28,331,137],{"class":38},[28,333,324],{"class":58},[28,335,62],{"class":42},[28,337,338],{"class":38},"prototype) ",[28,340,341],{"class":125},"\u002F\u002F true\n",[14,343,344,345,348],{},"我们甚至可以把 ",[25,346,347],{},"Array.prototype"," 当成一个数组来使用！",[18,350,352],{"className":106,"code":351,"language":108,"meta":23,"style":23},"Array.prototype.length \u002F\u002F 0\nArray.prototype.push(42)\nArray.prototype[0] \u002F\u002F 42\nArray.prototype.length \u002F\u002F 1\n\n\u002F\u002F 然而...\n[][0] \u002F\u002F 42\n",[25,353,354,369,390,407,422,429,435],{"__ignoreMap":23},[28,355,356,358,360,362,364,367],{"class":30,"line":31},[28,357,324],{"class":58},[28,359,62],{"class":42},[28,361,97],{"class":38},[28,363,62],{"class":42},[28,365,366],{"class":38},"length ",[28,368,264],{"class":125},[28,370,371,373,375,377,379,382,384,387],{"class":30,"line":68},[28,372,324],{"class":58},[28,374,62],{"class":42},[28,376,97],{"class":38},[28,378,62],{"class":42},[28,380,381],{"class":78},"push",[28,383,137],{"class":38},[28,385,386],{"class":140},"42",[28,388,389],{"class":38},")\n",[28,391,392,394,396,399,401,404],{"class":30,"line":149},[28,393,324],{"class":58},[28,395,62],{"class":42},[28,397,398],{"class":38},"prototype[",[28,400,180],{"class":140},[28,402,403],{"class":38},"] ",[28,405,406],{"class":125},"\u002F\u002F 42\n",[28,408,409,411,413,415,417,419],{"class":30,"line":172},[28,410,324],{"class":58},[28,412,62],{"class":42},[28,414,97],{"class":38},[28,416,62],{"class":42},[28,418,366],{"class":38},[28,420,421],{"class":125},"\u002F\u002F 1\n",[28,423,425],{"class":30,"line":424},5,[28,426,428],{"emptyLinePlaceholder":427},true,"\n",[28,430,432],{"class":30,"line":431},6,[28,433,434],{"class":125},"\u002F\u002F 然而...\n",[28,436,438,441,443,445],{"class":30,"line":437},7,[28,439,440],{"class":38},"[][",[28,442,180],{"class":140},[28,444,403],{"class":38},[28,446,406],{"class":125},[14,448,449,450,452],{},"于是看上去，似乎非基本类型也遵循一样的规则：",[25,451,97],{}," 也是一个“原始”的实例。",[14,454,455],{},"如果是其他类似数组的东西呢？",[18,457,459],{"className":106,"code":458,"language":108,"meta":23,"style":23},"let foo\nfoo = Object.getPrototypeOf((function () { return arguments })()) \u002F\u002F Arguments {}\nfoo.length \u002F\u002F undefined\n",[25,460,461,469,512],{"__ignoreMap":23},[28,462,463,466],{"class":30,"line":31},[28,464,465],{"class":34},"let",[28,467,468],{"class":38}," foo\n",[28,470,471,474,476,479,481,484,487,490,493,496,500,503,506,509],{"class":30,"line":68},[28,472,473],{"class":38},"foo ",[28,475,43],{"class":42},[28,477,478],{"class":38}," Object",[28,480,62],{"class":42},[28,482,483],{"class":78},"getPrototypeOf",[28,485,486],{"class":38},"((",[28,488,489],{"class":34},"function",[28,491,492],{"class":42}," ()",[28,494,495],{"class":42}," {",[28,497,499],{"class":498},"s7zQu"," return",[28,501,502],{"class":38}," arguments",[28,504,505],{"class":42}," }",[28,507,508],{"class":38},")()) ",[28,510,511],{"class":125},"\u002F\u002F Arguments {}\n",[28,513,514,517,519,521],{"class":30,"line":149},[28,515,516],{"class":38},"foo",[28,518,62],{"class":42},[28,520,366],{"class":38},[28,522,126],{"class":125},[14,524,525,526,529,530,532],{},"看起来 ",[25,527,528],{},"Arguments"," 好像又和 ",[25,531,324],{}," 不一样了。",[14,534,535,536,538,539,542,543,545],{},"现在我们知道，在早期的 JavaScript （ES3 之前）中，实际上只有很少几种内置的非基本类型对象，除了 ",[25,537,324],{}," 我们还有 ",[25,540,541],{},"Date","。那么 ",[25,544,541],{}," 是否也如此呢？",[18,547,550],{"className":548,"code":549,"language":108,"meta":23,"style":23},"language-javascript shiki shiki-themes material-theme-lighter material-theme material-theme-palenight has-highlighted","Date.prototype.valueOf() \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: this is not a Date object.\n",[25,551,552,569],{"__ignoreMap":23},[28,553,557,559,561,563,565,567],{"class":554,"line":31},[30,555,556],"highlighted","error",[28,558,541],{"class":58},[28,560,62],{"class":42},[28,562,97],{"class":38},[28,564,62],{"class":42},[28,566,259],{"class":78},[28,568,122],{"class":38},[28,570,571],{"class":30,"line":68},[28,572,573],{"class":125},"\u002F\u002F Uncaught TypeError: this is not a Date object.\n",[14,575,576],{},"咦？这好像和之前我们的结论不同！再试试：",[18,578,580],{"className":548,"code":579,"language":108,"meta":23,"style":23},"Date.prototype.toString() \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: Method Date.prototype.toString called on incompatible receiver [object Object]\n",[25,581,582,598],{"__ignoreMap":23},[28,583,585,587,589,591,593,596],{"class":584,"line":31},[30,555,556],[28,586,541],{"class":58},[28,588,62],{"class":42},[28,590,97],{"class":38},[28,592,62],{"class":42},[28,594,595],{"class":78},"toString",[28,597,122],{"class":38},[28,599,600],{"class":30,"line":68},[28,601,602],{"class":125},"\u002F\u002F Uncaught TypeError: Method Date.prototype.toString called on incompatible receiver [object Object]\n",[14,604,605],{},"呃，为何会这样呢？",[14,607,608,609,611,612,614,615,617,618,628],{},"我想一些对 JS 非常熟悉的同学可能能给出可能的解释：毕竟 ",[25,610,541],{}," 是一个非常妖魔的函数——全 JS 只有 ",[25,613,541],{}," 实例的 ",[25,616,237],{}," 返回非本身类型的结果（很久以前我甚至基于此特性写过 ",[619,620,624,625],"a",{"href":621,"rel":622},"https:\u002F\u002Fscrapbook-cyansalt.vercel.app\u002Fis-date",[623],"nofollow","跨环境可用的判断对象是否为 Date 类型方法",[626,627],"br",{},"）。事实如此吗？我们可以随着历史的脚步继续前进。",[91,630,632],{"id":631},"new-specs","新的标准",[14,634,635,636,639,640,643],{},"ES3 引入了一些新的类型，比如 ",[25,637,638],{},"Error"," 和 ",[25,641,642],{},"RegExp","。我们现在试一下：",[18,645,647],{"className":106,"code":646,"language":108,"meta":23,"style":23},"Error.prototype.toString() \u002F\u002F 'Error'\nRegExp.prototype.toString() \u002F\u002F '\u002F(?:)\u002F'\n",[25,648,649,666],{"__ignoreMap":23},[28,650,651,653,655,657,659,661,663],{"class":30,"line":31},[28,652,638],{"class":58},[28,654,62],{"class":42},[28,656,97],{"class":38},[28,658,62],{"class":42},[28,660,595],{"class":78},[28,662,122],{"class":38},[28,664,665],{"class":125},"\u002F\u002F 'Error'\n",[28,667,668,670,672,674,676,678,680],{"class":30,"line":68},[28,669,642],{"class":58},[28,671,62],{"class":42},[28,673,97],{"class":38},[28,675,62],{"class":42},[28,677,595],{"class":78},[28,679,122],{"class":38},[28,681,682],{"class":125},"\u002F\u002F '\u002F(?:)\u002F'\n",[14,684,685,686,688,689,691,692,694,695,697],{},"看上去是如此合理。而且如果我们使用 ",[25,687,237],{},"，它们也不会像 ",[25,690,541],{}," 一样报错。这样看来确实是 ",[25,693,541],{}," 是异类吗？不要忘记，",[25,696,642],{}," 也是可以交互的，我们来试试：",[18,699,701],{"className":548,"code":700,"language":108,"meta":23,"style":23},"RegExp.prototype.test('foo') \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: Method RegExp.prototype.exec called on incompatible receiver [object Object]\n",[25,702,703,729],{"__ignoreMap":23},[28,704,706,708,710,712,714,717,719,722,725,727],{"class":705,"line":31},[30,555,556],[28,707,642],{"class":58},[28,709,62],{"class":42},[28,711,97],{"class":38},[28,713,62],{"class":42},[28,715,716],{"class":78},"test",[28,718,137],{"class":38},[28,720,721],{"class":42},"'",[28,723,516],{"class":724},"sfazB",[28,726,721],{"class":42},[28,728,144],{"class":38},[28,730,731],{"class":30,"line":68},[28,732,733],{"class":125},"\u002F\u002F Uncaught TypeError: Method RegExp.prototype.exec called on incompatible receiver [object Object]\n",[14,735,736,737,740,741,744],{},"咦，这和 ",[25,738,739],{},"Date.prototype.toString()"," 的报错竟然是一致的！为什么 ",[25,742,743],{},"RegExp.prototype.toString()"," 却不会报错呢？",[14,746,747,748,750,751,754,755,757],{},"我们过会儿再看这个问题。再看看 ",[25,749,638],{},"。尽管 ",[25,752,753],{},"Error.prototype"," 表现得很像是一个 ",[25,756,638],{},"，但实际上它不一致的更彻底：",[18,759,761],{"className":106,"code":760,"language":108,"meta":23,"style":23},"Object.prototype.toString.call(Error.prototype) \u002F\u002F '[object Object]'\n",[25,762,763],{"__ignoreMap":23},[28,764,765,768,770,772,774,776,778,781,783,785,787,789],{"class":30,"line":31},[28,766,767],{"class":58},"Object",[28,769,62],{"class":42},[28,771,97],{"class":38},[28,773,62],{"class":42},[28,775,595],{"class":38},[28,777,62],{"class":42},[28,779,780],{"class":78},"call",[28,782,137],{"class":38},[28,784,638],{"class":58},[28,786,62],{"class":42},[28,788,338],{"class":38},[28,790,791],{"class":125},"\u002F\u002F '[object Object]'\n",[14,793,794,795,797,798,800,801,804],{},"它甚至都没有 ",[25,796,638],{}," 的标签！说明它就是一个普通的对象，只是因为 ",[25,799,638],{}," 具有特殊的 ",[25,802,803],{},".toString()"," 逻辑才有此输出。",[14,806,807,808,810,811,814],{},"再来看看其他的类型吧，比如更后面的 ",[25,809,324],{}," 的亲戚 ",[25,812,813],{},"UInt8Array","：",[18,816,818],{"className":548,"code":817,"language":108,"meta":23,"style":23},"Uint8Array.prototype.set([], 0) \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: this is not a typed array.\n",[25,819,820,845],{"__ignoreMap":23},[28,821,823,826,828,830,832,835,838,840,843],{"class":822,"line":31},[30,555,556],[28,824,825],{"class":58},"Uint8Array",[28,827,62],{"class":42},[28,829,97],{"class":38},[28,831,62],{"class":42},[28,833,834],{"class":78},"set",[28,836,837],{"class":38},"([]",[28,839,162],{"class":42},[28,841,842],{"class":140}," 0",[28,844,144],{"class":38},[28,846,847],{"class":30,"line":68},[28,848,849],{"class":125},"\u002F\u002F Uncaught TypeError: this is not a typed array.\n",[14,851,852],{},"呃，画风突变？",[14,854,855,856,859,860,859,863,859,866,869],{},"继续看看其他的。ES2015 之后又引入了很多很多类型：",[25,857,858],{},"Symbol","、",[25,861,862],{},"Set",[25,864,865],{},"Map",[25,867,868],{},"Promise"," 等等。我们可以挑几个典型的试试看。",[14,871,872,873,876,877,879],{},"首先是 ",[25,874,875],{},"BigInt","。按理说应该和 ",[25,878,226],{}," 的行为类似，试试看：",[18,881,883],{"className":548,"code":882,"language":108,"meta":23,"style":23},"BigInt.prototype.valueOf() \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: BigInt.prototype.valueOf requires that 'this' be a BigInt\n",[25,884,885,900],{"__ignoreMap":23},[28,886,888,890,892,894,896,898],{"class":887,"line":31},[30,555,556],[28,889,875],{"class":58},[28,891,62],{"class":42},[28,893,97],{"class":38},[28,895,62],{"class":42},[28,897,259],{"class":78},[28,899,122],{"class":38},[28,901,902],{"class":30,"line":68},[28,903,904],{"class":125},"\u002F\u002F Uncaught TypeError: BigInt.prototype.valueOf requires that 'this' be a BigInt\n",[14,906,907,908,911,912,217],{},"咦，又是一种新的报错？实际上错误与之前的错误不同的原因是因为，BigInt 是没有包装类型的，也就是不存在 ",[25,909,910],{},"typeof new BigInt() === 'object'"," 这回事。事实上你甚至无法 ",[25,913,914],{},"new BigInt()",[14,916,917,918,920],{},"再试一个基本类型，",[25,919,858],{}," 同样是没有包装类型的，那么：",[18,922,924],{"className":548,"code":923,"language":108,"meta":23,"style":23},"Symbol.prototype.valueOf() \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: Symbol.prototype.valueOf requires that 'this' be a Symbol\n",[25,925,926,941],{"__ignoreMap":23},[28,927,929,931,933,935,937,939],{"class":928,"line":31},[30,555,556],[28,930,858],{"class":58},[28,932,62],{"class":42},[28,934,97],{"class":38},[28,936,62],{"class":42},[28,938,259],{"class":78},[28,940,122],{"class":38},[28,942,943],{"class":30,"line":68},[28,944,945],{"class":125},"\u002F\u002F Uncaught TypeError: Symbol.prototype.valueOf requires that 'this' be a Symbol\n",[14,947,948,949,951,952,814],{},"果然如此。那么让我们试试非基本类型吧，看看 ",[25,950,324],{}," 的其他亲戚们。先试试 ",[25,953,862],{},[18,955,957],{"className":548,"code":956,"language":108,"meta":23,"style":23},"Set.prototype.add(1) \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: Method Set.prototype.add called on incompatible receiver #\u003CSet>\n",[25,958,959,979],{"__ignoreMap":23},[28,960,962,964,966,968,970,973,975,977],{"class":961,"line":31},[30,555,556],[28,963,862],{"class":58},[28,965,62],{"class":42},[28,967,97],{"class":38},[28,969,62],{"class":42},[28,971,972],{"class":78},"add",[28,974,137],{"class":38},[28,976,141],{"class":140},[28,978,144],{"class":38},[28,980,981],{"class":30,"line":68},[28,982,983],{"class":125},"\u002F\u002F Uncaught TypeError: Method Set.prototype.add called on incompatible receiver #\u003CSet>\n",[14,985,986,987,989,990,814],{},"好嘛，那 ",[25,988,865],{}," 等等就先不用试了。再试一下 ",[25,991,868],{},[18,993,995],{"className":548,"code":994,"language":108,"meta":23,"style":23},"Promise.prototype.then(console.log) \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: Method Promise.prototype.then called on incompatible receiver #\u003CPromise>\n",[25,996,997,1019],{"__ignoreMap":23},[28,998,1000,1002,1004,1006,1008,1011,1014,1016],{"class":999,"line":31},[30,555,556],[28,1001,868],{"class":58},[28,1003,62],{"class":42},[28,1005,97],{"class":38},[28,1007,62],{"class":42},[28,1009,1010],{"class":78},"then",[28,1012,1013],{"class":38},"(console",[28,1015,62],{"class":42},[28,1017,1018],{"class":38},"log) ",[28,1020,1021],{"class":30,"line":68},[28,1022,1023],{"class":125},"\u002F\u002F Uncaught TypeError: Method Promise.prototype.then called on incompatible receiver #\u003CPromise>\n",[14,1025,1026],{},"行吧。我们最后再试一个没有暴露构造函数的类型：",[18,1028,1030],{"className":548,"code":1029,"language":108,"meta":23,"style":23},"let foo\nfoo = Object.getPrototypeOf(function *() {}) \u002F\u002F GeneratorFunction {}\n\nfoo() \u002F\u002F [!code error]\n\u002F\u002F Uncaught TypeError: foo is not a function\n",[25,1031,1032,1038,1065,1069,1076],{"__ignoreMap":23},[28,1033,1034,1036],{"class":30,"line":31},[28,1035,465],{"class":34},[28,1037,468],{"class":38},[28,1039,1040,1042,1044,1046,1048,1050,1052,1054,1057,1060,1062],{"class":30,"line":68},[28,1041,473],{"class":38},[28,1043,43],{"class":42},[28,1045,478],{"class":38},[28,1047,62],{"class":42},[28,1049,483],{"class":78},[28,1051,137],{"class":38},[28,1053,489],{"class":34},[28,1055,1056],{"class":42}," *()",[28,1058,1059],{"class":42}," {}",[28,1061,144],{"class":38},[28,1063,1064],{"class":125},"\u002F\u002F GeneratorFunction {}\n",[28,1066,1067],{"class":30,"line":149},[28,1068,428],{"emptyLinePlaceholder":427},[28,1070,1072,1074],{"class":1071,"line":172},[30,555,556],[28,1073,516],{"class":78},[28,1075,122],{"class":38},[28,1077,1078],{"class":30,"line":424},[28,1079,1080],{"class":125},"\u002F\u002F Uncaught TypeError: foo is not a function\n",[14,1082,1083,1084,1086],{},"我们现在总结一下，实际上，这些内置类型的 ",[25,1085,97],{}," 可以按照表现分为以下几类：",[1088,1089,1090,1107,1117],"ol",{},[1091,1092,1093,1095,1096,859,1098,859,1100,859,1102,859,1104,1106],"li",{},[25,1094,97],{}," 实际上就是一个实例，包括：",[25,1097,115],{},[25,1099,226],{},[25,1101,230],{},[25,1103,286],{},[25,1105,324],{},"（早期）",[1091,1108,1109,1111,1112,859,1114,1116],{},[25,1110,97],{}," 的某些方面像是一个实例，包括 ",[25,1113,642],{},[25,1115,638],{},"（ES3）",[1091,1118,1119,1121,1122,859,1124,1126,1127,1129],{},[25,1120,97],{}," 完全不是实例，包括：",[25,1123,528],{},[25,1125,541],{},"（早期）、",[25,1128,858],{}," 等所有 ES2015 及之后的类型",[14,1131,1132],{},"那么问题来了？为何会这样？",[91,1134,1136],{"id":1135},"reason","原因",[14,1138,1139,1140,1142,1143,639,1145,1147],{},"在 ES2015 之前，所有的内置类型实际上都是第一类，也就是它们的 ",[25,1141,97],{}," 均表现为自身的实例；也就是说 ",[25,1144,541],{},[25,1146,642],{}," 在那时与现在不同。这样处理的原因目前不得而知，对于 JS 来说好像也没什么不正常的。",[14,1149,1150,1151,1156,1157,1160,1161,1163],{},"然而在 ES2015 讨论过程中，TC39 决定对 ES2015 新引入的类型",[619,1152,1155],{"href":1153,"rel":1154},"https:\u002F\u002Fesdiscuss.org\u002Ftopic\u002Fmust-built-in-prototypes-also-be-valid-instances-was-why-dataview-prototype-object-s-class-is-object",[623],"取消这个行为","。从某种角度似乎也能理解，比如 ",[25,1158,1159],{},"TypedArray"," 如果具有像 ",[25,1162,324],{}," 一样的全局行为似乎很难接受。",[14,1165,1166,1167,1169,1170,639,1172,217],{},"既然如此，那么我们是不是可以对历史的类型也取消这一行为呢？TC39 是这样想的，于是也这么做了，但在实施的时候发现了本文最开始这种写法，以及早期 underscore 也使用了 ",[25,1168,347],{}," 的表现，因此彼时并未修改 ",[25,1171,115],{},[25,1173,324],{},[14,1175,1176,1177,1182,1183,1186,1187,1190,1191,1194],{},"对前端新特性感兴趣的同学应该听说过 ",[619,1178,1181],{"href":1179,"rel":1180},"https:\u002F\u002Fdeveloper.chrome.com\u002Fblog\u002Fsmooshgate\u002F",[623],"“Smoosh 门”","，是当初 ",[25,1184,1185],{},"Array.prototype.flat"," 还叫做 ",[25,1188,1189],{},"Array.prototype.flatten"," 的时候被发现与 Mootools 不兼容，因此最后改名了。实际上像 Mootools 这种修改原型的库总是引发向前不兼容的罪魁祸首，在 ES2015 发布后就发现其依赖了 ",[25,1192,1193],{},"Number.prototype"," 的行为。为了保险起见，TC39 在 ES2016 中又回滚所有早期类型的改动。这就有了我们看到的第一类类型。",[14,1196,1197,1198,1200,1201,639,1203,1205,1206,1208,1209,1211],{},"同时，有些网站还使用了 ",[25,1199,743],{}," 导致不兼容。不过这个问题 TC39 选择了一个折衷方案：既然 ",[25,1202,642],{},[25,1204,638],{}," 本来就有特殊的 ",[25,1207,803],{}," 逻辑，那就让它们适配 ",[25,1210,97],{}," 就好了。这也就是我们看到的第二类类型。",[1213,1214,1215],"style",{},"html pre.shiki code .spNyl, html code.shiki .spNyl{--shiki-light:#9C3EDA;--shiki-default:#C792EA;--shiki-dark:#C792EA}html pre.shiki code .sTEyZ, html code.shiki .sTEyZ{--shiki-light:#90A4AE;--shiki-default:#EEFFFF;--shiki-dark:#BABED8}html pre.shiki code .sMK4o, html code.shiki .sMK4o{--shiki-light:#39ADB5;--shiki-default:#89DDFF;--shiki-dark:#89DDFF}html pre.shiki code .sBMFI, html code.shiki .sBMFI{--shiki-light:#E2931D;--shiki-default:#FFCB6B;--shiki-dark:#FFCB6B}html pre.shiki code .s2Zo4, html code.shiki .s2Zo4{--shiki-light:#6182B8;--shiki-default:#82AAFF;--shiki-dark:#82AAFF}html .light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}html.light .shiki span {color: var(--shiki-light);background: var(--shiki-light-bg);font-style: var(--shiki-light-font-style);font-weight: var(--shiki-light-font-weight);text-decoration: var(--shiki-light-text-decoration);}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 .sHwdD, html code.shiki .sHwdD{--shiki-light:#90A4AE;--shiki-light-font-style:italic;--shiki-default:#546E7A;--shiki-default-font-style:italic;--shiki-dark:#676E95;--shiki-dark-font-style:italic}html pre.shiki code .sbssI, html code.shiki .sbssI{--shiki-light:#F76D47;--shiki-default:#F78C6C;--shiki-dark:#F78C6C}html pre.shiki code .s7zQu, html code.shiki .s7zQu{--shiki-light:#39ADB5;--shiki-light-font-style:italic;--shiki-default:#89DDFF;--shiki-default-font-style:italic;--shiki-dark:#89DDFF;--shiki-dark-font-style:italic}html pre.shiki code .sfazB, html code.shiki .sfazB{--shiki-light:#91B859;--shiki-default:#C3E88D;--shiki-dark:#C3E88D}",{"title":23,"searchDepth":68,"depth":68,"links":1217},[1218,1220,1222,1223],{"id":93,"depth":68,"text":1219},"基本类型的 prototype",{"id":305,"depth":68,"text":1221},"非基本类型的 prototype",{"id":631,"depth":68,"text":632},{"id":1135,"depth":68,"text":1136},"2022-08-19","md",{},"\u002Fposts\u002Fdifferent-prototypes",{"title":5,"description":16},"posts\u002F2022\u002Fdifferent-prototypes","B3ZJ6KvyeapZOfGbdlthwWNkZKoFs_7I_rp3iEuHzTc",[1232,1236],{"title":1233,"path":1234,"stem":1235,"children":-1},"不要使用 DOM 的 onxxx 属性的第一万个理由","\u002Fposts\u002Fdo-not-use-dom-onxxx","posts\u002F2022\u002Fdo-not-use-dom-onxxx",{"title":1237,"path":1238,"stem":1239,"children":-1},"为了保护隐私，Web 标准牺牲了什么？","\u002Fposts\u002Fweb-features-and-privacy","posts\u002F2023\u002Fweb-features-and-privacy",1792500630763]