一道有价值的JS继承面试题

vn266574 2年前
   <p><strong>题目</strong></p>    <p>原题目来源于一个网友的问答</p>    <pre>  <code class="language-javascript">var A = function() {      this.name = 'apple';  }  A.prototype.getName = function() {      return this.name;  }    // 补充代码    var B = A.extend({      initialize: function() {          this.superclass.initialize.call(this);          this.total = 3;      },      say: function() {          return '我有' + this.total + '个' + this.getName()      }  });  var b = new B();  console.log(b.say()); //我有3个apple</code></pre>    <p><strong>分析</strong></p>    <ol>     <li> <p>题目希望生成一个新的构造函数,B继承于A。(尽量不要更改A)</p> </li>     <li> <p>题目表达出希望有initialize方法实现构造函数继承,又需要原型继承。不难想到我们要用组合继承、寄生组合继承或者ES6继承。</p> </li>     <li> <p>如果所有的函数都可以使用extend方法生成一个新的构造函数,那方法的通用性会更强。</p> </li>     <li> <p>initialize的this指向显然要改成指向子类构造函数中的this。</p> </li>    </ol>    <p><strong>解答</strong></p>    <p>一. 要实现分析的第三点,不难想到使用函数的原型</p>    <pre>  <code class="language-javascript">Function.prototype.extend= Function.prototype.extend || function(obj) {}</code></pre>    <p>二. initialize方法实现构造函数继承</p>    <pre>  <code class="language-javascript">Function.prototype.extend= Function.prototype.extend || function(obj) {      var self = this; //这里的this指向函数调用者,也可以是A        function SubClass() {          this.superclass = { initialize: self };          if (obj.initialize) {              obj.initialize.call(this); //处理this指向问题          }      }            return SubClass;  }</code></pre>    <p>三. 原型继承并且添加新的原型方法</p>    <pre>  <code class="language-javascript">Function.prototype.extend= Function.prototype.extend || function(obj) {      var self = this; //这里的this指向函数调用者,也可以是A        function SubClass() {          this.superclass = { initialize: self };          if (obj.initialize) {              obj.initialize.call(this); //处理this指向问题          }      }            SubClass.prototype = new self();      SubClass.prototype.constructor = SubClass;        for(var key in obj){          if(key !== 'initialize'){              SubClass.prototype[key] = obj[key]          }      }            return SubClass;  }</code></pre>    <p><strong>问题</strong></p>    <ol>     <li> <p>添加较为严谨的类型判断</p> </li>     <li> <p>组合继承是存在一定问题的(见javascript高级教程第六章),如果能用ES6继承会更好。</p> </li>    </ol>    <p><strong>改进</strong></p>    <pre>  <code class="language-javascript">function inherits(subClass, superClass) { // ES6继承      if (typeof superClass !== "function" && superClass !== null) {          throw new TypeError("Super expression must either be null or a function, not " + typeof superClass);      }      subClass.prototype = Object.create(superClass && superClass.prototype, {          constructor: {               value: subClass,              enumerable: false,              writable: true,              configurable: true          }      });      if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass;  }    function getType(obj) {      return Object.prototype.toString.call(obj).slice(8, -1).toLowerCase();  }    Function.prototype.extend= Function.prototype.extend || function(obj) {      var self = this; //这里的this指向函数调用者,也可以是A        function SubClass() {          this.superclass = { initialize: self };          if (getType(obj) === 'object' && getType(obj.initialize) === 'function') {              obj.initialize.call(this); //处理this指向问题          }      }            inherits(SubClass, self);        for (var key in obj) {          if (key !== 'initialize') {              SubClass.prototype[key] = obj[key]          }      }            return SubClass;  }</code></pre>    <p><strong>总结:</strong></p>    <ol>     <li> <p>该题目考查了几个重要的知识点:原型,继承,闭包,this指向。是一道比较值得去好好思考的题目。</p> </li>     <li> <p>希望有更好的解决方案出现。</p> </li>    </ol>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008888142</p>    <p> </p>