Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/javascript/473.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Javascript构造函数属性的意义是什么?_Javascript_Prototype_Constructor - Fatal编程技术网

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

Javascript构造函数属性的意义是什么?,javascript,prototype,constructor,Javascript,Prototype,Constructor,试图绕过Javascript对OO的理解……和其他许多人一样,对构造函数属性感到困惑。特别是构造函数属性的重要性,因为我似乎无法使它产生任何效果。例如: 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

试图绕过Javascript对OO的理解……和其他许多人一样,对
构造函数
属性感到困惑。特别是
构造函数
属性的重要性,因为我似乎无法使它产生任何效果。例如:

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`.
在上面的示例中,对象
b
似乎具有名为(
Bar
)的正确构造函数,并且它从
Foo
继承了age属性。那么,为什么许多人认为这是一个必要的步骤:

Bar.prototype.constructor = Bar;

显然,在构造
b
时调用了正确的
构造函数,那么这个原型属性有什么影响呢?我很想知道正确设置构造函数属性实际上会有什么实际区别,因为我看不出它对创建对象后实际调用哪个构造函数有任何影响。

2020年9月更新

下面的答案来自ECMAScript 3的时代,第一句话不再正确,因为自ECMAScript 6以来,
构造函数
属性在一些地方使用。不过,我认为总的要点仍然适用。感谢T.J.Crowder在评论中指出了这一点,请阅读他的答案,以更全面地了解当前的情况

原始答案


构造函数
属性对内部任何内容都没有实际意义。只有当代码显式使用它时,它才有任何用处。例如,您可能决定需要每个对象都有一个对创建它的实际构造函数的引用;如果是这样,您需要在通过将对象分配给构造函数的
prototype
属性来设置继承时显式设置
constructor
属性,如您的示例所示。

第一步是了解
构造函数和
prototype
都是关于什么的。这并不难,但我们必须放弃古典意义上的“继承”

构造函数


constructor
属性不会在程序中产生任何特定的影响,除非您可以查看它以查看哪个函数与操作符
new
一起用于创建对象。如果您键入
newbar()
它将是
Bar
,并且您键入
newfoo
它将是
Foo

原型

prototype
属性用于查找相关对象没有要求的属性的情况。如果您编写
x.attr
,JavaScript将尝试在
x
的属性中查找
attr
。如果找不到它,它将在
x.\uu proto\uu
中查找。如果它也不在那里,只要定义了
\uuuuuu proto\uuuuuuu,它就会在
x.\uuuuuuu proto\uuuuuuuuu
中查找

那么什么是
\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?简而言之,
prototype
表示“类型”,而
表示“实例”。(我用引号表示,因为类型和实例之间实际上没有任何区别)。当您编写
x=new MyType()
时,发生的事情(除其他外)是
x.\uuuu proto\uuuuuuu
设置为
MyType.prototype

问题

现在,以上应该是你所需要的全部来推导你自己的例子的意思,但要尝试并回答你的实际问题;“为什么要写这样的东西”:

Bar.prototype.constructor=Bar

我个人从未见过它,我觉得它有点傻,但在您给出的上下文中,它将意味着
Bar.prototype
-对象(使用
new Foo(42)
创建)将假装是由
Bar
创建的,而不是
Foo
。我想这是一种类似于C++/Java/C#类语言的想法,在这种语言中,类型查找(构造函数
属性)总是产生最具体的类型,而不是原型链中更高级的更通用对象的类型

我的建议是:不要过多考虑JavaScript中的“继承”。接口和混合的概念更有意义。不要检查对象的类型。检查所需的属性(“如果它走路像鸭子,嘎嘎叫像鸭子,那它就是鸭子”)


试图强迫JavaScript进入一个经典的继承模型,而它所拥有的只是上述的原型机制,这是造成混淆的原因。许多建议手动设置
构造函数
-属性的人可能正是这样做的。抽象是很好的,但是构造函数属性的手动赋值不是JavaScript的惯用用法。

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

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

    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;
        ...
    };
    
  • 这个
    new f()
    不会调用超类的构造函数,所以在创建子类时,可能需要先调用超类,如下所示:

    SubClass = function() {
        SubClass.superClass.constructor.call(this);
    };
    
    function Foo(age) {
        this.age = age;
    }
    
    function Bar() {
        this.name = "baz"; 
    }
    
    Bar.prototype = new Foo(42); 
    var one = new Bar();
    console.log(one.constructor);   // 'Foo'
    var two = new Foo();
    console.log(two.constructor);   // 'Foo'
    

  • 因此构造函数属性在这里有意义。

    构造函数属性指向用于创建对象实例的构造函数。如果您键入“new Bar()”,它将是“Bar”,而您键入“new Foo()”,它将是“Foo”

    但是,如果您在不设置构造函数的情况下设置原型,则会得到如下结果:

    SubClass = function() {
        SubClass.superClass.constructor.call(this);
    };
    
    function Foo(age) {
        this.age = age;
    }
    
    function Bar() {
        this.name = "baz"; 
    }
    
    Bar.prototype = new Foo(42); 
    var one = new Bar();
    console.log(one.constructor);   // 'Foo'
    var two = new Foo();
    console.log(two.constructor);   // 'Foo'
    
    要将构造函数实际设置为用于创建对象的构造函数,我们还需要在设置prototype时设置构造函数,如下所示:

    function Foo(age) {
        this.age = age;
    }
    
    function Bar() {
        this.name = "baz"; 
    }
    
    Bar.prototype = new Foo(42); 
    Bar.prototype.constructor = Bar;
    var one = new Bar();
    console.log(one.constructor);   // 'Bar'
    var two = new Foo();
    console.log(two.constructor);   // 'Foo'
    

    当您希望
    prototype.constructor
    属性在
    prototype
    属性重新分配后继续存在时,其中一个用例是在
    prototype
    上定义一个方法,该方法生成与给定实例相同类型的新实例。例子: