• 首页
  • vue
  • TypeScript
  • JavaScript
  • scss
  • css3
  • html5
  • php
  • MySQL
  • redis
  • jQuery
  • Object.prototype.constructor

    返回创建实例对象的Object构造函数的引用。注意,此属性的值是对函数本身的引用,而不是一个包含函数名称的字符串。对原始类型来说,如1true"test",该值只可读。

    描述

    所有对象都会从它的原型上继承一个constructor属性:

    var o = {};
    o.constructor === Object; // true
    
    var o = new Object;
    o.constructor === Object; // true
    
    var a = [];
    a.constructor === Array; // true
    
    var a = new Array;
    a.constructor === Array // true
    
    var n = new Number(3);
    n.constructor === Number; // true
    

    示例

    打印一个对象的构造函数

    以下示例创建一个原型,Tree,以及该类型的对象,即theTree。然后打印theTree对象的constructor属性。

    function Tree(name) {
       this.name = name;
    }
    
    var theTree = new Tree("Redwood");
    console.log( "theTree.constructor is " + theTree.constructor );
    

    打印输出:

    theTree.constructor is function Tree(name) {
        this.name = name;
    }
    

    改变对象的 constructor

    下面的例子展示了如何修改基本类型对象的constructor属性的值。只有true,1"test"的不受影响,因为创建他们的是只读的原生构造函数(native constructors)。这个例子也说明了依赖一个对象的constructor属性并不安全。

    function Type() { };
    
    var	types = [
    	new Array,
        [],
    	new Boolean,
        true,        // remains unchanged
    	new Date,
    	new Error,
    	new Function,
    	function(){},
    	Math,	
    	new Number,
    	1,           // remains unchanged
    	new Object,
    	{},
    	new RegExp,
    	/(?:)/,
    	new String,
    	"test"       // remains unchanged
    ];
    
    for(var i = 0; i < types.length; i++) {
    	types[i].constructor = Type;
    	types[i] = [ types[i].constructor, types[i] instanceof Type, types[i].toString() ];
    };
    
    console.log( types.join("\n") );
    

    此示例显示以下输出:

    function Type() {},false,
    function Type() {},false,
    function Type() {},false,false
    function Boolean() {
        [native code]
    },false,true
    function Type() {},false,Mon Sep 01 2014 16:03:49 GMT+0600
    function Type() {},false,Error
    function Type() {},false,function anonymous() {
    
    }
    function Type() {},false,function () {}
    function Type() {},false,[object Math]
    function Type() {},false,0
    function Number() {
        [native code]
    },false,1
    function Type() {},false,[object Object]
    function Type() {},false,[object Object]
    function Type() {},false,/(?:)/
    function Type() {},false,/(?:)/
    function Type() {},false,
    function String() {
        [native code]
    },false,test
    

    改变函数的 constructor

    大多数情况下,此属性用于定义一个构造函数,并使用new和继承原型链进一步调用它。

    function Parent() {}
    Parent.prototype.parentMethod = function parentMethod() {};
    
    function Child() {}
    Child.prototype = Object.create(Parent.prototype); // re-define child prototype to Parent prototype
    
    Child.prototype.constructor = Child; // return original constructor to Child
    

    但为什么我们需要在这里执行最后一行?很不幸正确答案是- 看情况而定。

    让我们来尝试定义在哪些情况下,重新分配原始构造函数会发挥重要作用,以及在什么时候它就是额外的未使用的(无效的)代码行。

    试想下一种情况:该对象具有创建自身的create方法。

    function Parent() {};
    function CreatedConstructor() {}
    
    CreatedConstructor.prototype = Object.create(Parent.prototype);
    
    CreatedConstructor.prototype.create = function create() {
      return new this.constructor();
    }
    
    new CreatedConstructor().create().create(); // error undefined is not a function since constructor === Parent
    

    在上面的示例中,将显示异常,因为构造函数链接到Parent。

    为了避免它,只需分配您将要使用的必要构造函数。

    function Parent() {}; 
    function CreatedConstructor() {} 
    
    CreatedConstructor.prototype = Object.create(Parent.prototype); 
    CreatedConstructor.prototype.constructor = CreatedConstructor; // set right constructor for further using
    
    CreatedConstructor.prototype.create = function create() { 
      return new this.constructor();
    } 
    
    new CreatedConstructor().create().create(); // it's pretty fine
    

    好的,现在很清楚为什么更改构造函数会很有用。

    让我们再考虑一个案例。

    function ParentWithStatic() {}
    
    ParentWithStatic.startPosition = { x: 0, y:0 };
    ParentWithStatic.getStartPosition = function getStartPosition() {
      return this.startPosition;
    } 
    
    function Child(x, y) {
      this.position = {
        x: x,
        y: y
      };
    }
    
    Child.prototype = Object.create(ParentWithStatic.prototype); 
    Child.prototype.constructor = Child;
    
    Child.prototype.getOffsetByInitialPosition = function getOffsetByInitialPosition() {
      var position = this.position;
      var startPosition = this.constructor.getStartPosition(); // error undefined is not a function, since the constructor is Child
    
      return {
        offsetX: startPosition.x - position.x,
        offsetY: startPosition.y - position.y
      }
    };
    

    对于此示例,我们需要保持父构造函数继续正常工作。

    总结:手动设置或更新构造函数可能会导致不同且有时令人困惑的后果。为了防止它,只需在每个特定情况下定义构造函数的角色。在大多数情况下,不使用构造函数,并且不需要重新分配构造函数。