一个JavaScript对象可以有一个原型链,也可以是一个函数吗?

function a () { return "foo"; } ab = function () { return "bar"; } function c () { }; c.prototype = a; var d = new c(); db(); // returns "bar" d(); // throws exception, d is not a function 

有没有什么方法可以成为一个函数,但仍然inheritance属性?

简答:不可能。

这行代码:

 var d = new c(); 

自动假定d是一个对象。 除非c是一个内build对象的构造Function ,例如Function 。 但是,如果c已经被语言定义,那么就不能操纵它的原型,也不能从你喜欢的东西中“inheritance”它。 那么,在一些口译人员中,你可以做到,但是你不能在所有的口译人员中安全地做到这一点 – 标准说:“你们不要乱用标准物品,口译人员也会打你!”

内build的对象是“独特的”,JavaScript不提供复制它们的方法。 无法重新创buildstring,数字,函数等,而不采取不兼容的欺骗手段。

其实,事实certificate,这是可能的 ,虽然以非标准的方式。

Mozilla,Webkit,Blink / V8,Rhino和ActionScript提供了非标准的__proto__属性,允许在创build对象后更改对象的原型。 在这些平台上,以下代码是可能的:

 function a () { return "foo"; } ab = function () { return "bar"; } function c () { return "hatstand"; } c.__proto__ = a; c(); // returns "hatstand" cb(); // returns "bar"; inherited from a 

这对任何不需要担心跨平台兼容性的人都是有用的。

但是请注意,只有对象的属性才能被inheritance。 例如:

 var d = {}; d.__proto__ = a; db(); // returns "bar" d(); // throws exception -- the fact that d is inheriting from a function // doesn't make d itself a function. 

是的,如果你使用Daniel Cassidy提到的__proto__属性是可能的。 诀窍是让c实际上返回一个已经附加到它的原型链的函数。

 function a () { return "foo"; } ab = function () { return "bar"; } function c () { var func = function() { return "I am a function"; }; func.__proto__ = a; return func; } c.prototype = a; var d = new c(); db(); // returns "bar" d(); // returns "I am a function" 

但是,如果您希望instanceof返回更好的结果,则需要对原型链进行一些调整。

 d instanceof c // true d instanceof a // false c instanceof a // false 

它是否必须实际上是一个原型链? 你可以使用混合模式来使一个函数具有所有的属性。 如果你真的想要的话,你甚至可以用一个很好的“新”语法来包装它。

 function a () { return "foo"; } ab = function () { return "bar"; } function c () { var f = function(){ return a(); }; //mixin all properties on a for(var prop in a){ f[prop] = a[prop]; } return f; //just returns the function instead of "this" }; var d = new c(); //doesn't need the new keyword, but just for fun it still works alert(d()); //show "foo" alert(db()); //shows "bar" 

您可以将属性添加到d,而不会影响。 这和你想要的唯一区别是对a的改变不会影响c的现有“实例”。

基于对关于类似问题的 meta的讨论,我在@ alexander-mills原始发布这个答案


现在可以按照符合标准的方式完成

首先创build一个inheritanceFunction的对象

 const obj = Object.create(Function.prototype); // Ensures availability of call, apply ext 

然后将自定义方法和属性添加到obj

接下来声明该函数

 const f = function(){ // Hello, World! }; 

并设置obj作为f的原型

 Object.setPrototypeOf(f,obj); 

Demonstraction

 const obj = Object.create(Function.prototype); // Define an 'answer' method on 'obj' obj.answer = function() { // Call this object this.call(); // Logs 'Hello, World' console.log('The ultimate answer is 42'); } const f = function() { // Standard example console.log('Hello, World'); }; Object.setPrototypeOf(f, obj); // 'f' is now an object with an 'answer' method f.answer(); // But is still a callable function f(); 

这是我现在一直在尝试做的事情。 特别感谢上述作者的意见。

这是一个使用“可调用对象”的链式实现:

 var $omnifarious = (function(Schema){ var fn = function f(){ console.log('ran f!!!'); return f; }; Schema.prototype = { w: function(w){ console.log('w'); return this; }, x: function(x){ console.log('x'); return this; }, y: function(y){ console.log('y'); return this; } }; fn.__proto__ = (new Schema()).__proto__; return fn; })(function schema(){ console.log('created new schema', this); }); console.log( $omnifarious()().w().x().y()()() ); 

另外,通过这种“Schema”方法,可以在Schemaprototype__proto__对象上使用Object.freeze()创build一个可重用的interface 。 这可能看起来像这样: fn.__proto__ = Object.freeze(new Schema().__proto__) – 这不是一个实际的例子,可能需要更多。 这就是说,这是一个不同的讨论。 试试看,让我知道!

希望这是有帮助的。