JS中的对象之原型
对象
ECMAScript做为一个高度抽象的面向对象语言,是通过_对象_来交互的。即使ECMAScript里边也有_基本类型_,但是,当需要的时候,它们也会被转换成对象。
一个对象就是一个属性集合,并拥有一个独立的prototype(原型)对象。这个prototype可以是一个对象或者null。
var foo={ x: 10, y:20 };
我们拥有一个这样的结构,两个明显的自身属性和一个隐含的_proto_属性,这个属性
是对foo原型对象的引用:
这些prototype有什么用?让我们以_原型链_(prototype chain)的概念来回答这个问题。
原型链
原型对象也是简单的对象并且可以拥有它们自己的原型。如果一个原型对象的原型是一个非null的引用,那么以此类推,这就叫作_原型链_。
原型链是一个用来实现继承和共享属性的有限对象链。
ECMAScript中没有类的概念。但是,代码重用的风格并没有太多不同(尽管从某些方面来说比基于类(class-based)的方式要更加灵活)并且通过_原型链_来实现。这种继承方式叫作_委托继承_(delegation based inheritance)(或者,更贴近ECMAScript一些,叫作_原型继承_(prototype based inheritance))。
var a = { x: 10, calculate: function(z) { return this.x + this.y; } } ; var b = { y:20, _proto_:a }; var c = { y: 30, _proto_:a } // call the inherited method b.calculate(30); //60 c.calculate(40); //80
这样我们通过将a作为一个属性值赋值给b, c的_proto_属性;
足够简单,这就是通过原型链实现的。
看看规则:如果一个属性或者方法在_自身_中无法找到(也就是说是对象自身没有一个那样的属性),然后他就会尝试在原型链中寻找这个属性/方法。如果这个属性没有在原型中找到,那么将会查找这个原型的原型,以此类推,遍历整个原型链(当然这在类继承中也是一样的,当解析一个继承的_方法_的时候-我们遍历_class链_( class chain))。第一个被查找到的同名属性/方法会被使用。因此,一个被查找到的属性叫作_继承_属性。如果在遍历了整个原型链之后还是没有查找到这个属性的话,返回undefined
值。
注意,继承方法中所使用的this
的值被设置为_原始_对象,而并不是在其中查找到这个方法的(原型)对象。也就是,在上面的例子中this.y
取的是b
和c
中的值,而不是a
中的值。但是,this.x
是取的是a
中的值,并且又一次通过_原型链_机制完成。
如果没有明确为一个对象指定原型,那么它将会使用__proto__
的默认值-Object.prototype
。Object.prototype
对象自身也有一个__proto__
属性,这是原型链的_终点_并且值为null
。