一个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”方法,可以在Schema
的prototype
或__proto__
对象上使用Object.freeze()
创build一个可重用的interface
。 这可能看起来像这样: fn.__proto__ = Object.freeze(new Schema().__proto__)
– 这不是一个实际的例子,可能需要更多。 这就是说,这是一个不同的讨论。 试试看,让我知道!
希望这是有帮助的。