Javascript构造函数属性的意义是什么?

aaa*_*210 118 javascript constructor prototype

试图绕过Javascript对OO的看法......和许多其他人一样,对constructor财产产生混淆.特别是constructor财产的重要性,因为我似乎无法使其产生任何影响.例如:

function Foo(age) {
    this.age = age;
}

function Bar() {
    Foo.call(this, 42);
    this.name = "baz"; 
}

Bar.prototype = Object.create(Foo.prototype); 
var b = new Bar;    

alert(b.constructor); // "Foo". That's OK because we inherit `Foo`'s prototype.
alert(b.name);        // "baz". Shows that Bar() was called as constructor.
alert(b.age);         // "42", inherited from `Foo`.
Run Code Online (Sandbox Code Playgroud)

在上面的例子中,对象b似乎有正确的构造函数call(Bar) - 并且它继承了age属性Foo.那么为什么许多人认为这是必要的步骤:

Bar.prototype.constructor = Bar;
Run Code Online (Sandbox Code Playgroud)

显然,Bar构造时会调用正确的构造函数b,因此这个原型属性有什么影响?我很想知道它实际上使构造函数属性设置'正确'有什么实际区别 - 因为我无法看到它对创建对象后实际调用的构造函数有任何影响.

Jak*_*kob 99

第一步是了解什么constructorprototype所有.这并不困难,但人们不得不放弃传统意义上的"继承".

构造函数

constructor属性不会在程序中产生任何特殊效果,除了您可以查看它以查看与操作符一起使用哪个函数new来创建对象.如果你键入new Bar()它将是Bar,你输入new Foo它将是Foo.

原型

prototype如果相关对象没有要求的属性,则该属性用于查找.如果你写x.attr,JavaScript就试图找到attr其中x的属性.如果它找不到它,它会查看x.__proto__.如果它不存在,x.__proto__.__proto__只要__proto__定义它就会查看等等.

那么__proto__它与它有什么关系prototype呢?简而言之,prototype是"类型",而__proto__"实例".(我用引号说,因为类型和实例之间没有任何区别).当你写作时x = new MyType(),发生的事情(以及其他事情)x.__proto___是设置的MyType.prototype.

这个问题

现在,上面应该是你需要得出你自己的例子意味着什么,但试图回答你的实际问题; "为什么要这样写":

Bar.prototype.constructor = Bar;

我个人从来没有见过它,我发现它有点愚蠢,但在你给出它的上下文中,意味着Bar.prototype-object(通过使用创建new Foo(42))将构成由Bar而不是创建Foo.我想这个想法有些类似于C++/Java/C#类似的语言,其中类型查找(constructor属性)将始终产生最具体的类型,而不是原型链中更通用的对象的类型.

我的建议:不要过多考虑JavaScript中的"继承".接口和mixin的概念更有意义.并且不要检查对象的类型.检查所需的属性("如果它像鸭子一样走路,像鸭子一样呱呱叫,它是一只鸭子").

试图强制JavaScript进入经典的继承模型,当它具有如上所述的原型机制时,就会引起混淆.建议手动设置constructor-property 的许多人可能试图这样做.抽象很好,但是构造函数属性的这种手动赋值并不是非常惯用的JavaScript.

  • @Jakob,你说"`constructor`属性__does not__会导致程序中的任何特殊效果,除了你可以查看它以查看哪个函数与运算符`new`一起使用来创建你的对象.如果你输入的话`new Bar()`它将是`Bar`,你键入`new Foo`it将是'Foo`." 这是不正确的.`constructor`属性是指创建给定对象的**原型**的函数,如示例中甚至由OP所见. (5认同)

Tim*_*own 70

constructor物业对内部任何事物都没有实际的区别.只有在您的代码明确使用它时,它才有用.例如,您可能决定需要每个对象都具有对创建它的实际构造函数的引用; 如果是这样,您需要constructor通过将对象分配给构造函数的prototype属性来设置继承时显式设置该属性,如您的示例所示.

  • @Raynos:我认为我会考虑依赖于`constructor`属性,正如所讨论的那样,有一个在脚本中被干扰的历史,并且没有用,对任何垫片都是不可接受的要求,不建议在任何垫片中使用它一般. (2认同)

小智 10

一个使用构造函数的情况:

  1. 这是继承的常见实现之一:

    Function.prototype.extend = function(superClass,override) {
        var f = new Function();
        f.prototype = superClass.prototype;
        var p = this.prototype = new f();
        p.constructor = this;
        this.superclass = superClass.prototype;
        ...
    };
    
    Run Code Online (Sandbox Code Playgroud)
  2. new f()不会调用superClass的构造函数,所以当你创建一个subClass时,你可能需要先调用superClass,如下所示:

    SubClass = function() {
        SubClass.superClass.constructor.call(this);
    };
    
    Run Code Online (Sandbox Code Playgroud)

所以构造函数属性在这里有意义.


T.J*_*der 5

此处的先前答案(以各种方式)说 constructor JavaScript 本身中的任何内容都未使用该属性的值。写这些答案时确实如此,但 ES2015 及以后的版本已开始 constructor 用于事物。

函数的 constructor 属性的prototype属性旨在指向函数,以便您可以询问对象是什么构造了它。它作为创建传统函数对象或类构造函数对象(详细信息)的一部分自动设置。

function TraditionalFunction() {
}

console.log(TraditionalFunction.prototype.constructor === TraditionalFunction); // true

class ExampleClass {
}

console.log(ExampleClass.prototype.constructor === ExampleClass); // true
Run Code Online (Sandbox Code Playgroud)

箭头函数没有prototype属性,因此它们没有prototype.constructor.

多年来,JavaScript 规范只说 constructor 默认情况下该属性将存在并具有该值(返回该函数的链接)。但是从 ES2015 开始,这种情况发生了变化,规范中的各种操作现在实际使用了该 constructor 属性,例如thisthisthisthis

因此,在设置构建继承链的构造函数时,最好确保该 constructor 属性引用适当的函数。有关示例等,请在此处查看我的答案