一尘不染

如何设置已经实例化的JavaScript对象的原型?

javascript

假设我的fooJavaScript代码中有一个对象。 foo是一个复杂的对象,它在其他地方生成。如何更改foo对象的原型?

我的动机是为从.NET到JavaScript文字序列化的对象设置适当的原型。

假设我已经在ASP.NET页面中编写了以下JavaScript代码。

var foo = <%=MyData %>;

假设这MyData是在对象JavaScriptSerializer上调用.NET的结果Dictionary<string,string>

在运行时,它将变为以下内容:

var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];

如您所见,foo成为对象的数组。我希望能够foo使用适当的原型进行初始化。我 不是
要修改Object.prototype,也没有Array.prototype。我怎样才能做到这一点?


阅读 232

收藏
2020-05-01

共1个答案

一尘不染

编辑2012年2月:下面的答案不再准确。 __proto__被作为“标准可选”添加到ECMAScript
6中,这意味着它不需要实施,但如果要实施,则必须遵循给定的规则集。目前尚无定论,但至少它将正式成为JavaScript规范的一部分。

这个问题比表面上看起来要复杂得多,而且就Java组件内部知识而言,这超出了大多数人的薪水等级。

prototype创建该对象的新的子对象时,对象的属性使用。更改它不会反映在对象本身中,而是在将该对象用作其他对象的构造函数时反映出来,并且在更改现有对象的原型时没有用。

function myFactory(){};
myFactory.prototype = someOtherObject;

var newChild = new myFactory;
newChild.__proto__ === myFactory.prototype === someOtherObject; //true

对象具有指向当前原型的内部[[prototype]]属性。它的工作方式是:只要调用对象的属性,它将从该对象开始,然后遍历[[prototype]]链,直到在根Object原型之后找到匹配项或失败为止。这就是Javascript允许运行时构建和修改对象的方式。它有一个搜索所需内容的计划。

__proto__属性存在于某些实现中(现在有很多):任何Mozilla实现,我所知道的所有Webkit实现,其他一些实现。此属性指向内部[[prototype]]属性,并允许在对象创建后进行修改。由于这种链式查找,任何属性和功能都将立即切换以匹配原型。

此功能虽然现在已标准化,但仍不是JavaScript的必需部分,并且在支持该功能的语言中,很有可能会将您的代码归为“未优化”类别。JS引擎必须尽最大努力对代码进行分类,尤其是经常访问的“热”代码,如果您正在做诸如修改之类的事情__proto__,它们将根本无法优化您的代码。

专门讨论的当前实现__proto__以及它们之间的区别。每个实现都有不同的实现方式,因为这是一个棘手且尚未解决的问题。Java语言中的所有内容都是可变的,除了a。)语法b。)宿主对象(DOM在技术上不在Javascript之外)和c。)__proto__。其余的一切完全掌握在您和所有其他开发人员的手中,因此您可以看到为什么__proto__伸出来就像拇指酸痛一样。

有一件事情__proto__可以做到,而这在其他方面是不可能做到的:在运行时指定对象原型与其构造函数分开。这是一个重要的用例,也是__proto__尚未死亡的主要原因之一。非常重要的一点是,这已成为和声制定中的一个重要讨论点,或即将被称为ECMAScript6。在创建过程中指定对象原型的能力将成为下一版Javascript的一部分,而这将是表示__proto__日期的铃铛已正式编号。

在短期内,__proto__如果您要定向支持它的浏览器(不是IE,而且永远不会有IE),就可以使用。由于ES6直到2013年才能最终定稿,因此它可能会在接下来的10年中在webkit和moz中使用。

很抱歉,但是可设置__proto__,除了对象初始化程序的用例之外(例如,在尚无法访问的新对象上,类似于ES5的Object.create),这是一个可怕的想法。我写这是__proto__在12年前设计并实现可设置的。

…缺乏分层是一个问题(考虑JSON数据和一个key"__proto__")。更糟糕的是,可变性意味着实现必须检查循环原型链,以避免循环。需要不断检查无限递归

最后,__proto__在现有对象上进行更改可能会破坏新原型对象中的非泛型方法,而该方法可能无法在__proto__正在设置其的接收者(直接)对象上工作。通常,这只是一种不好的做法,是一种故意的类型混淆。

2020-05-01