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