Dan*_*don 101 javascript function-prototypes
假设我的foo
JavaScript代码中有一个对象. foo
是一个复杂的对象,它是在其他地方生成的.如何更改foo
对象的原型?
我的动机是将适当的原型设置为从.NET到JavaScript文字序列化的对象.
假设我在ASP.NET页面中编写了以下JavaScript代码.
var foo = <%=MyData %>;
Run Code Online (Sandbox Code Playgroud)
假设这MyData
是在对象JavaScriptSerializer
上调用.NET的结果Dictionary<string,string>
.
在运行时,这将变为以下内容:
var foo = [{"A":"1","B":"2"},{"X":"7","Y":"8"}];
Run Code Online (Sandbox Code Playgroud)
如您所见,foo
成为一个对象数组.我希望能够foo
使用适当的原型进行初始化.我不是要修改Object.prototype
,也没有Array.prototype
.我怎样才能做到这一点?
小智 111
编辑2012年2月:以下答案不再准确.__proto__作为"规范可选"添加到ECMAScript 6中,这意味着它不需要实现,但如果是,则必须遵循给定的规则集.目前尚未解决,但至少它将成为JavaScript规范的正式部分.
这个问题比表面看起来要复杂得多,并且超出了大多数人对Javascript内部知识的薪酬等级.
在prototype
创建该对象的新的子对象时,对象的属性使用.更改它不会反映在对象本身中,而是在该对象用作其他对象的构造函数时反映,并且无法用于更改现有对象的原型.
function myFactory(){};
myFactory.prototype = someOtherObject;
var newChild = new myFactory;
newChild.__proto__ === myFactory.prototype === someOtherObject; //true
Run Code Online (Sandbox Code Playgroud)
对象具有指向当前原型的内部[[prototype]]属性.它的工作方式是每当调用一个对象上的属性时,它将从该对象开始,然后通过[[prototype]]链向上,直到它找到匹配,或者在根对象原型之后失败.这就是Javascript允许运行时构建和修改对象的方式; 它有一个搜索它需要的计划.
该__proto__
属性存在于某些实现中(现在很多):任何Mozilla实现,我所知道的所有webkit,以及其他一些.此属性指向内部[[prototype]]属性,并允许在对象上创建后创建.由于链式查找,任何属性和函数都会立即切换到与原型匹配.
此功能虽然现在已经标准化,但仍然不是JavaScript的必需部分,并且在支持它的语言中很有可能将代码转换为"未优化"类别.JS引擎必须尽最大努力对代码进行分类,特别是经常访问的"热门"代码,如果你正在做一些像修改那样花哨的东西__proto__
,它们根本不会优化你的代码.
这篇文章https://bugzilla.mozilla.org/show_bug.cgi?id=607863专门讨论__proto__
了它们之间的当前实现和差异.每个实现都以不同的方式执行,因为它是一个困难且未解决的问题.Javascript中的所有内容都是可变的,除了a.)语法b.)主机对象(DOM在技术上存在于Javascript之外)和c.)__proto__
.其余部分完全掌握在您和其他所有开发人员的手中,因此您可以看到为什么__proto__
像拇指疼痛一样突出.
有一件事情是__proto__
允许的,否则不可能做到:在运行时指定对象原型与其构造函数分开.这是一个重要的用例,也是__proto__
尚未死亡的主要原因之一.重要的是它在Harmony的制定中是一个严肃的讨论点,或者很快被称为ECMAScript 6.在创建过程中指定对象原型的能力将成为下一版Javascript的一部分,这将是钟声表明__proto__
日子正式编号.
在短期内,您可以使用,__proto__
如果您的目标是支持它的浏览器(不是IE,也不会是IE).由于ES6将在2013年之前完成,因此它可能会在未来10年内在webkit和moz中运行.
Brendan Eich - re:ES5中新对象方法的方法:
抱歉,...但是可设置
__proto__
,除了对象初始化用例(即,在一个尚未到达的新对象上,类似于ES5的Object.create),这是一个可怕的想法.我__proto__
在12年前设计并实现了可设置的这个....缺乏分层是一个问题(用密钥考虑JSON数据
"__proto__"
).更糟糕的是,可变性意味着实现必须检查循环原型链以避免ilooping.[需要不断检查无限递归]最后,
__proto__
对现有对象进行变异可能会破坏新原型对象中的非泛型方法,这些方法不可能对__proto__
正在设置的接收方(直接)对象起作用.这通常是一种不好的做法,一种故意类型混淆的形式.
Tim*_*Tim 14
您可以constructor
在对象的实例上使用来就地更改对象的原型.我相信这就是你要做的事情.
这意味着如果你有foo
一个实例Foo
:
function Foo() {}
var foo = new Foo();
Run Code Online (Sandbox Code Playgroud)
您可以通过执行以下操作bar
向所有实例添加属性Foo
:
foo.constructor.prototype.bar = "bar";
Run Code Online (Sandbox Code Playgroud)
这是一个显示概念验证的小提琴:http://jsfiddle.net/C2cpw/.不是很确定老浏览器将如何使用这种方法,但我很确定这应该做得很好.
如果您打算将功能混合到对象中,那么此代码段应该可以完成以下任务:
function mix() {
var mixins = arguments,
i = 0, len = mixins.length;
return {
into: function (target) {
var mixin, key;
if (target == null) {
throw new TypeError("Cannot mix into null or undefined values.");
}
for (; i < len; i += 1) {
mixin = mixins[i];
for (key in mixin) {
target[key] = mixin[key];
}
// Take care of IE clobbering `toString` and `valueOf`
if (mixin && mixin.toString !== Object.prototype.toString) {
target.toString = mixin.toString;
} else if (mixin && mixin.valueOf !== Object.prototype.valueOf) {
target.valueOf = mixin.valueOf;
}
}
return target;
}
};
};
Run Code Online (Sandbox Code Playgroud)
你可以做到foo.__proto__ = FooClass.prototype
,Firefox,Chrome和Safari支持的AFAIK.请记住,该__proto__
物业是非标准的,可能会在某些时候消失.
文档:https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Object/proto.另请参阅http://www.mail-archive.com/jsmentors@googlegroups.com/msg00392.html以获取解释为何没有Object.setPrototypeOf()
以及为何__proto__
弃用的原因.
归档时间: |
|
查看次数: |
71752 次 |
最近记录: |