可能重复:
Can a JavaScript object have a prototype chain, but also be a function?
我正在寻找一个可调用的JavaScript对象,使用任意原型链,但不修改Function.prototype。
换句话说,这必须起作用:
var o = { x: 5 };
var foo = bar(o);
assert(foo() === "Hello World!");
delete foo.x;
assert(foo.x === 5);
不做任何全局变更。
答案 0 :(得分:12)
没有什么可以阻止你向函数添加任意属性,例如。
function bar(o) {
var f = function() { return "Hello World!"; }
o.__proto__ = f.__proto__;
f.__proto__ = o;
return f;
}
var o = { x: 5 };
var foo = bar(o);
assert(foo() === "Hello World!");
delete foo.x;
assert(foo.x === 5);
我相信应该做你想做的事。
这可以通过将对象o
注入原型链来实现,但有几点需要注意:
__proto__
,或者甚至有一个等效的,一些评论,这看起来只适用于基于Firefox和Safari的浏览器(因此camino,chrome等工作)。< / LI>
o.__proto__ = f.__proto__;
仅对函数原型函数(如function.toString)非常必要,因此您可能只想跳过它,特别是如果您期望o
拥有有意义的原型。答案 1 :(得分:3)
我正在寻找一个可调用的JavaScript对象,使用任意原型链,但不修改Function.prototype。
我认为没有一种可移植的方法可以做到这一点:
您必须设置函数对象的[[Prototype]]属性或将[[Call]]属性添加到常规对象。第一个可以通过非标准__proto__
属性完成(参见olliej's answer),据我所知,第二个属性是不可能的。
[[Prototype]]只能在对象创建期间通过构造函数的prototype
属性进行设置。不幸的是,据我所知,没有JavaScript实现可以暂时重新分配Function.prototype
。
答案 2 :(得分:1)
我最接近的浏览器是这个(在FF,IE,Crome和Opera中测试过):
function create(fun,proto){
var f=function(){};
//Copy the object since it is going to be changed.
for (var x in proto)
f.prototype[x] = proto[x];
f.prototype.toString = fun;
return new f;
}
var fun=function(){return "Hello world";}
var obj={x:5}
var foo=create(fun,obj);
foo.x=8;
alert(foo); //Hello world
alert(foo.x); // 8
delete foo.x;
alert(foo.x); // 5
答案 3 :(得分:0)
你不能以便携的方式做到这一点。但是,如果您考虑一下,如果delete foo.x;
的目的是重置x
的值,您可以在reset()
上提供一个foo
方法,该方法会将缺少的属性恢复为他们的默认值。
// Object creation and initialisation
(foo=function()
{
alert("called");
}).reset = function()
{
if(!("x"in this)) this.x=42;
};
foo.reset();
// Using our callable object
alert(foo.x); // 42
foo(); alert(foo.x); // called; 42
foo.x=3; foo.reset(); alert(foo.x); // 3 [*]
delete foo.x; foo.reset(); alert(foo.x); // 42
(在Chromium和Internet Explorer中测试过,但这应该适用于所有浏览器。)
在标有[*]
的行中,对[{1}}的调用确实没有必要,但是它可以证明如果你不小心调用它并不重要,并且这可以推广到一个属性很容易。
请注意,在我们的可调用对象reset
的函数体中将引用包含范围,这可能对我们没有用,因为我们希望函数体访问对象成员。要缓解这个问题,请将其包装在一个这样的闭包中:
this