凌可儿 發表於 2019-12-26 11:15:00

JavaScript 继承小记

<p>面向对象编程很重要的一个方面,就是对象的继承。A 对象通过继承 B 对象,就能直接拥有 B 对象的所有属性和方法。这对于代码的复用是非常有用的。</p>
<p>大部分面向对象的编程语言,都是通过“类”(class)实现对象的继承。传统上,JavaScript 语言的继承不通过 class(ES6 引入了class 语法),而是通过“原型对象”(prototype)实现。那么在JS中常见的继承方式有几种呢?</p>
<p>首先我们先来通过 es5 里的方法做一个类,即构造方法,如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person() {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name = "张三"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age = 18<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过类添加属性和静态方法</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> Person.city = "北京"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">18</span> Person.eat = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">19</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在吃"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 实例化 Person</span>
<span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Person();
</span><span style="color: rgba(0, 128, 128, 1)">24</span> p.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> p.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> p.eat(); // 报错 p.eat is not a function</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> Person.eat(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Person在吃// this 指向发生改变,为全局,该 name 不是 Person 类中定义的 name</span></pre>
</div>
<p>&nbsp;</p>
<p>在上面的代码中,我们根据构造函数方法创建了一个 Person 类,并通过内部定义参数方法,原型链扩展属性和方法,通过类添加属性和方法。接下来我们就根据这个 Person 类来实现集中继承的方法。</p>
<p>1、对象冒充实现继承</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person() {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name = "张三"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age = 18<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student() {
</span><span style="color: rgba(0, 128, 128, 1)">18</span>   Person.call(<span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Student();
</span><span style="color: rgba(0, 128, 128, 1)">21</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">23</span> <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 128, 0, 1)"> * 对象冒充继承不能实现
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 128, 0, 1)"> * 父类原型链上的属性和方法
</span><span style="color: rgba(0, 128, 128, 1)">26</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> undefined</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 报错 s.work is not a function</span></pre>
</div>
<p>在上面的代码中,我们可以通过对象冒充的方法进行继承,但是原型链上的属性和方法是不能被继承的。</p>
<p>&nbsp;</p>
<p>2、原型链继承</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person() {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name = "张三"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age = 18<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过类添加属性和静态方法</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> Person.city = "北京"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">18</span> Person.eat = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">19</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在吃"<span style="color: rgba(0, 0, 0, 1)">)
</span><span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student() {
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">25</span> Student.prototype = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Person();
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Student();
</span><span style="color: rgba(0, 128, 128, 1)">27</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">29</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span></pre>
</div>
<p>在上面的代码中,我们通过原型链的方法进行继承,这样构造方法内的方法和原型链上的方法我们都能继承了,看似很不错,但是其实存在着一些问题,如下:</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person(name,age) {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person("张三",18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> p.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> p.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span>
<span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student(name,age) {
</span><span style="color: rgba(0, 128, 128, 1)">21</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">23</span> Student.prototype = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Person();
</span><span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span> Student("李四", '20'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">25</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> undefined</span>
<span style="color: rgba(0, 128, 128, 1)">26</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> undefined在运动</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> undefined在工作</span></pre>
</div>
<p>在上面的代码中,我们可以看出,通过原型链继承,在实例化子类的时候没法给父类进行传参。</p>
<p>3、原型链+对象冒充组合继承</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person("张三", 18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> p.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> p.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span>
<span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)">21</span>   Person.call(<span style="color: rgba(0, 0, 255, 1)">this</span>, name, age); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象冒充</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> Student.prototype = <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Person();
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span> Student("李四", '20'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">26</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四</span>
<span style="color: rgba(0, 128, 128, 1)">27</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span>
<span style="color: rgba(0, 128, 128, 1)">29</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span></pre>
</div>
<p>上面的代码中我们通过原型链继承+对象冒充的组合方式实现了继承,不过也存在缺点就是无论在什么情况下,都会调用两次构造函数:一次是在创建子类型原型的时候,另一次是在子类型构造函数的内部,子类型最终会包含父类型对象的全部实例属性,但我们不得不在调用子类构造函数时重写这些属性。</p>
<p>4、组合继承优化</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person("张三", 18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> p.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> p.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span>
<span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)">21</span>   Person.call(<span style="color: rgba(0, 0, 255, 1)">this</span>, name, age); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象冒充</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> <span style="color: rgba(0, 128, 0, 1)">/*</span><span style="color: rgba(0, 128, 0, 1)">*
</span><span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 128, 0, 1)"> * 可以只继承 Person 的原型链
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 128, 0, 1)"> * 因为上面已经通过对象冒充继承了 Person 构造方法
</span><span style="color: rgba(0, 128, 128, 1)">27</span><span style="color: rgba(0, 128, 0, 1)">*/</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> Student.prototype =<span style="color: rgba(0, 0, 0, 1)"> Person.prototype;
</span><span style="color: rgba(0, 128, 128, 1)">29</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span> Student("李四", '20'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">30</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四</span>
<span style="color: rgba(0, 128, 128, 1)">31</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span>
<span style="color: rgba(0, 128, 128, 1)">32</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span>
<span style="color: rgba(0, 128, 128, 1)">34</span>
<span style="color: rgba(0, 128, 128, 1)">35</span> console.log(s <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Student, s <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Person); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">true true</span>
<span style="color: rgba(0, 128, 128, 1)">36</span> console.log(s.constructor); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">Person</span></pre>
</div>
<p>这种方式通过父类原型和子类原型指向同一对象,子类可以继承到父类的公有方法当做自己的公有方法,而且不会初始化两次实例方法/属性,避免的组合继承的缺点。</p>
<p>但是这种方法没办法辨别是实例是子类还是父类创造的,子类和父类的构造函数指向是同一个。</p>
<p>&nbsp;</p>
<p>5、组合继承继续优化</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Person(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义参数</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 6</span>   <span style="color: rgba(0, 0, 255, 1)">this</span>.run = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)"> 8</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">10</span>
<span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 通过原型链扩展属性和方法</span>
<span style="color: rgba(0, 128, 128, 1)">12</span> Person.prototype.sex = "男"<span style="color: rgba(0, 0, 0, 1)">;
</span><span style="color: rgba(0, 128, 128, 1)">13</span> Person.prototype.work = <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> () {
</span><span style="color: rgba(0, 128, 128, 1)">14</span>   console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> <span style="color: rgba(0, 0, 0, 1)">};
</span><span style="color: rgba(0, 128, 128, 1)">16</span> <span style="color: rgba(0, 0, 255, 1)">var</span> p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person("张三", 18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">17</span> p.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在运动</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> p.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 张三在工作</span>
<span style="color: rgba(0, 128, 128, 1)">19</span>
<span style="color: rgba(0, 128, 128, 1)">20</span> <span style="color: rgba(0, 0, 255, 1)">function</span><span style="color: rgba(0, 0, 0, 1)"> Student(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)">21</span>   Person.call(<span style="color: rgba(0, 0, 255, 1)">this</span>, name, age); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 对象冒充</span>
<span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span> Student.prototype =<span style="color: rgba(0, 0, 0, 1)"> Object.create(Person.prototype);
</span><span style="color: rgba(0, 128, 128, 1)">25</span> Student.prototype.constructor =<span style="color: rgba(0, 0, 0, 1)"> Student;
</span><span style="color: rgba(0, 128, 128, 1)">26</span> <span style="color: rgba(0, 0, 255, 1)">var</span> s = <span style="color: rgba(0, 0, 255, 1)">new</span> Student("李四", '20'<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">27</span> console.log(s.name); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四</span>
<span style="color: rgba(0, 128, 128, 1)">28</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span>
<span style="color: rgba(0, 128, 128, 1)">29</span> console.log(s.sex); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 男</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span>
<span style="color: rgba(0, 128, 128, 1)">31</span>
<span style="color: rgba(0, 128, 128, 1)">32</span> console.log(s <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Student, s <span style="color: rgba(0, 0, 255, 1)">instanceof</span> Person); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> true true</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> console.log(s.constructor); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Student</span></pre>
</div>
<p>在上面的代码中,我们通过借助原型可以基于已有的对象来创建对象,&nbsp;<span class="cnblogs_code"><span style="color: rgba(0, 0, 255, 1)">var</span> B = Object.create(A)</span>&nbsp;&nbsp;以A对象为原型,生成了B对象。B继承了A的所有属性和方法。</p>
<p>同样的,Student 继承了所有的 Person 原型对象的属性和方法。目前来说,最完美的继承方法!</p>
<p>&nbsp;</p>
<p>上面的代码我们都是基于 ES5 的特性进行的继承,在 ES6 中为我们提供了 class 类来帮助我们更快更好的实现继承。</p>
<p>ES6中引入了class关键字,class可以通过extends关键字实现继承,还可以通过static关键字定义类的静态方法,这比 ES5 的通过修改原型链实现继承,要清晰和方便很多。</p>
<p>ES5 的继承,实质是先创造子类的实例对象this,然后再将父类的方法添加到this上面(Parent.call(this))。ES6 的继承机制完全不同,实质是先将父类实例对象的属性和方法,加到this上面(所以必须先调用super方法),然后再用子类的构造函数修改this。</p>
<p>需要注意的是,class关键字只是原型的语法糖,JavaScript继承仍然是基于原型实现的。</p>
<div class="cnblogs_code">
<pre><span style="color: rgba(0, 128, 128, 1)"> 1</span> <span style="color: rgba(0, 0, 0, 1)">class Person {
</span><span style="color: rgba(0, 128, 128, 1)"> 2</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">调用类的构造方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 3</span> <span style="color: rgba(0, 0, 0, 1)">    constructor(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)"> 4</span>         <span style="color: rgba(0, 0, 255, 1)">this</span>.name =<span style="color: rgba(0, 0, 0, 1)"> name;
</span><span style="color: rgba(0, 128, 128, 1)"> 5</span>         <span style="color: rgba(0, 0, 255, 1)">this</span>.age =<span style="color: rgba(0, 0, 0, 1)"> age;
</span><span style="color: rgba(0, 128, 128, 1)"> 6</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)"> 7</span>   
<span style="color: rgba(0, 128, 128, 1)"> 8</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义方法</span>
<span style="color: rgba(0, 128, 128, 1)"> 9</span> <span style="color: rgba(0, 0, 0, 1)">    run() {
</span><span style="color: rgba(0, 128, 128, 1)">10</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在运动"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">11</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">12</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">13</span>
<span style="color: rgba(0, 128, 128, 1)">14</span> let p = <span style="color: rgba(0, 0, 255, 1)">new</span> Person('张三', 18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">15</span> console.log(p); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Person { name: '张三', age: 18 }</span>
<span style="color: rgba(0, 128, 128, 1)">16</span>
<span style="color: rgba(0, 128, 128, 1)">17</span> <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">定义一个子类</span>
<span style="color: rgba(0, 128, 128, 1)">18</span> <span style="color: rgba(0, 0, 0, 1)">class Student extends Person {
</span><span style="color: rgba(0, 128, 128, 1)">19</span> <span style="color: rgba(0, 0, 0, 1)">    constructor(name, age) {
</span><span style="color: rgba(0, 128, 128, 1)">20</span>         <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">通过super调用父类的构造方法</span>
<span style="color: rgba(0, 128, 128, 1)">21</span> <span style="color: rgba(0, 0, 0, 1)">      super(name, age)
</span><span style="color: rgba(0, 128, 128, 1)">22</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">23</span>
<span style="color: rgba(0, 128, 128, 1)">24</span>   <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)">在子类自身定义方法</span>
<span style="color: rgba(0, 128, 128, 1)">25</span> <span style="color: rgba(0, 0, 0, 1)">    work() {
</span><span style="color: rgba(0, 128, 128, 1)">26</span>         console.log(<span style="color: rgba(0, 0, 255, 1)">this</span>.name + "在工作"<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">27</span> <span style="color: rgba(0, 0, 0, 1)">    }
</span><span style="color: rgba(0, 128, 128, 1)">28</span> <span style="color: rgba(0, 0, 0, 1)">}
</span><span style="color: rgba(0, 128, 128, 1)">29</span>
<span style="color: rgba(0, 128, 128, 1)">30</span> let s = <span style="color: rgba(0, 0, 255, 1)">new</span> Student('李四', 18<span style="color: rgba(0, 0, 0, 1)">);
</span><span style="color: rgba(0, 128, 128, 1)">31</span> console.log(s); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> Student { name: '李四', age: 18 }</span>
<span style="color: rgba(0, 128, 128, 1)">32</span> s.run(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在运动</span>
<span style="color: rgba(0, 128, 128, 1)">33</span> s.work(); <span style="color: rgba(0, 128, 0, 1)">//</span><span style="color: rgba(0, 128, 0, 1)"> 李四在工作</span></pre>
</div>
<p>上面通过 class 关键字所创建的类的继承简单易懂,是未来 JS 的发展方向。</p><br><br>
来源:https://www.cnblogs.com/weijiutao/p/12090916.html
頁: [1]
查看完整版本: JavaScript 继承小记