<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>原型链与继承 on Last Stand</title><link>https://amatsuzero.github.io/LastStand/tags/%E5%8E%9F%E5%9E%8B%E9%93%BE%E4%B8%8E%E7%BB%A7%E6%89%BF/</link><description>Recent content in 原型链与继承 on Last Stand</description><generator>Hugo</generator><language>zh-cn</language><lastBuildDate>Fri, 08 Nov 2024 00:00:00 +0800</lastBuildDate><atom:link href="https://amatsuzero.github.io/LastStand/tags/%E5%8E%9F%E5%9E%8B%E9%93%BE%E4%B8%8E%E7%BB%A7%E6%89%BF/index.xml" rel="self" type="application/rss+xml"/><item><title>原型链与继承</title><link>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</link><pubDate>Tue, 01 Oct 2024 00:00:00 +0800</pubDate><guid>https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/</guid><description>&lt;p&gt;&lt;code&gt;JavaScript&lt;/code&gt; 中没有类的概念的，主要通过原型链来实现继承。通常情况下，继承意味着复制操作，然而 &lt;code&gt;JavaScript&lt;/code&gt; 默认并不会复制对象的属性，相反，&lt;code&gt;JavaScript&lt;/code&gt; 只是在两个对象之间创建一个关联（原型对象指针），这样，一个对象就可以通过委托访问另一个对象的属性和函数，所以与其叫继承，委托的说法反而更准确些。&lt;/p&gt;
&lt;h2 id="原型"&gt;原型&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;当我们 &lt;code&gt;new&lt;/code&gt; 了一个新的对象实例，明明什么都没有做，就直接可以访问 &lt;code&gt;toString&lt;/code&gt; 、&lt;code&gt;valueOf&lt;/code&gt; 等原生方法。那么这些方法是从哪里来的呢？答案就是原型。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-01.png"&gt;&lt;/p&gt;
&lt;p&gt;在控制台打印一个空对象时，我们可以看到，有很多方法，已经“初始化”挂载在内置的 &lt;code&gt;__proto__&lt;/code&gt; 对象上了。这个内置的 &lt;code&gt;__proto__&lt;/code&gt; 是一个指向原型对象的指针，它会在创建一个新的引用类型对象时（显示或者隐式）自动创建，并挂载到新实例上。当我们尝试访问实例对象上的某一属性 / 方法时，如果实例对象上有该属性 / 方法时，就返回实例属性 / 方法，如果没有，就去 &lt;code&gt;__proto__&lt;/code&gt; 指向的原型对象上查找对应的属性 / 方法。这就是为什么我们尝试访问空对象的 &lt;code&gt;toString&lt;/code&gt; 和 &lt;code&gt;valueOf&lt;/code&gt; 等方法依旧能访问到的原因，&lt;strong&gt;&lt;code&gt;JavaScript&lt;/code&gt; 正式以这种方式为基础来实现继承的。&lt;/strong&gt;&lt;/p&gt;
&lt;h2 id="构造函数"&gt;构造函数&lt;/h2&gt;
&lt;p&gt;如果说实例的 &lt;code&gt;__proto__&lt;/code&gt; 只是一个指向原型对象的指针，那就说明在此之前原型对象就已经创建了，那么原型对象是什么时候被创建的呢？这就要引入&lt;strong&gt;构造函数&lt;/strong&gt;的概念。&lt;/p&gt;
&lt;p&gt;其实构造函数也就只是一个普通的函数而已，如果这个函数可以使用 &lt;code&gt;new&lt;/code&gt; 关键字来创建它的实例对象，那么我们就把这种函数称为 &lt;strong&gt;构造函数&lt;/strong&gt;。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre tabindex="0" style="color:#f8f8f2;background-color:#272822;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-text-size-adjust:none;"&gt;&lt;code class="language-javascript" data-lang="javascript"&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 普通函数
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#75715e"&gt;// 构造函数，函数首字母通常大写
&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;function&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt; () {}
&lt;/span&gt;&lt;/span&gt;&lt;span style="display:flex;"&gt;&lt;span&gt;&lt;span style="color:#66d9ef"&gt;const&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;person&lt;/span&gt; &lt;span style="color:#f92672"&gt;=&lt;/span&gt; &lt;span style="color:#66d9ef"&gt;new&lt;/span&gt; &lt;span style="color:#a6e22e"&gt;Person&lt;/span&gt;();
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;原型对象正是在构造函数被声明时一同创建的。构造函数被申明时，原型对象也一同完成创建，然后挂载到构造函数的 &lt;code&gt;prototype&lt;/code&gt; 属性上：&lt;/p&gt;
&lt;p&gt;&lt;img loading="lazy" src="https://amatsuzero.github.io/LastStand/posts/frontend/javascript/javascript-011/image-02.png"&gt;&lt;/p&gt;
&lt;p&gt;原型对象被创建时，会自动生成一个 &lt;code&gt;constructor&lt;/code&gt; 属性，指向创建它的构造函数。这样它俩的关系就被紧密地关联起来了。&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;细心的话，你可能会发现，原型对象也有自己的 &lt;code&gt;__proto__&lt;/code&gt; ，这也不奇怪，毕竟万物皆对象嘛。原型对象的 &lt;strong&gt;proto&lt;/strong&gt; 指向的是 &lt;code&gt;Object.prototype&lt;/code&gt;。那么 &lt;code&gt;Object.prototype.__proto__&lt;/code&gt; 存不存在呢？其实是不存在的，打印的话会发现是 &lt;code&gt;null&lt;/code&gt; 。这也证明了 &lt;code&gt;Object&lt;/code&gt; 是 &lt;code&gt;JavaScript&lt;/code&gt; 中数据类型的起源。&lt;/p&gt;</description></item></channel></rss>