繁体   English   中英

如何访问原型上的阴影JavaScript对象字段?

[英]How to access a shadowed JavaScript object field on the prototype?

使用以下ES2015(ES6)类定义:

class Card {
    constructor(val) {
        this.val = val;
    }
    val(){
        return this.val;
    }
}

(或等效的ES5和更早的代码)

但是,执行以下方法调用:

new Card(val).val()

抛出TypeError: Card.val is not a function

Card.x.call(Card)

似乎有同样的问题。

鉴于两个名称应该保持不变,我如何正确引用原型的val方法而不是对象的val字段?

我只是试图获得灵感,我们可以有效地避免javascript中的这种冲突,假设我们必须以这种方式命名它们。

为了避免混淆,我们不妨将val你对原型“原val ”,并在构造“实例分配一个val ”。

您不能在对象(“实例val ”)上拥有与其原型(“proto val ”)上的属性同名的属性,并直接通过对象引用访问它们,获取一个或另一个取决于在背景上。 这不是JavaScript的功能。 这是JavaScript属性查找工作方式的固有特性,而JavaScript的“方法”只是引用函数的属性。

下面的选项,但让我们更仔细地看看为什么“实例val ”覆盖“proto val ”:

使用上述代码的任何更正版本,此行:

var c = new Card(42);

在内存中给我们这个(省略了一些细节):

+------------------------------------------+
      |                                          |
      \   +------------+                         |
Card>--+->| (function) |                         |
          +------------+       +-------------+   |
          | prototype  |>---+->|  (object)   |   |
          +------------+   /   +-------------+   |
                           |   | constructor |>--+   +------------+
                           |   | val         |>----->| (function) |
                           |   +-------------+       +------------+ 
                           |
      +---------------+    |
c>--->|   (object)    |    |
      +---------------+    |
      | [[Prototype]] |>---+
      | val: 42       |
      +---------------+

标识符Card (实际上是变量)是指一个函数。 该函数的prototype属性是指我们将“proto val ”方法置于其上的对象。 变量c指的是一个实例,它具有规范所谓的“内部插槽”,称为[[Prototype]] ,它指的是它的原型,它是我们在制作new Card时从Card.prototype获得的。 原型具有指向方法的val属性,以及指向返回功能Card指向的constructor属性。

当我们要求JavaScript引擎在c查找val属性时,它会在c引用的对象上找到它,并从那里使用它; “实例val ”已经覆盖了“proto val ”。 如果“实例val ”不在那里,JavaScript引擎将无法在对象c上找到它并且会查看对象的原型(对象的[[Prototype]]内部插槽指向的内容),然后它会找到指向该函数的val属性。 但“实例val ”正在阻碍。

你基本上有三个选择:

  1. 做你说过你不想做的事情:给他们不同的名字。 例如,data属性(“instance val ”)可以是_val ,或者方法(“proto val ”)可以是getVal (因为方法名称通常应该是动词),或者两者都是(这很常见)等等。

  2. 在构造函数中创建val方法,并且根本没有val数据属性:

     // ES2015 (ES6) and higher class Card { constructor(val) { this.val = function() { return val; }; } } 

    要么

     // ES5 and earlier function Card(val) { this.val = function() { return val; }; } 

    由于数据val根本不再是实例上的属性,因此与方法val没有冲突。

    这是有效的,因为val方法现在是对Card调用的上下文的闭包,因此它具有对val参数的持久访问。 但是,没有原型方法可以直接访问它; 他们必须使用this.val()来获取它。

  3. 做你现在正在做的事情并在原型而不是实例上查找“proto val ”:

     var c = new Card(val).val() Object.getPrototypeOf(c).val.call(c); // ES5+ 

    (不太可靠)

     var c = new Card(val).val() Card.prototype.val.call(c); 

    (甚至不太可靠)

     var c = new Card(val).val() c.constructor.prototype.val.call(c); 

    ......正如你所看到的那样,这很痛苦。 它起作用,因为在那些例子中我没有在c上查找“proto val ”(因为“实例val ”在路上); 我直接在c的原型上查找(当然,在第一个例子中; 可能在第二个例子中; 希望在第三个例子中)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM