3

我想评论这个老问题,但它似乎被锁定了。

这是我的用例:

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

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

我相信我可以做到这一点

obj.__proto__ = Derived.prototype;

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

我的用例是否有替代实现现在存在或计划在未来实现?

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

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

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

这是一个演示这个问题的小提琴。

4

3 回答 3

3

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

看到这一点,我认为你可以通过额外的课程来做到这一点,你知道,就像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

因为内部的 [[Prototype]]obj仍然指向同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:-)

于 2012-03-28T00:50:14.093 回答
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的不在[[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. 对象 obj 是使用构造函数 Base 创建的。obj instanceof Base 返回 true。

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

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

•obj 以访问 Derived 的方法

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

•obj instanceof 派生返回true

您可以通过在创建任何Base实例之前创建DerivedBase.prototype实例来做到这一点。

创建实例后,您无法修改链。如果您放弃instanceof约束,那么您可以Derived.prototype通过简单地将方法复制到Base.prototype. 另一种方法是使用callapply

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

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

于 2012-03-28T00:09:48.953 回答
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

小提琴在这里

John Resig的一篇文章。

于 2012-03-27T23:55:27.753 回答