[{"data":1,"prerenderedAt":1322},["ShallowReactive",2],{"blog-\u002Fblog\u002Fjavascript-prototypes-prototype-chain-explained":3},{"id":4,"title":5,"body":6,"description":1307,"difficulty":1308,"extension":1309,"framework":1310,"frameworkSlug":1311,"meta":1312,"navigation":169,"order":130,"path":1313,"qaPath":1314,"seo":1315,"stem":1316,"subtopic":1317,"topic":1318,"topicSlug":1319,"updated":1320,"__hash__":1321},"blog\u002Fblog\u002Fjavascript-prototypes-prototype-chain-explained.md","JavaScript Prototypes & the Prototype Chain Explained — A Visual Guide",{"type":7,"value":8,"toc":1293},"minimark",[9,14,41,48,52,59,93,198,220,230,233,272,399,420,424,433,539,563,567,576,666,676,722,726,733,812,825,829,848,970,979,983,986,1043,1060,1080,1084,1091,1190,1210,1214,1225,1229,1283,1289],[10,11,13],"h2",{"id":12},"the-idea-behind-prototypes","The idea behind prototypes",[15,16,17,18,22,23,27,28,31,32,36,37,40],"p",{},"JavaScript doesn't have classes in the way C++ or Java do — even the ",[19,20,21],"code",{},"class"," keyword is\nsyntactic sugar over a much simpler, more flexible mechanism: ",[24,25,26],"strong",{},"prototypes",". Every object\nhas a hidden internal link to another object, called its ",[24,29,30],{},"prototype",". When you try to\nread a property that an object doesn't have, the engine doesn't give up — it follows that\nlink to the prototype and looks there, then to ",[33,34,35],"em",{},"that"," object's prototype, and so on. This\nseries of links is the ",[24,38,39],{},"prototype chain",", and it is the single mechanism behind\ninheritance, shared methods, and a lot of \"magic\" in the language.",[15,42,43,44,47],{},"Once you internalize property lookup as \"walk up the chain until found or you hit ",[19,45,46],{},"null",",\"\nhuge swathes of JavaScript stop being mysterious.",[10,49,51],{"id":50},"property-lookup-walks-the-chain","Property lookup walks the chain",[15,53,54,55,58],{},"When you access ",[19,56,57],{},"obj.foo",", the engine performs these steps:",[60,61,62,74,80,83],"ol",{},[63,64,65,66,69,70,73],"li",{},"Does ",[19,67,68],{},"obj"," have an own property ",[19,71,72],{},"foo","? If yes, return it.",[63,75,76,77,79],{},"If not, go to ",[19,78,68],{},"'s prototype and check there.",[63,81,82],{},"Repeat up the chain.",[63,84,85,86,88,89,92],{},"If you reach the end (",[19,87,46],{},") without finding it, the result is ",[19,90,91],{},"undefined",".",[94,95,100],"pre",{"className":96,"code":97,"language":98,"meta":99,"style":99},"language-js shiki shiki-themes github-light github-dark","const animal = { eats: true }\nconst rabbit = Object.create(animal)   \u002F\u002F rabbit's prototype IS animal\nrabbit.jumps = true\n\nrabbit.jumps   \u002F\u002F true  — own property\nrabbit.eats    \u002F\u002F true  — found on animal via the chain\nrabbit.flies   \u002F\u002F undefined — not found anywhere\n","js","",[19,101,102,128,152,164,171,180,189],{"__ignoreMap":99},[103,104,107,111,115,118,122,125],"span",{"class":105,"line":106},"line",1,[103,108,110],{"class":109},"szBVR","const",[103,112,114],{"class":113},"sj4cs"," animal",[103,116,117],{"class":109}," =",[103,119,121],{"class":120},"sVt8B"," { eats: ",[103,123,124],{"class":113},"true",[103,126,127],{"class":120}," }\n",[103,129,131,133,136,138,141,145,148],{"class":105,"line":130},2,[103,132,110],{"class":109},[103,134,135],{"class":113}," rabbit",[103,137,117],{"class":109},[103,139,140],{"class":120}," Object.",[103,142,144],{"class":143},"sScJk","create",[103,146,147],{"class":120},"(animal)   ",[103,149,151],{"class":150},"sJ8bj","\u002F\u002F rabbit's prototype IS animal\n",[103,153,155,158,161],{"class":105,"line":154},3,[103,156,157],{"class":120},"rabbit.jumps ",[103,159,160],{"class":109},"=",[103,162,163],{"class":113}," true\n",[103,165,167],{"class":105,"line":166},4,[103,168,170],{"emptyLinePlaceholder":169},true,"\n",[103,172,174,177],{"class":105,"line":173},5,[103,175,176],{"class":120},"rabbit.jumps   ",[103,178,179],{"class":150},"\u002F\u002F true  — own property\n",[103,181,183,186],{"class":105,"line":182},6,[103,184,185],{"class":120},"rabbit.eats    ",[103,187,188],{"class":150},"\u002F\u002F true  — found on animal via the chain\n",[103,190,192,195],{"class":105,"line":191},7,[103,193,194],{"class":120},"rabbit.flies   ",[103,196,197],{"class":150},"\u002F\u002F undefined — not found anywhere\n",[15,199,200,203,204,207,208,211,212,215,216,219],{},[19,201,202],{},"rabbit"," itself has only ",[19,205,206],{},"jumps",", but reading ",[19,209,210],{},"rabbit.eats"," succeeds because the lookup\nclimbs to ",[19,213,214],{},"animal",". This is ",[33,217,218],{},"delegation",": objects delegate to their prototypes for anything\nthey don't have themselves.",[10,221,223,226,227,229],{"id":222},"__proto__-vs-prototype-the-confusing-pair",[19,224,225],{},"__proto__"," vs ",[19,228,30],{}," — the confusing pair",[15,231,232],{},"These two names trip up nearly everyone, because they sound the same but mean different\nthings.",[234,235,236,255],"ul",{},[63,237,238,242,243,246,247,250,251,254],{},[24,239,240],{},[19,241,225],{}," (or properly, ",[19,244,245],{},"Object.getPrototypeOf(obj)",") is the ",[24,248,249],{},"actual prototype\nlink"," that ",[33,252,253],{},"every"," object has — it points to the object it delegates to.",[63,256,257,261,262,265,266,268,269,92],{},[24,258,259],{},[19,260,30],{}," is a property that exists ",[24,263,264],{},"only on functions",". It's the object that\nwill become the ",[19,267,225],{}," of instances created with ",[19,270,271],{},"new",[94,273,275],{"className":96,"code":274,"language":98,"meta":99,"style":99},"function Dog(name) { this.name = name }\nDog.prototype.bark = function () { return 'woof' }\n\nconst d = new Dog('Rex')\nObject.getPrototypeOf(d) === Dog.prototype   \u002F\u002F true\nd.bark()                                      \u002F\u002F 'woof' — found on Dog.prototype\n",[19,276,277,306,337,341,363,386],{"__ignoreMap":99},[103,278,279,282,285,288,292,295,298,301,303],{"class":105,"line":106},[103,280,281],{"class":109},"function",[103,283,284],{"class":143}," Dog",[103,286,287],{"class":120},"(",[103,289,291],{"class":290},"s4XuR","name",[103,293,294],{"class":120},") { ",[103,296,297],{"class":113},"this",[103,299,300],{"class":120},".name ",[103,302,160],{"class":109},[103,304,305],{"class":120}," name }\n",[103,307,308,311,313,315,317,320,322,325,328,331,335],{"class":105,"line":130},[103,309,310],{"class":113},"Dog",[103,312,92],{"class":120},[103,314,30],{"class":113},[103,316,92],{"class":120},[103,318,319],{"class":143},"bark",[103,321,117],{"class":109},[103,323,324],{"class":109}," function",[103,326,327],{"class":120}," () { ",[103,329,330],{"class":109},"return",[103,332,334],{"class":333},"sZZnC"," 'woof'",[103,336,127],{"class":120},[103,338,339],{"class":105,"line":154},[103,340,170],{"emptyLinePlaceholder":169},[103,342,343,345,348,350,353,355,357,360],{"class":105,"line":166},[103,344,110],{"class":109},[103,346,347],{"class":113}," d",[103,349,117],{"class":109},[103,351,352],{"class":109}," new",[103,354,284],{"class":143},[103,356,287],{"class":120},[103,358,359],{"class":333},"'Rex'",[103,361,362],{"class":120},")\n",[103,364,365,368,371,374,377,379,381,383],{"class":105,"line":173},[103,366,367],{"class":120},"Object.",[103,369,370],{"class":143},"getPrototypeOf",[103,372,373],{"class":120},"(d) ",[103,375,376],{"class":109},"===",[103,378,284],{"class":113},[103,380,92],{"class":120},[103,382,30],{"class":113},[103,384,385],{"class":150},"   \u002F\u002F true\n",[103,387,388,391,393,396],{"class":105,"line":182},[103,389,390],{"class":120},"d.",[103,392,319],{"class":143},[103,394,395],{"class":120},"()                                      ",[103,397,398],{"class":150},"\u002F\u002F 'woof' — found on Dog.prototype\n",[15,400,401,402,405,406,409,410,412,413,415,416,419],{},"So ",[19,403,404],{},"Dog.prototype"," is a ",[33,407,408],{},"setup"," object (where you put shared methods), and each instance's\n",[19,411,225],{}," points back to it. The function's own ",[19,414,225],{},", by the way, is\n",[19,417,418],{},"Function.prototype"," — functions are objects too.",[10,421,423],{"id":422},"reading-the-chain-to-the-top","Reading the chain to the top",[15,425,426,427,430,431,92],{},"Follow any normal object's chain upward and you eventually reach ",[19,428,429],{},"Object.prototype",", then\n",[19,432,46],{},[94,434,436],{"className":96,"code":435,"language":98,"meta":99,"style":99},"const arr = [1, 2, 3]\nObject.getPrototypeOf(arr) === Array.prototype           \u002F\u002F true\nObject.getPrototypeOf(Array.prototype) === Object.prototype \u002F\u002F true\nObject.getPrototypeOf(Object.prototype)                  \u002F\u002F null \u003C- the top\n",[19,437,438,467,488,518],{"__ignoreMap":99},[103,439,440,442,445,447,450,453,456,459,461,464],{"class":105,"line":106},[103,441,110],{"class":109},[103,443,444],{"class":113}," arr",[103,446,117],{"class":109},[103,448,449],{"class":120}," [",[103,451,452],{"class":113},"1",[103,454,455],{"class":120},", ",[103,457,458],{"class":113},"2",[103,460,455],{"class":120},[103,462,463],{"class":113},"3",[103,465,466],{"class":120},"]\n",[103,468,469,471,473,476,478,481,483,485],{"class":105,"line":130},[103,470,367],{"class":120},[103,472,370],{"class":143},[103,474,475],{"class":120},"(arr) ",[103,477,376],{"class":109},[103,479,480],{"class":113}," Array",[103,482,92],{"class":120},[103,484,30],{"class":113},[103,486,487],{"class":150},"           \u002F\u002F true\n",[103,489,490,492,494,496,499,501,503,506,508,511,513,515],{"class":105,"line":154},[103,491,367],{"class":120},[103,493,370],{"class":143},[103,495,287],{"class":120},[103,497,498],{"class":113},"Array",[103,500,92],{"class":120},[103,502,30],{"class":113},[103,504,505],{"class":120},") ",[103,507,376],{"class":109},[103,509,510],{"class":113}," Object",[103,512,92],{"class":120},[103,514,30],{"class":113},[103,516,517],{"class":150}," \u002F\u002F true\n",[103,519,520,522,524,526,529,531,533,536],{"class":105,"line":166},[103,521,367],{"class":120},[103,523,370],{"class":143},[103,525,287],{"class":120},[103,527,528],{"class":113},"Object",[103,530,92],{"class":120},[103,532,30],{"class":113},[103,534,535],{"class":120},")                  ",[103,537,538],{"class":150},"\u002F\u002F null \u003C- the top\n",[15,540,541,542,545,546,505,549,552,553,556,557,559,560,92],{},"This is why every array has methods like ",[19,543,544],{},"map"," (from ",[19,547,548],{},"Array.prototype",[33,550,551],{},"and"," ",[19,554,555],{},"toString","\n(from ",[19,558,429],{},"): they live on prototypes the array delegates to. The chain for a\nplain array literal is: ",[19,561,562],{},"arr -> Array.prototype -> Object.prototype -> null",[10,564,566],{"id":565},"creating-objects-with-a-specific-prototype","Creating objects with a specific prototype",[15,568,569,572,573,575],{},[19,570,571],{},"Object.create(proto)"," is the most explicit way to set up a prototype link. It builds a new\nobject whose ",[19,574,225],{}," is exactly the argument you pass.",[94,577,579],{"className":96,"code":578,"language":98,"meta":99,"style":99},"const base = {\n  describe() { return `I am ${this.name}` }\n}\n\nconst item = Object.create(base)\nitem.name = 'Widget'\nitem.describe()   \u002F\u002F 'I am Widget' — method borrowed from base\n",[19,580,581,593,617,622,626,642,652],{"__ignoreMap":99},[103,582,583,585,588,590],{"class":105,"line":106},[103,584,110],{"class":109},[103,586,587],{"class":113}," base",[103,589,117],{"class":109},[103,591,592],{"class":120}," {\n",[103,594,595,598,601,603,606,608,610,612,615],{"class":105,"line":130},[103,596,597],{"class":143},"  describe",[103,599,600],{"class":120},"() { ",[103,602,330],{"class":109},[103,604,605],{"class":333}," `I am ${",[103,607,297],{"class":113},[103,609,92],{"class":333},[103,611,291],{"class":120},[103,613,614],{"class":333},"}`",[103,616,127],{"class":120},[103,618,619],{"class":105,"line":154},[103,620,621],{"class":120},"}\n",[103,623,624],{"class":105,"line":166},[103,625,170],{"emptyLinePlaceholder":169},[103,627,628,630,633,635,637,639],{"class":105,"line":173},[103,629,110],{"class":109},[103,631,632],{"class":113}," item",[103,634,117],{"class":109},[103,636,140],{"class":120},[103,638,144],{"class":143},[103,640,641],{"class":120},"(base)\n",[103,643,644,647,649],{"class":105,"line":182},[103,645,646],{"class":120},"item.name ",[103,648,160],{"class":109},[103,650,651],{"class":333}," 'Widget'\n",[103,653,654,657,660,663],{"class":105,"line":191},[103,655,656],{"class":120},"item.",[103,658,659],{"class":143},"describe",[103,661,662],{"class":120},"()   ",[103,664,665],{"class":150},"\u002F\u002F 'I am Widget' — method borrowed from base\n",[15,667,668,669,672,673,675],{},"You can also create an object with ",[24,670,671],{},"no prototype"," by passing ",[19,674,46],{},", which is useful for\ndictionaries where inherited keys would be a hazard:",[94,677,679],{"className":96,"code":678,"language":98,"meta":99,"style":99},"const map = Object.create(null)\nmap.toString          \u002F\u002F undefined — no Object.prototype in its chain\n'toString' in map     \u002F\u002F false truly empty\n",[19,680,681,700,708],{"__ignoreMap":99},[103,682,683,685,688,690,692,694,696,698],{"class":105,"line":106},[103,684,110],{"class":109},[103,686,687],{"class":113}," map",[103,689,117],{"class":109},[103,691,140],{"class":120},[103,693,144],{"class":143},[103,695,287],{"class":120},[103,697,46],{"class":113},[103,699,362],{"class":120},[103,701,702,705],{"class":105,"line":130},[103,703,704],{"class":120},"map.toString          ",[103,706,707],{"class":150},"\u002F\u002F undefined — no Object.prototype in its chain\n",[103,709,710,713,716,719],{"class":105,"line":154},[103,711,712],{"class":333},"'toString'",[103,714,715],{"class":109}," in",[103,717,718],{"class":120}," map     ",[103,720,721],{"class":150},"\u002F\u002F false truly empty\n",[10,723,725],{"id":724},"shadowing-own-properties-win","Shadowing: own properties win",[15,727,728,729,732],{},"If an object has its ",[33,730,731],{},"own"," property with the same name as one further up the chain, the own\nproperty \"shadows\" the inherited one — lookup stops at the first match.",[94,734,736],{"className":96,"code":735,"language":98,"meta":99,"style":99},"const proto = { greet() { return 'hi from proto' } }\nconst obj = Object.create(proto)\nobj.greet = () => 'hi from obj'\n\nobj.greet()   \u002F\u002F 'hi from obj'  own property shadows the prototype's\n",[19,737,738,763,779,797,801],{"__ignoreMap":99},[103,739,740,742,745,747,750,753,755,757,760],{"class":105,"line":106},[103,741,110],{"class":109},[103,743,744],{"class":113}," proto",[103,746,117],{"class":109},[103,748,749],{"class":120}," { ",[103,751,752],{"class":143},"greet",[103,754,600],{"class":120},[103,756,330],{"class":109},[103,758,759],{"class":333}," 'hi from proto'",[103,761,762],{"class":120}," } }\n",[103,764,765,767,770,772,774,776],{"class":105,"line":130},[103,766,110],{"class":109},[103,768,769],{"class":113}," obj",[103,771,117],{"class":109},[103,773,140],{"class":120},[103,775,144],{"class":143},[103,777,778],{"class":120},"(proto)\n",[103,780,781,784,786,788,791,794],{"class":105,"line":154},[103,782,783],{"class":120},"obj.",[103,785,752],{"class":143},[103,787,117],{"class":109},[103,789,790],{"class":120}," () ",[103,792,793],{"class":109},"=>",[103,795,796],{"class":333}," 'hi from obj'\n",[103,798,799],{"class":105,"line":166},[103,800,170],{"emptyLinePlaceholder":169},[103,802,803,805,807,809],{"class":105,"line":173},[103,804,783],{"class":120},[103,806,752],{"class":143},[103,808,662],{"class":120},[103,810,811],{"class":150},"\u002F\u002F 'hi from obj'  own property shadows the prototype's\n",[15,813,814,815,818,819,821,822,824],{},"Importantly, assigning to ",[19,816,817],{},"obj.greet"," creates an ",[24,820,731],{}," property on ",[19,823,68],{}," — it never\nmutates the prototype. Writes always happen on the object itself (with one exception:\ninherited setters run). This write-local, read-up-the-chain asymmetry is key to how\ninheritance stays safe.",[10,826,828],{"id":827},"why-shared-methods-live-on-the-prototype","Why shared methods live on the prototype",[15,830,831,832,834,835,837,838,840,841,844,845,847],{},"Putting methods on the prototype rather than on each instance is a deliberate memory\noptimization. If every ",[19,833,310],{}," carried its own copy of ",[19,836,319],{},", a thousand dogs would mean a\nthousand identical functions. With the method on ",[19,839,404],{},", all instances ",[24,842,843],{},"share one\nfunction",", and ",[19,846,297],{}," resolves to whichever instance called it.",[94,849,851],{"className":96,"code":850,"language":98,"meta":99,"style":99},"function Dog(name) { this.name = name }   \u002F\u002F per-instance data\nDog.prototype.bark = function () {        \u002F\u002F shared behavior\n  return `${this.name} says woof`\n}\nconst a = new Dog('A'), b = new Dog('B')\na.bark === b.bark   \u002F\u002F true same function object, different `this`\n",[19,852,853,877,899,916,920,957],{"__ignoreMap":99},[103,854,855,857,859,861,863,865,867,869,871,874],{"class":105,"line":106},[103,856,281],{"class":109},[103,858,284],{"class":143},[103,860,287],{"class":120},[103,862,291],{"class":290},[103,864,294],{"class":120},[103,866,297],{"class":113},[103,868,300],{"class":120},[103,870,160],{"class":109},[103,872,873],{"class":120}," name }   ",[103,875,876],{"class":150},"\u002F\u002F per-instance data\n",[103,878,879,881,883,885,887,889,891,893,896],{"class":105,"line":130},[103,880,310],{"class":113},[103,882,92],{"class":120},[103,884,30],{"class":113},[103,886,92],{"class":120},[103,888,319],{"class":143},[103,890,117],{"class":109},[103,892,324],{"class":109},[103,894,895],{"class":120}," () {        ",[103,897,898],{"class":150},"\u002F\u002F shared behavior\n",[103,900,901,904,907,909,911,913],{"class":105,"line":154},[103,902,903],{"class":109},"  return",[103,905,906],{"class":333}," `${",[103,908,297],{"class":113},[103,910,92],{"class":333},[103,912,291],{"class":120},[103,914,915],{"class":333},"} says woof`\n",[103,917,918],{"class":105,"line":166},[103,919,621],{"class":120},[103,921,922,924,927,929,931,933,935,938,941,944,946,948,950,952,955],{"class":105,"line":173},[103,923,110],{"class":109},[103,925,926],{"class":113}," a",[103,928,117],{"class":109},[103,930,352],{"class":109},[103,932,284],{"class":143},[103,934,287],{"class":120},[103,936,937],{"class":333},"'A'",[103,939,940],{"class":120},"), ",[103,942,943],{"class":113},"b",[103,945,117],{"class":109},[103,947,352],{"class":109},[103,949,284],{"class":143},[103,951,287],{"class":120},[103,953,954],{"class":333},"'B'",[103,956,362],{"class":120},[103,958,959,962,964,967],{"class":105,"line":182},[103,960,961],{"class":120},"a.bark ",[103,963,376],{"class":109},[103,965,966],{"class":120}," b.bark   ",[103,968,969],{"class":150},"\u002F\u002F true same function object, different `this`\n",[15,971,972,973],{},"Rule of thumb: ",[24,974,975,976,978],{},"per-instance state goes on ",[19,977,297],{},"; shared behavior goes on the prototype.",[10,980,982],{"id":981},"inspecting-and-changing-the-chain","Inspecting and changing the chain",[15,984,985],{},"A few tools let you inspect and (rarely) modify prototypes:",[94,987,989],{"className":96,"code":988,"language":98,"meta":99,"style":99},"Object.getPrototypeOf(obj)            \u002F\u002F read the prototype preferred\nObject.setPrototypeOf(obj, newProto)  \u002F\u002F change it slow, avoid in hot paths\nobj.isPrototypeOf?.(other)            \u002F\u002F is obj in other's chain?\nchild instanceof Parent               \u002F\u002F is Parent.prototype in child's chain?\n",[19,990,991,1003,1016,1029],{"__ignoreMap":99},[103,992,993,995,997,1000],{"class":105,"line":106},[103,994,367],{"class":120},[103,996,370],{"class":143},[103,998,999],{"class":120},"(obj)            ",[103,1001,1002],{"class":150},"\u002F\u002F read the prototype preferred\n",[103,1004,1005,1007,1010,1013],{"class":105,"line":130},[103,1006,367],{"class":120},[103,1008,1009],{"class":143},"setPrototypeOf",[103,1011,1012],{"class":120},"(obj, newProto)  ",[103,1014,1015],{"class":150},"\u002F\u002F change it slow, avoid in hot paths\n",[103,1017,1018,1020,1023,1026],{"class":105,"line":154},[103,1019,783],{"class":120},[103,1021,1022],{"class":143},"isPrototypeOf",[103,1024,1025],{"class":120},"?.(other)            ",[103,1027,1028],{"class":150},"\u002F\u002F is obj in other's chain?\n",[103,1030,1031,1034,1037,1040],{"class":105,"line":166},[103,1032,1033],{"class":120},"child ",[103,1035,1036],{"class":109},"instanceof",[103,1038,1039],{"class":143}," Parent",[103,1041,1042],{"class":150},"               \u002F\u002F is Parent.prototype in child's chain?\n",[15,1044,1045,1047,1048,1051,1052,1055,1056,1059],{},[19,1046,1036],{}," is really a prototype-chain check in disguise: ",[19,1049,1050],{},"x instanceof C"," asks \"is\n",[19,1053,1054],{},"C.prototype"," somewhere in ",[19,1057,1058],{},"x","'s chain?\" That's why it works across inheritance levels.",[15,1061,1062,1072,1073,1076,1077,1079],{},[24,1063,1064,1065,1068,1069,1071],{},"Avoid ",[19,1066,1067],{},"Object.setPrototypeOf"," and ",[19,1070,225],{}," assignment at runtime."," Changing an\nobject's prototype after creation forces engines to throw away optimizations, making\nsubsequent access dramatically slower. Set the prototype at creation time with\n",[19,1074,1075],{},"Object.create"," or ",[19,1078,271],{}," instead.",[10,1081,1083],{"id":1082},"hasownproperty-vs-the-chain","hasOwnProperty vs the chain",[15,1085,1086,1087,1090],{},"Because lookups climb the chain, you often need to distinguish own properties from inherited\nones — especially in ",[19,1088,1089],{},"for...in"," loops, which iterate inherited enumerable keys too.",[94,1092,1094],{"className":96,"code":1093,"language":98,"meta":99,"style":99},"const proto = { inherited: 1 }\nconst obj = Object.create(proto)\nobj.own = 2\n\nfor (const key in obj) {\n  console.log(key, Object.hasOwn(obj, key))\n  \u002F\u002F 'own' true\n  \u002F\u002F 'inherited' false  \u003C- came from the prototype\n}\n",[19,1095,1096,1111,1125,1135,1139,1157,1174,1179,1185],{"__ignoreMap":99},[103,1097,1098,1100,1102,1104,1107,1109],{"class":105,"line":106},[103,1099,110],{"class":109},[103,1101,744],{"class":113},[103,1103,117],{"class":109},[103,1105,1106],{"class":120}," { inherited: ",[103,1108,452],{"class":113},[103,1110,127],{"class":120},[103,1112,1113,1115,1117,1119,1121,1123],{"class":105,"line":130},[103,1114,110],{"class":109},[103,1116,769],{"class":113},[103,1118,117],{"class":109},[103,1120,140],{"class":120},[103,1122,144],{"class":143},[103,1124,778],{"class":120},[103,1126,1127,1130,1132],{"class":105,"line":154},[103,1128,1129],{"class":120},"obj.own ",[103,1131,160],{"class":109},[103,1133,1134],{"class":113}," 2\n",[103,1136,1137],{"class":105,"line":166},[103,1138,170],{"emptyLinePlaceholder":169},[103,1140,1141,1144,1147,1149,1152,1154],{"class":105,"line":173},[103,1142,1143],{"class":109},"for",[103,1145,1146],{"class":120}," (",[103,1148,110],{"class":109},[103,1150,1151],{"class":113}," key",[103,1153,715],{"class":109},[103,1155,1156],{"class":120}," obj) {\n",[103,1158,1159,1162,1165,1168,1171],{"class":105,"line":182},[103,1160,1161],{"class":120},"  console.",[103,1163,1164],{"class":143},"log",[103,1166,1167],{"class":120},"(key, Object.",[103,1169,1170],{"class":143},"hasOwn",[103,1172,1173],{"class":120},"(obj, key))\n",[103,1175,1176],{"class":105,"line":191},[103,1177,1178],{"class":150},"  \u002F\u002F 'own' true\n",[103,1180,1182],{"class":105,"line":1181},8,[103,1183,1184],{"class":150},"  \u002F\u002F 'inherited' false  \u003C- came from the prototype\n",[103,1186,1188],{"class":105,"line":1187},9,[103,1189,621],{"class":120},[15,1191,1192,1195,1196,1199,1200,1202,1203,1205,1206,1209],{},[19,1193,1194],{},"Object.hasOwn(obj, key)"," (the modern, safe form of ",[19,1197,1198],{},"hasOwnProperty",") returns ",[19,1201,124],{}," only\nfor own properties. Use it to filter ",[19,1204,1089],{},", or just prefer ",[19,1207,1208],{},"Object.keys",", which never\nincludes inherited keys.",[10,1211,1213],{"id":1212},"performance-and-depth","Performance and depth",[15,1215,1216,1217,1220,1221,1224],{},"Lookups are fast, but a very deep chain means more hops for a missed property. In practice,\nchains are shallow (two or three levels), so this rarely matters. What ",[33,1218,1219],{},"does"," matter is\nkeeping the chain ",[24,1222,1223],{},"stable"," — mutating prototypes at runtime, as noted, is the real\nperformance trap. Engines optimize objects with predictable shapes and chains; surprise them\nand you pay for it.",[10,1226,1228],{"id":1227},"key-takeaways","Key takeaways",[234,1230,1231,1240,1256,1265,1272,1278],{},[63,1232,1233,1234,1237,1238,92],{},"Every object has a hidden prototype link; missing-property lookups walk this ",[24,1235,1236],{},"chain","\nuntil found or ",[19,1239,46],{},[63,1241,1242,1244,1245,1248,1249,1251,1252,1255],{},[19,1243,225],{}," (read via ",[19,1246,1247],{},"Object.getPrototypeOf",") is the actual link on every object;\n",[19,1250,30],{}," is a property on ",[24,1253,1254],{},"functions"," that becomes instances' link.",[63,1257,1258,1260,1261,1264],{},[19,1259,571],{}," sets the chain explicitly; ",[19,1262,1263],{},"Object.create(null)"," makes a\nprototype-less object.",[63,1266,1267,1268,1271],{},"Own properties ",[24,1269,1270],{},"shadow"," inherited ones, and writes always land on the object itself.",[63,1273,1274,1275,1277],{},"Shared methods go on the prototype so all instances reuse one function while ",[19,1276,297],{}," varies.",[63,1279,1280,1282],{},[19,1281,1036],{}," is a prototype-chain test; never reassign prototypes at runtime in hot code.",[15,1284,1285,1286,1288],{},"The prototype chain is the foundation everything else — constructors, ",[19,1287,21],{},", inheritance —\nis built on. Get this model crisp and the rest of the object system follows naturally.",[1290,1291,1292],"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 pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}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 .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}",{"title":99,"searchDepth":130,"depth":130,"links":1294},[1295,1296,1297,1299,1300,1301,1302,1303,1304,1305,1306],{"id":12,"depth":130,"text":13},{"id":50,"depth":130,"text":51},{"id":222,"depth":130,"text":1298},"__proto__ vs prototype — the confusing pair",{"id":422,"depth":130,"text":423},{"id":565,"depth":130,"text":566},{"id":724,"depth":130,"text":725},{"id":827,"depth":130,"text":828},{"id":981,"depth":130,"text":982},{"id":1082,"depth":130,"text":1083},{"id":1212,"depth":130,"text":1213},{"id":1227,"depth":130,"text":1228},"Understand JavaScript prototypes and the prototype chain — how property lookup works, __proto__ vs prototype, Object.create, and why this model underpins inheritance in JS.","medium","md","JavaScript","javascript",{},"\u002Fblog\u002Fjavascript-prototypes-prototype-chain-explained","\u002Fjavascript\u002Fobjects\u002Fprototypes-chain",{"title":5,"description":1307},"blog\u002Fjavascript-prototypes-prototype-chain-explained","Prototypes & the Prototype Chain","Objects & Prototypes","objects","2026-06-18","0is5APR-enJPR2TCtVvzx6Zqfch3qgcbvrA0Ru2ma30",1781808673080]