【问题标题】:Is there a good use case for the constructor property in Javascript?Javascript 中的构造函数属性是否有很好的用例?
【发布时间】:2025-12-03 14:25:01
【问题描述】:

首先,这个问题不是“构造函数属性是做什么的?” - 关于它到底是什么以及它是如何工作的,有很多很好的文档:它是对创建对象的函数的引用(可能从它的原型继承)。

我更感兴趣的是了解此属性的常见用例。理论上看起来一切都很好,但是您什么时候真正需要对构造对象的函数的引用?一些想法是:

  • 也许我想克隆它。我可以再次调用构造函数并
    获取我的对象的另一个实例。这当然不会很好用 因为您可能会创建对象的实例
    原型,而不是对象本身;加上一个更受欢迎的方法 是创建一个新对象并设置该对象的原型。
  • 也许你可以用它来判断对象的“类型”是什么 是。这似乎很奇怪,因为您可以使用 instanceofObject.prototype.toString() 代替。
  • 能否更改或重新分配构造函数?是否有充分的理由 这样做?

希望有些人可以加入一些使用构造函数引用的优秀 Javascript 模式,或提供该属性为何存在的官方解释。

【问题讨论】:

  • Object.prototype.toString 不会帮助您确定通过用户定义的构造函数创建的对象的类型。它仅有助于区分各种内置函数。
  • "这当然行不通,因为您可能会创建对象原型的实例,而不是对象本身" - 你是什么意思?它工作正常:jsfiddle.net/tjnuA
  • 其实我什至不知道你是怎么做到的——像var x = new myObj.constructor()之类的?
  • @MikeChristensen 嗯,是的,你可以做到...这是一个合法的用例。
  • 哦,抱歉,没有注意到您的 jsfiddle 链接 - 我的意思是,是的,它在理论上确实有效(我没有尝试过),但是您正在克隆原型,而不是目的。我已经更新了你的代码来演示:jsfiddle.net/tjnuA/1

标签: javascript prototype-programming


【解决方案1】:

构造函数属性很方便(或者如果它是可靠的)的一种情况是函数需要知道它已传递的参数类型,例如

function foo(arg) {
  if ( /* if arg is an array */ ) {
    // deal with array
  } else if ( /* if arg is an object */ ) {
    // deal with object
  }
}

如果上述函数传递一个数组或对象,那么typeof 在这两种情况下都会返回object。可以使用构造函数属性:

  if ( arg.constructor == Array )

但是,如果数组是在与测试发生位置不同的框架中创建的(即,它的 Array 构造函数与测试范围内的 Array 函数是不同的对象),则会失败。

因此,如果您排除框架(或范围是问题的其他情况),那么构造函数属性可以用于此。

但这并不能解决构造函数属性可写的一般问题(因此可以设置为任何内容)以及原型链不重要的情况。

【讨论】:

  • 在这种情况下测试arg.constructor 还是arg.constructor.toString() 更好?当我只使用 ArrayImageData 时,JsHint 会抱怨。
  • 解决 JSHint 抱怨的原因并解决与您相关的问题。 Javascript 是非常动态的,如果你设定界限并生活在其中,生活会更轻松。
  • 我从来没有找到以这种方式测试.constructor 属性的理由。如果我进行类型测试,我通常使用instanceof,因为它是语言内置的,即使对象继承自您正在测试的对象也可以工作,即使.constructor 设置不正确也可以工作。我想测试.constructor 属性可以做的一件事是测试叶对象类型是否匹配某种类型的对象,但大多数多态设计不需要知道这一点。如果它像“鸭子”一样工作,那么您可以将其视为“鸭子”,即使它已被归类为“野鸭”。
【解决方案2】:

其中一个很好的用例是在 javascript 中实现“继承”和“类”。让我们考虑以下示例:

// define the Person Class
function Person() {}

Person.prototype.walk = function(){
  alert ('I am walking!');
};
Person.prototype.sayHello = function(){
  alert ('hello');
};

// define the Student class
function Student() {
  // Call the parent constructor
  Person.call(this);
}

// inherit Person
Student.prototype = new Person();

// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;

// replace the sayHello method
Student.prototype.sayHello = function(){
  alert('hi, I am a student');
}

// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
  alert('goodBye');
}

var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();

// check inheritance
alert(student1 instanceof Person); // true 
alert(student1 instanceof Student); // true

如您所见,我们通过将 Student.prototype 重新分配给 new Person(); 来继承 Person,但随后我们需要将构造函数重新分配给 Student,因为我们要创建 Student 类的实例,而不是 Person。

更新

顺便说一句,更真实的javascript继承示例是使用中间函数,因此在定义阶段不会创建Person对象:

// inherit Person
function F() {}
F.prototype = Person.prototype;
Student.prototype = new F();

【讨论】:

  • 这个:Student.prototype = Object.create( Person.prototype ); 而不是 Student.prototype = new Person();。后一个坏了,应该避免。
  • 我知道 Javascript 中基于原型的继承,但是在您的示例中,如果您注释掉 Student.prototype.constructor = Student;,那么结果将完全相同。那么“纠正”构造函数的意义何在。我的问题是你什么时候需要构造函数引用?
  • @MikeChristensen,如果你不正确的构造函数,那么你可能无法识别对象的确切类型:student1.constructor === Student //will be false if correct constructor was not assigned 有意义吗?
  • 到目前为止,我们发现的唯一用例似乎是您需要能够准确地确定某物是什么类型的对象,并且您需要它可以跨原始类型工作和用户定义的类型。
  • 嗯,有时您甚至需要创建与您所拥有的对象相同的实例。而做到这一点的唯一方法就是弄清楚类型然后创建对象,或者直接使用obj.prototype.constructor这个
【解决方案3】:

我以前用它来进行类型检查。它并不比instanceof 有用多少,但它更明确一点。

function isArray(o) {
    return o.constructor == Array;
}

【讨论】:

    最近更新 更多