使用函数作为原型

使用JavaScript,可以使用一个函数作为原型,例如

function Foo(){ } Foo.prototype = function(){ } 

还是需要使用

 Foo.prototype = { }; 

更重要的是,它有重要的区别吗?

是的,由于JavaScript原型inheritance的灵活性,两种方法都是允许的。 首先让我们来看看这两种情况下的原型链。 我只考虑简单的文字对象。

Object.prototype vs函数原型

Object.prototype (internal [[Prototype]]的最后一个值是使用literal创build的对象,最终是Object.prototype 。 例如:

 /*Example 1*/ var o = { foo: 1, bar: 2 } Prototypical chain: o -> Object.prototype /*Example 2*/ var o = { foo: 1, bar: 2 } o.__proto__ = { another:3 } Prototypical chain: o ->o.__proto__ -> Object.prototype 

对于函数, Object.prototype的最后一个值也是Object.prototype ,除了它始终有一个前面的值Function.prototype 。 例如:

 /*Example 1*/ function Foo () { return xyz; } Prototypical chain: Foo -> Function.prototype -> Object.prototype /*Example 2*/ function Foo () { return xyz; } Foo.prototype = { another:3 } Prototypical chain: Foo -> Foo.prototype -> Function.prototype -> Object.prototype 

对于选项1:

 function Foo(){ } Foo.prototype = function(){ } 

按照上面的讨论,原型链将是Foo -> Function.prototype -> Object.prototype

对于选项2:

 function Foo(){ this.name = 'bar'; } Foo.prototype = { } 

原型链将是Foo -> Object.prototype

对于这两种情况,原型链是有效的,并且inheritance无疑是正确的。

任何对象都可以是原型。 原型可以是一个普通的旧对象,或者一个函数或一个数组,这两个对象都是对象,也可以是其他任何对象,包括正则expression式和甚至date,更不用说包装数字,string和布尔值等基本元素的对象。

但是当人们谈论使用一个函数作为原型时,他们通常打算或希望能够以某种方式从实例化的对象访问该函数, 但是他们不能 。 实例在原型上查找属性 ,无论是数组还是date,还是正则expression式或函数或普通旧对象,但是它们都不能访问原型对象的“主体”,在这种情况下基于数字或string的对象称为PrimitiveValue

这里有一些例子可能会使它更清晰,使用Object.create基于原型创build对象的最简单情况。

 // plain old object prototype prototype = { a: 42 }; obj = Object.create(prototype); obj.a // 42 // array as prototype array = [ 1, 2 ]; obj = Object.create(array); array.a = 42 obj.a // 42 // NO WAY TO ACCESS [1, 2] from obj regexp = /foo/; regexp.a = 42 obj = Object.create(regexp) obj.a // 42 // NO WAY TO ACCESS regexp from obj > number = Object(22) > number.a = 42 > obj = Object.create(number) > obj.a // 42 // NO WAY TO ACCESS PRIMITIVE VALUE 22 FROM obj 

现在我们来看一下函数的例子。 与其他types的对象一样

 fn = function() { }; fn.a = 42; obj = Object.create(fn) obj.a // 42 // NO WAY TO ACCESS fn from obj 

但是,由于fn有自己的原型,包括调用等方法, obj也inheritance了这些。 所以定义了obj.call 。 但是,调用它会导致错误,因为obj不是可以调用的函数。

 > obj.call() < Uncaught TypeError: obj is not a function 

所以得出的结论是,使用一个函数作为原型没有什么特别的错误或非法的; 没有理由。