【问题标题】:Good way to change an object's prototype to change results of instanceof?更改对象原型以更改 instanceof 结果的好方法?
【发布时间】:2012-03-27 22:53:26
【问题描述】:

我想评论this old question,但它似乎被锁定了。

这是我的用例:

  1. 使用构造函数Base 创建对象objobj instanceof Base 返回 true。
  2. 我想更改obj 的原型,使其看起来好像obj 是从Derived 构造的。也就是说,我要
    • obj 访问Derived 的方法
    • obj instanceof Derived 返回真

原因是obj 在层次结构中有一个类型,该类型在创建时是未知的,并由之后发生的事情决定。我希望能够将其向下移动。

我相信我可以做到这一点

obj.__proto__ = Derived.prototype;

__proto__ 将在 JavaScript 的下一版本中被弃用。 proxies API,自从我上面链接的问题被问到之后发生了变化,似乎不支持我的用例。

对于我的用例,现在存在或计划在未来有替代实现吗?

我现在能看到的唯一选择是使用

obj2 = Object.create(Derived.prototype);
obj2.extend(obj);

并且永远不要存储多个对 obj 的引用,但这样的代价是相当不便的。

这是一个 fiddle 演示问题。

【问题讨论】:

  • __proto__already deprecated。对象的[[Prototype]]只能在构造的时候修改,之后不能修改链。
  • 好的......但它仍然在我的环境中可用。我正在寻找更便携的解决方案。你能帮忙吗?
  • 不推荐使用的东西不会从系统中删除,它基本上被标记为将来删除,因此不应使用。维护支持以便有时间修改使用已弃用功能的代码。
  • 是的,提这个有什么意义?我已经提到我目前依赖非便携式行为并且正在寻找替代方案。您的评论对讨论没有任何贡献。
  • 好的,您似乎很惊讶地发现一个已弃用的功能仍然可用,只是想我会解释一下。

标签: javascript ecmascript-5 ecmascript-harmony


【解决方案1】:

我认为不可能这样做。正如 RobG 所展示的,您可以通过 更改 损害类的 prototype 属性来使 instanceof 返回 false

看到这一点,我认为你可以通过额外的课程来做到这一点,你知道,就像常见的 Object.create shim 中的 F

Object.newChangeable = function create(b) {
    function F(){b.call(this);}
    F.prototype = b.prototype;
    var f = new F();
    f.change = function change(n) {
        F.prototype = n.prototype;
    };
    return f;
}

var obj = Object.newChangeable(Base);
obj instanceof Base; // true

obj.change(Derived);

但是没有

obj instanceof Derived; // still false
obj instanceof Base; // still true

因为obj 的内部[[Prototype]] 仍然与Base.prototype 指向相同。你可以做的是将Derived 变成新的Base

var obj = new Base;
obj instanceof Base; // true

Derived.prototype = Base.prototype;
Base.prototype = {}; // something else

alert(obj instanceof Derived); // true
alert(obj instanceof Base); // false

但我认为这不是您想要的,操纵表达式的右侧而不是更改 obj 的内容 :-)

【讨论】:

  • 好的,我想你可以在第一句话之后停下来。我会花更多时间来考虑其他想法,但如果没有其他人能提出解决方案,我会接受这一点。
【解决方案2】:

instanceof 运算符只检查构造函数的公共prototype 属性是否在对象的[[Prototype]] 链上。打破链条的一种方法是更改​​构造函数的原型:

function Base() {}

var base = new Base();

alert( base instanceof Base); // true

Base.prototype = {};

alert( base instanceof Base); // false
alert( base instanceof Object); // true

第二个警报是错误的,因为新的Base.prototype 不再位于base[[Prototype]] 链上(但原来的仍然存在)。请注意,Object.protoyype 仍然是。以上是instanceof 运算符未被视为特别有用的原因之一。

要做你想做的事,你必须在构造对象时创建[[Prototype]]链,因为你以后不能改变它:

Derived.prototype = new Base();

var base = new Derived();

alert(base instanceof Base); // true
alert(base instanceof Derived); // true

编辑

要求是:

  1. 对象 obj 是使用构造函数 Base 创建的。 obj instanceof Base 返回 true。

如图所示,这不一定是真的。如果您的策略依赖于 instanceof 返回特定值,那么您对设计施加了(可能不合理的)约束,没有明显的好处。

2。我想更改 obj 的原型,使其看起来好像 obj 是从 Derived 构造的。也就是说,我想要

•obj 来访问 Derived 的方法

您可以通过将 Base.prototype 设为 Derived 的实例(如图所示)或将属性复制到 Base.prototype 来做到这一点。

•obj instanceof 派生返回真

您可以通过将Base.prototype 设为Derived 的实例 创建任何Base 实例。

创建实例后不能修改链。如果您删除了instanceof 约束,那么您可以添加Derived.prototype 的方法,只需将它们复制到Base.prototype。另一种方法是使用 callapply

Derived.prototype.someMethod.call(base, ...);

但我怀疑你正在尝试做一些不可能的事情。

【讨论】:

  • 是的,我也会这样做。但我认为问题是关于特定实例的,这个解决方案改变了整个“类”的原型。
  • Bergi 是正确的。请参阅我添加到问题中的fiddle
  • 但是您的小提琴没有执行上述操作,它为 Derived 分配了一个新原型,但仍然创建了一个 Base 实例(它不会根据需要连接原型)。
  • Derived 获得分配的原型,以便它的实例将从 Base 派生。它改变了 obj 的原型链来完成我指定的两个条件。
【解决方案3】:

你是这个意思吗(对这个问题有点困惑,我还是个学习者)

function vehicle(name, color)
{
    if(this instanceof arguments.callee)
    {    
        this.name = name;
        this.color = color;
    }
    else return new arguments.callee(arguments);   
}

vehicle.prototype = {
    getName : function()
    {
        alert(this.name);
    } 
}

function Car(name, color, speed)
{
        this.name = name;
        this.color = color;
        this.speed = speed;
}

Car.prototype = vehicle();
var obj = new Car("Ford", "Red", "200mph");

obj.getName(); // alerts `Ford` using vehicle's/parent's method
alert(obj instanceof vehicle); alerts `True` instanceof vehicle's/parent's constructor

小提琴是here

John Resig的一篇文章。

【讨论】:

  • 不,问题是“如何制作new car() instanceof plane?”!
  • @Bergi,这里的 vehicle 是基础构造函数,而 car 是从 vehicle 派生的,而 Ford 是由 car 创建的对象,请问你这里的飞机是什么意思?
  • Sheikh,我以为我在原始问题中解释得很清楚,但我会再试一次:你创建了 obj 作为 Car 的实例。现在创建一个派生自 Car 的新类 Dragster,并更改 obj(但不是它从 Car 的构造),以便此表达式返回 true:“obj instanceof Dragster”
  • 让我掌握,很快就会回来。
  • 但是我不能在不改变 Car 的情况下为 Dragster 使用不同的原型,所以不,这不行。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 2021-10-19
  • 2012-12-18
  • 2016-02-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多