JavaScript - 意外/奇怪的构造函数

时间:2015-02-11 23:09:58

标签: javascript

var ninja = {
    name: 'Ninja',
    say: function () {
        return 'I am a ' + this.name;
    }
};

function F(){
}

F.prototype = ninja;

var ninja2 = new F();

ninja2.name;

Output >>> "Ninja"

ninja2.constructor === F

Output >>> false

ninja2.constructor

Output >>> function Object()

ninja2.__proto__ === ninja

Output >>> true

在此示例中,为什么F ninja2的构造函数不是Hero (正如人们所料)?!

我希望这是因为...下一个例子打印function Hero(){ } var h1 = new Hero(); h1.constructor Output >>> function Hero()

F.prototype = ninja;

概念上有什么区别?

我认为这与我在第一个例子中明确设置F的事实有关。但它与此有何关系?我很困惑。 ninja2的构造函数new F()不是ninja2吗?在使用{{1}}创建{{1}}之后?

2 个答案:

答案 0 :(得分:2)

constructor属性没有魔力,它只是在创建函数对象时自动添加的属性:

  

13.2 Creating Function Objects

     
      
  • 创建一个新的本机ECMAScript对象,让 F 成为该对象。
  •   
  • ...
  •   
  • proto 是创建一个新对象的结果,该对象将由表达式new Object()构造,其中Object是具有该名称的标准内置构造函数。 / LI>   
  • 使用参数&#34; constructor&#34;,Property Descriptor {[[Value]]调用 proto 的[[DefineOwnProperty]]内部方法:< em> F ,{   [[可写]]: true ,[[Enumerable]]: false ,[[Configurable]]:    true }, false
  •   
  • 使用参数&#34; prototype&#34;,Property Descriptor {[[Value]]调用 F 的[[DefineOwnProperty]]内部方法:< EM>原,   {[[可写]]: true ,[[Enumerable]]: false ,[[Configurable]]:    false }和 false
  •   
  • ...
  •   

示例:

function F(){}
F.prototype.constructor; // F

因此,当您使用其他对象覆盖F.prototype时,您将失去constructor属性。

然后,当您使用ninja2.constructor时,您会获得Object因为:

  1. ninja2没有自己的constructor属性。
  2. ninja2继承自ninja,其中没有constructor属性。
  3. ninja继承自Object.prototype,其constructor属性设置为Object
  4. 要解决此问题,您可以

    • constructor中恢复F.prototype

      function F(){}
      F.prototype = ninja;
      F.prototype.constructor = F;
      
    • constructor中加入ninja

      var ninja = {
          constructor: F, /* ... */
      };
      
    • 将所需的属性添加到F.prototype,而不是将其替换为另一个对象:

      Object.assign(F.prototype, ninja); /* Requires ECMAScript 6 */
      

答案 1 :(得分:1)

你宣布&#34; F&#34;如下:

function F(){}

这将创建一个功能对象&#34; F&#34;这样的原型:

F.prototype = { constructor: F };

&#34; ninja&#34;您创建的对象默认具有Object()构造函数。用'&#34; ninja&#34;替换F.prototype时。对象,下面的代码行现在使用来自&#34; ninja&#34;的Object()构造函数。因为你覆盖了F&#39的原型:

var ninja2 = new F();