更改对象原型以更改instanceof结果的好方法?

时间:2012-03-27 22:53:27

标签: javascript ecmascript-5 ecmascript-harmony

我想对this old question发表评论,但似乎已被锁定。

这是我的用例:

  1. 使用构造函数obj创建对象Baseobj instanceof Base返回true。
  2. 我想更改obj的原型,使其看起来好像obj是从Derived构建的。那就是我想要的
    • obj可以访问Derived
    • 的方法
    • obj instanceof Derived返回true
  3. 原因是obj在层次结构中有一个类型,它在创建时是未知的,并由之后发生的事情决定。我希望能够将其移到层次结构中。

    我相信我可以用

    做到这一点

    obj.__proto__ = Derived.prototype;

    __proto__将在下一版本的JavaScript中弃用。 proxies API自上面提到的问题以来发生了变化,但似乎不支持我的用例。

    我的用例是否有替代实现,现在或计划在将来使用?

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

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

    并且永远不会存储多个对obj的引用,但是这个成本非常不方便。

    以下是展示此问题的fiddle

3 个答案:

答案 0 :(得分:3)

我认为不可能这样做。正如RobG所演示的那样,你可以通过更改使类false属性返回prototype

看到这一点,我认为你可以通过一个额外的课程来完成它,就像来自普通F垫片的Object.create一样:

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的内部[[原型]]仍指向与Base.prototype相同。您可以做的是DerivedBase

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处的东西: - )

答案 1 :(得分:1)

instanceof 运算符只检查构造函数的public 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不再位于[[Prototype]] base链上(原来的那个仍然存在)。请注意,Object.protoyype仍然是。以上是instanceof运算符不被视为特别有用的一个原因。

要执行您要执行的操作,您必须在构造对象时创建[[Prototype]]链,因为您以后无法更改它:

Derived.prototype = new Base();

var base = new Derived();

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

修改

要求是:

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

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

  

2。我想改变obj的原型,好像obj是从Derived构造的。也就是说,我想要

     

•obj可以访问Derived方法

你可以通过使Base.prototype成为Derived的实例(如图所示)或将属性复制到Base.prototype来实现。

  

•obj instanceof Derived返回true

您可以在创建 Base 的任何实例之前,通过Base.prototype 派生 的实例来实现这一目标。

创建实例后无法修改链。如果您放弃instanceof约束,则只需将Derived.prototype复制到Base.prototype即可添加Derived.prototype.someMethod.call(base, ...); 方法。另一种方法是使用调用应用

{{1}}

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

答案 2 :(得分:0)

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

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的文章。