[{"data":1,"prerenderedAt":496},["ShallowReactive",2],{"article-frontend\u002Fjavascript":3},{"_path":4,"_dir":5,"_draft":6,"_partial":6,"_locale":7,"title":8,"description":9,"date":10,"tags":11,"body":13,"_type":490,"_id":491,"_source":492,"_file":493,"_stem":494,"_extension":495},"\u002Farticles\u002Ffrontend\u002Fjavascript","frontend",false,"","JavaScript 原型与原型链详解","深入理解 JavaScript 原型机制，从构造函数、prototype、__proto__ 到完整原型链的工作原理","2023-03-23",[12],"软件工程",{"type":14,"children":15,"toc":474},"root",[16,24,30,36,41,46,53,58,69,79,87,93,103,140,146,151,159,168,177,185,201,209,214,243,253,273,294,303,343,355,363,368,373,379,389,442,455,461,466],{"type":17,"tag":18,"props":19,"children":21},"element","h1",{"id":20},"原型与原型链",[22],{"type":23,"value":20},"text",{"type":17,"tag":25,"props":26,"children":28},"h2",{"id":27},"前言",[29],{"type":23,"value":27},{"type":17,"tag":31,"props":32,"children":33},"p",{},[34],{"type":23,"value":35},"原型与原型链，作为JavaScript中很关键的知识点之一，它的重要性是可想而知的，如果原型与原型链没有搞明白，会很影响你接下来的很多学习，例如js继承机制、TypeScript、vue框架等，所以原型与原型链是很重要的基础，也是每一名前端工程师必须研究透的",{"type":17,"tag":25,"props":37,"children":39},{"id":38},"构造函数",[40],{"type":23,"value":38},{"type":17,"tag":31,"props":42,"children":43},{},[44],{"type":23,"value":45},"讲到原型，就一定要先对构造函数有一定的基础",{"type":17,"tag":47,"props":48,"children":50},"h3",{"id":49},"构造函数中有静态成员实例成员原型属性一般是称为方法",[51],{"type":23,"value":52},"构造函数中有静态成员、实例成员、原型属性(一般是称为方法)",{"type":17,"tag":31,"props":54,"children":55},{},[56],{"type":23,"value":57},"静态成员：在构造函数本身创建的属性，只能通过构造函数访问。",{"type":17,"tag":31,"props":59,"children":60},{},[61,67],{"type":17,"tag":62,"props":63,"children":66},"img",{"alt":64,"src":65},"构造函数-静态成员.png","https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fcd1beb4fc50e4862921a10cc59f4b356~tplv-k3u1fbpfcp-watermark.image?",[],{"type":23,"value":68},"\n实例成员：在构造函数本身，通过this添加的成员，只能通过实例化对象访问。",{"type":17,"tag":31,"props":70,"children":71},{},[72,77],{"type":17,"tag":62,"props":73,"children":76},{"alt":74,"src":75},"构造函数-实例成员.png","https:\u002F\u002Fp3-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fbd9259cc09db4d00a5458a869828874b~tplv-k3u1fbpfcp-watermark.image?",[],{"type":23,"value":78},"\n原型属性：在构造函数的原型对象上创建的属性(方法)。",{"type":17,"tag":31,"props":80,"children":81},{},[82],{"type":17,"tag":62,"props":83,"children":86},{"alt":84,"src":85},"构造函数-原型属性.png","https:\u002F\u002Fp3-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F383203f9b61542c7a9988abb280afbb0~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":47,"props":88,"children":90},{"id":89},"可能这么看不够直观看图",[91],{"type":23,"value":92},"可能这么看不够直观，看图",{"type":17,"tag":31,"props":94,"children":95},{},[96,101],{"type":17,"tag":62,"props":97,"children":100},{"alt":98,"src":99},"构造函数.png","https:\u002F\u002Fp9-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002F4a02290d9fe5486ca6af9b34387b9f71~tplv-k3u1fbpfcp-watermark.image?",[],{"type":23,"value":102},"\n首先我们要知道，全局变量、局部变量、函数名都是储存在栈中的，而对象实体是储存在堆中的。",{"type":17,"tag":104,"props":105,"children":106},"ol",{},[107,122,127],{"type":17,"tag":108,"props":109,"children":110},"li",{},[111,113,120],{"type":23,"value":112},"栈中的Person构造函数通过地址值0x123找到了堆中的Person构造函数对象，堆中的Person构造函数存放着实例成员(this.name,this.age,this.sayName)、静态成员(Person.uname)以及",{"type":17,"tag":114,"props":115,"children":117},"code",{"className":116},[],[118],{"type":23,"value":119},"prototype",{"type":23,"value":121},"(后面详细说)等属性",{"type":17,"tag":108,"props":123,"children":124},{},[125],{"type":23,"value":126},"prototype通过储存的地址值找到Person原型对象，这里存储着原型属性(sing函数)以及constructor等属性。",{"type":17,"tag":108,"props":128,"children":129},{},[130,132,138],{"type":23,"value":131},"我们通过new实例化了构造函数Person，在内存堆中创建了person1实例对象，栈中person1通过地址值0x345找到堆中的person1实例对象，在new构造函数Person的时候发生这么一件事，就是构造函数内部的this被赋值为person1这个实例对象，同时构造函数中的实例成员全被添加到实例对象中，所以现在实例化对象中存有实例成员(this.name,this.age,this.sayName)以及",{"type":17,"tag":114,"props":133,"children":135},{"className":134},[],[136],{"type":23,"value":137},"__proto__",{"type":23,"value":139},"(后面详细说)等属性。",{"type":17,"tag":47,"props":141,"children":143},{"id":142},"new-构造函数后发生了什么",[144],{"type":23,"value":145},"new 构造函数后发生了什么",{"type":17,"tag":31,"props":147,"children":148},{},[149],{"type":23,"value":150},"这块可以先放一放，不影响理解原型与原型链，但是理解了会有一种通透的感觉",{"type":17,"tag":104,"props":152,"children":153},{},[154],{"type":17,"tag":108,"props":155,"children":156},{},[157],{"type":23,"value":158},"创建一个新对象(实例对象)",{"type":17,"tag":160,"props":161,"children":163},"pre",{"code":162},"    const person1 = new Object()\n",[164],{"type":17,"tag":114,"props":165,"children":166},{"__ignoreMap":7},[167],{"type":23,"value":162},{"type":17,"tag":104,"props":169,"children":171},{"start":170},4,[172],{"type":17,"tag":108,"props":173,"children":174},{},[175],{"type":23,"value":176},"将this指向实例对象，并将构造函数中用this定义的属性复制到实例上(用call和apply都行)",{"type":17,"tag":160,"props":178,"children":180},{"code":179},"    Person.apply(person1, [....])\n",[181],{"type":17,"tag":114,"props":182,"children":183},{"__ignoreMap":7},[184],{"type":23,"value":179},{"type":17,"tag":104,"props":186,"children":188},{"start":187},3,[189],{"type":17,"tag":108,"props":190,"children":191},{},[192,194,199],{"type":23,"value":193},"将实例对象中的",{"type":17,"tag":114,"props":195,"children":197},{"className":196},[],[198],{"type":23,"value":137},{"type":23,"value":200},"属性指向Person的原型(原来指向的是Object的原型对象)",{"type":17,"tag":160,"props":202,"children":204},{"code":203},"    person1.__proto__ = Person.prototype\n",[205],{"type":17,"tag":114,"props":206,"children":207},{"__ignoreMap":7},[208],{"type":23,"value":203},{"type":17,"tag":25,"props":210,"children":212},{"id":211},"原型",[213],{"type":23,"value":211},{"type":17,"tag":215,"props":216,"children":218},"h5",{"id":217},"个人习惯prototype称为显式原型属性__proto__prototype称为隐式原型属性",[219,221,226,228,233,235,241],{"type":23,"value":220},"个人习惯：",{"type":17,"tag":114,"props":222,"children":224},{"className":223},[],[225],{"type":23,"value":119},{"type":23,"value":227},"称为显式原型属性、",{"type":17,"tag":114,"props":229,"children":231},{"className":230},[],[232],{"type":23,"value":137},{"type":23,"value":234},"(",{"type":17,"tag":114,"props":236,"children":238},{"className":237},[],[239],{"type":23,"value":240},"[[prototype]]",{"type":23,"value":242},")称为隐式原型属性。",{"type":17,"tag":215,"props":244,"children":245},{"id":119},[246,251],{"type":17,"tag":114,"props":247,"children":249},{"className":248},[],[250],{"type":23,"value":119},{"type":23,"value":252},":",{"type":17,"tag":31,"props":254,"children":255},{},[256,258,263,265,271],{"type":23,"value":257},"我们每创建一个函数，js引擎就会自动为了函数创建一个",{"type":17,"tag":114,"props":259,"children":261},{"className":260},[],[262],{"type":23,"value":119},{"type":23,"value":264},"属性，这个属性通过储存的地址值指向函数的原型对象(也是Object的实例对象)，而原型对象会自动获得一个",{"type":17,"tag":114,"props":266,"children":268},{"className":267},[],[269],{"type":23,"value":270},"constructor",{"type":23,"value":272},"属性，这个属性指回与之关联的构造函数。",{"type":17,"tag":31,"props":274,"children":275},{},[276,278,284,286,292],{"type":23,"value":277},"上面我们说函数的原型对象，也是Object的实例对象，在我们调用函数时(",{"type":17,"tag":114,"props":279,"children":281},{"className":280},[],[282],{"type":23,"value":283},"Fun()",{"type":23,"value":285},")，其实相当于执行了",{"type":17,"tag":114,"props":287,"children":289},{"className":288},[],[290],{"type":23,"value":291},"Fun.constructor = new Object()",{"type":23,"value":293},"这段代码",{"type":17,"tag":215,"props":295,"children":296},{"id":137},[297,302],{"type":17,"tag":114,"props":298,"children":300},{"className":299},[],[301],{"type":23,"value":137},{"type":23,"value":252},{"type":17,"tag":31,"props":304,"children":305},{},[306,308,313,315,320,322,327,329,334,336,341],{"type":23,"value":307},"注：现在谷歌浏览器显示这个属性为",{"type":17,"tag":114,"props":309,"children":311},{"className":310},[],[312],{"type":23,"value":240},{"type":23,"value":314},"，每次实例化构造函数，创建一个实例对象，其内部会有一个",{"type":17,"tag":114,"props":316,"children":318},{"className":317},[],[319],{"type":23,"value":137},{"type":23,"value":321},"属性，指向构造函数的原型对象，在内部的操作的是：实例化构造函数——>将构造函数中",{"type":17,"tag":114,"props":323,"children":325},{"className":324},[],[326],{"type":23,"value":119},{"type":23,"value":328},"储存的地址值拷贝一份赋值给实例对象",{"type":17,"tag":114,"props":330,"children":332},{"className":331},[],[333],{"type":23,"value":137},{"type":23,"value":335},"属性——>结果就是",{"type":17,"tag":114,"props":337,"children":339},{"className":338},[],[340],{"type":23,"value":137},{"type":23,"value":342},"属性指向原型对象",{"type":17,"tag":215,"props":344,"children":346},{"id":345},"我们可以通过代码验证prototype__proto__constructor",[347,349],{"type":23,"value":348},"我们可以通过代码验证",{"type":17,"tag":114,"props":350,"children":352},{"className":351},[],[353],{"type":23,"value":354},"prototype、__proto__、constructor",{"type":17,"tag":31,"props":356,"children":357},{},[358],{"type":17,"tag":62,"props":359,"children":362},{"alt":360,"src":361},"构造函数-原型.png","https:\u002F\u002Fp6-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fbd5f05dd75dd4577b02a7a7817424e5f~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":25,"props":364,"children":366},{"id":365},"原型链",[367],{"type":23,"value":365},{"type":17,"tag":31,"props":369,"children":370},{},[371],{"type":23,"value":372},"你有没有疑惑过我明明没有定义过toString()方法，但是我在哪都可以使用这个方法？答案很简单，这得益于原型链。",{"type":17,"tag":47,"props":374,"children":376},{"id":375},"理解原型与原型链最好的方法是就是将原型可视化",[377],{"type":23,"value":378},"理解原型与原型链最好的方法是就是将原型可视化。",{"type":17,"tag":31,"props":380,"children":381},{},[382,384],{"type":23,"value":383},"以上面代码为例\n",{"type":17,"tag":62,"props":385,"children":388},{"alt":386,"src":387},"原型1.png","https:\u002F\u002Fp1-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Ffd3e760acff24da39ddd915ae9a59b43~tplv-k3u1fbpfcp-watermark.image?",[],{"type":17,"tag":104,"props":390,"children":391},{},[392,411,430],{"type":17,"tag":108,"props":393,"children":394},{},[395,397,402,404,409],{"type":23,"value":396},"我们可以看到Person构造函数中有显式原型",{"type":17,"tag":114,"props":398,"children":400},{"className":399},[],[401],{"type":23,"value":119},{"type":23,"value":403},"属性指向他的原型，原型中又有一个",{"type":17,"tag":114,"props":405,"children":407},{"className":406},[],[408],{"type":23,"value":270},{"type":23,"value":410},"属性指回Person构造函数，",{"type":17,"tag":108,"props":412,"children":413},{},[414,416,421,423,428],{"type":23,"value":415},"而实例对象中有隐式原型属性",{"type":17,"tag":114,"props":417,"children":419},{"className":418},[],[420],{"type":23,"value":137},{"type":23,"value":422},"也指向Person原型对象，此时我们注意Person原型，因为他也是Object的实例对象，所有它也有一个隐式原型",{"type":17,"tag":114,"props":424,"children":426},{"className":425},[],[427],{"type":23,"value":137},{"type":23,"value":429},"属性指向Object原型，",{"type":17,"tag":108,"props":431,"children":432},{},[433,435,440],{"type":23,"value":434},"我们再看Objet原型，他的隐式原型属性",{"type":17,"tag":114,"props":436,"children":438},{"className":437},[],[439],{"type":23,"value":137},{"type":23,"value":441},"指向null，意味着空。所以Object原型就是整个原型链的终点。",{"type":17,"tag":47,"props":443,"children":445},{"id":444},"对于这段代码来说他的原型链就是person1实例对象person原型对象object的实例对象object原型对象可以发现原型链是沿着隐式原型属性__proto__走的所以也称为隐式原型链",[446,448,453],{"type":23,"value":447},"对于这段代码来说，他的原型链就是:person1实例对象——>Person原型对象(Object的实例对象)——>Object原型对象。可以发现原型链是沿着隐式原型属性",{"type":17,"tag":114,"props":449,"children":451},{"className":450},[],[452],{"type":23,"value":137},{"type":23,"value":454},"走的，所以也称为隐式原型链。",{"type":17,"tag":47,"props":456,"children":458},{"id":457},"把前面都弄懂最后尝试理解以下这个图",[459],{"type":23,"value":460},"把前面都弄懂，最后尝试理解以下这个图",{"type":17,"tag":31,"props":462,"children":463},{},[464],{"type":23,"value":465},"如果你能理解、说出这里每一条线产生的原因，并且脱离了这张图，看到图中的一个词立马能在脑中浮现出与它相关的指向，那么恭喜你，你在后面理解继承，以及学习TS类继承的时候，几乎无压力，全程绿灯，这点我深有感触。",{"type":17,"tag":31,"props":467,"children":468},{},[469],{"type":17,"tag":62,"props":470,"children":473},{"alt":471,"src":472},"原型链.webp","https:\u002F\u002Fp1-juejin.byteimg.com\u002Ftos-cn-i-k3u1fbpfcp\u002Fae55273691354149bd7589bbd6f9c93c~tplv-k3u1fbpfcp-watermark.image?",[],{"title":7,"searchDepth":475,"depth":475,"links":476},2,[477,478,483,484],{"id":27,"depth":475,"text":27},{"id":38,"depth":475,"text":38,"children":479},[480,481,482],{"id":49,"depth":187,"text":52},{"id":89,"depth":187,"text":92},{"id":142,"depth":187,"text":145},{"id":211,"depth":475,"text":211},{"id":365,"depth":475,"text":365,"children":485},[486,487,489],{"id":375,"depth":187,"text":378},{"id":444,"depth":187,"text":488},"对于这段代码来说，他的原型链就是:person1实例对象——>Person原型对象(Object的实例对象)——>Object原型对象。可以发现原型链是沿着隐式原型属性__proto__走的，所以也称为隐式原型链。",{"id":457,"depth":187,"text":460},"markdown","content:articles:frontend:javascript原型链.md","content","articles\u002Ffrontend\u002Fjavascript原型链.md","articles\u002Ffrontend\u002Fjavascript原型链","md",1779811690455]