阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      JS object 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
        }
      };
      

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

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

      规范

      SpecificationStatusComment
      ECMAScript 1st Edition (ECMA-262)StandardInitial definition. Implemented in JavaScript 1.1.
      ECMAScript 5.1 (ECMA-262) Object.prototype.constructorStandard
      ECMAScript 2015 (6th Edition, ECMA-262)Object.prototype.constructorStandard
      ECMAScript Latest Draft (ECMA-262)Object.prototype.constructorDraft
      目录
      目录