[英]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
”正在阻碍。
你基本上有三个选择:
做你说过你不想做的事情:给他们不同的名字。 例如,data属性(“instance val
”)可以是_val
,或者方法(“proto val
”)可以是getVal
(因为方法名称通常应该是动词),或者两者都是(这很常见)等等。
在构造函数中创建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()
来获取它。
做你现在正在做的事情并在原型而不是实例上查找“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.