【问题标题】:Why is JavaScript prototype property undefined on new objects?为什么 JavaScript 原型属性未在新对象上定义?
【发布时间】:2013-01-05 05:18:56
【问题描述】:

我对 JavaScript 的原型概念还很陌生。

考虑以下代码:

var x = function func(){
}

x.prototype.log = function() {
  console.log("1");
}

var b = new x();

据我了解,b.log() 应该返回 1,因为 x 是它的原型。但是为什么b.prototype这个属性是未定义的呢?

b.prototype 不应该返回对x 函数的引用吗?

【问题讨论】:

标签: javascript prototype


【解决方案1】:

只有构造函数有原型。由于x 是一个构造函数,所以x 有一个原型。

b 不是构造函数。因此,它没有原型。

如果你想获得构造b(在本例中为x)的函数的引用,你可以使用

b.constructor

【讨论】:

  • 彼得,你有什么关于阅读所有 JS 对象模型的书/在线资源的建议吗?
  • @VictorPiousbox 最精确和最详细的来源是ECMAScript specification,但如果您不习惯阅读这类内容,可能很难阅读。除此之外,我只会使用搜索引擎搜索信息。
  • 在阅读了这么多文章说每个对象都有原型之后,我认为即使是从函数(使用 new)创建的对象也有一个!但现在我明白了。
  • w3schools.com/js/js_object_prototypes.asp 说“每个 JavaScript 对象都有一个原型。原型也是一个对象。”你说的答案与你所说的只有构造函数有原型有什么矛盾
【解决方案2】:

函数的.prototype 属性只是用于在函数作为构造函数调用时在新对象上设置继承。

当新对象被创建时,它的内部[[Prototype]]属性被设置为函数的.prototype属性指向的对象。

对象本身没有获得.prototype 属性。它与对象的关系完全是内部的。

这就是为什么它可以做b.log()。当 JS 引擎看到 b 对象本身没有 log 属性时,它会尝试在对象内部 [[Prototype]] 对象上查找它,并成功找到它。

需要明确的是,[[Prototype]] 属性不可直接访问。它是一个内部属性,只能通过 JS 引擎提供的其他构造间接可变。

【讨论】:

    【解决方案3】:

    JavaScript 中的所有普通对象都有一个内部原型槽(注意:这里的原型不是指原型属性)。 ECMAScript 标准 (http://www.ecma-international.org/ecma-262/6.0/index.html) 指定此插槽称为 [[Prototype]]。您可以通过 __proto__ 属性访问此插槽。

    __proto__ 可能无法可靠地跨浏览器使用。 __proto__ 成为 ECMAScript 6 中的官方属性

    然而,原型属性是构造函数上的一个属性,它设置构造对象上的 __proto__ 属性。

    您可以访问某些类型的原型属性,例如核心 JavaScript 类型(日期、数组等)。还有一个 JavaScript 函数(可以看作是一个构造函数)有一个公共的原型属性。但是,函数的实例没有原型属性。

    在你的情况下,var b = new x();, b 是函数 x 的一个实例。因此 b.prototype 是未定义的。但是,b 确实有一个内部 [[Prototype]] 插槽。如果您在 Google Chrome 中输出 b.__proto__,例如版本 63.0.3239.132,或 Firefox,例如版本 43.0.4

    console.log(b.__proto__);
    

    你会看到它的 [[Prototype]] 槽如下:

    {log: ƒ, constructor: ƒ}
    

    就是这样。


    仅供参考,整个代码sn-p如下:

    var x = function() {
    };
    x.prototype.log = function() {
      console.log("1");
    }
    
    var b = new x();
    b.log();  // 1
    
    console.log(b.prototype); // undefined
    console.log(b.__proto__); // {log: ƒ, constructor: ƒ}
    console.log(x.prototype); // {log: ƒ, constructor: ƒ}
    

    【讨论】:

    • 构造函数默认为隐藏属性。我说得对吗?
    • @Atul,不确定您是否指的是 Object.prototype.constructor。 constructor 属性返回对创建实例对象的 Object 构造函数的引用。您可以访问它,例如,var c = new x.prototype.constructor();var d = new b.__proto__.constructor();
    【解决方案4】:

    在浏览您的代码之前,我想确定一些原型概念,这些概念是理解您的代码行为所必需的。

    1. [[prototype]] 是 JavaScript 对象的隐藏属性。此隐藏属性只不过是到 Object.prototype(如果由对象文字创建)的链接。没有标准方法可以访问此 [[prototype]] 属性。
    2. JavaScript 中的函数是对象,所以它们也有[[prototype]] 属性。在这里,如果是函数,这个隐藏的属性是指向Function.prototype 的链接。也没有标准方法可以访问这个[[prototype]] 属性。李>
    3. 除了这个隐藏链接[[prototype]]之外,每当创建函数对象时,都会在其中创建一个prototype属性,该属性与隐藏的[[prototype]]属性是分开的。

    现在来到你的代码:

    var x = 函数 func(){}

    当这一行执行时,一个函数对象x 被创建了两个链接:

    • Function.prototype(不可访问),
    • x.prototype(可访问)。

    x.prototype.log = function() { 控制台.log("1"); }

    我们现在知道x 是一个函数对象,所以x.prototype 是可访问的,因此您可以在此处包含日志方法。

    var b = new x();

    b 是一个对象,但不是函数对象。它有那个隐藏的链接[[prototype]],但它是不可访问的。因此,当您尝试像b.prototype 一样访问时,它会给出undefined。如果您想检查b 的原型而不是看到(x.prototype).isPrototypeOf(b);,它将返回true。所以你可以说隐藏链接引用了x.prototype

    以下是关于原型的一些事实:

    1. 如果对象O 是用O = new func(){} 创建的,那么O[[prototype]] 就是Function.prototype
    2. 如果对象O是用O = {}创建的,那么O[[prototype]]就是Object.prototype
    3. 如果对象O 是用O = Object.create(obj) 创建的,那么O[[prototype]] 就是obj

    【讨论】:

      【解决方案5】:

      因为prototype 是函数(实际上是构造函数)的属性,因为它定义了此类对象(从该原型所属的构造函数创建的对象)的属性/方法。看看this link

      【讨论】:

        猜你喜欢
        • 2012-01-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-04-14
        • 1970-01-01
        • 2021-11-10
        • 1970-01-01
        • 2016-02-26
        相关资源
        最近更新 更多