继承
许多面向对象语言都支持接口继承和实现继承两种方式,但是ECMAScript只支持实现继承,而且是依靠原型链来实现。
- 理解原型对象
function Person(){ Person.prototype.name = "Nicholas"; Person.prototype.age = 29; Person.prototype.job = "Software Engineer"; Person.prototype.sayName = function(){ alert(this.name); }; } var person1 = new Person(); var person2 = new Person(); alert(person1.sayName == person2.sayName); // true
- 只要创建了一个新函数,就会根据一组特定的规则为该函数创建一个prototype属性,这个属性指向函数的原型对象。在默认情况下,所有原型对象都会自动获得一个constructor(构造函数)属性,这个属性包含一个指向prototype 属性所在函数的指针。当调用构造函数创建一个新实例后,该实例对象的内部将包含一个指针(内部属性),指向构造函数的原型对象。Firefox、Safari 和Chrome 在每个对象上都支持一个属性__proto__;要明确的真正重要的一点就是,这个连接存在于实例与构造函数的原型对象之间,而不是存在于实例与构造函数之间。
总的来说,构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针constructor和其它添加的属性、方法,而实例都包含一个指向原型对象prototype的内部指针。 - 在我们调用
person1.sayName()
的时候,会先后执行两次搜索。首先搜索实例person1
是否有sayName
属性,如果没有就搜索person1
的原型。
虽然可以通过对象实例访问保存在原型中的值,但不能通过对象实例重写原型中的值。如果在实例中添加一个与实例原型属性同名的属性,那就会在实例中创建该属性,并屏蔽原型中的属性。person1.name = "Greg"; alert(person1.name); // "Grey"---来自实例 delete person.name; alert(person1.name); // "Nicholas"---来自原型 // 使用delete操作符删除了person1.name
- 我们可以通过isPrototypeOf()方法来确定对象之间是否存在这种关系
alert(Person.prototype.isPrototypeOf(person1)); //true
- ECMAScript 5 增加了一个新方法,叫Object.getPrototypeOf(),在所有支持的实现中,这个方法可以返回属性的值。Object.getPrototypeOf()可以方便地取得一个对象的原型,而这在利用原型实现继承的情况下非常重要。
alert(Object.getPrototypeOf(person1) == Person.prototype); //true alert(Object.getPrototypeOf(person1).name);
- 使用hasOwnProperty()方法可以检测一个属性是存在于实例中,还是存在于原型中。这个方法(从Object 继承来的)只在给定属性存在于对象实例中时,才会返回true。
alert(person1.hasOwnProperty("name"));
- 原型与
in
操作符:
由于in 操作符只要通过对象能够访问到属性就返回true,hasOwnProperty()只在属性存在于实例中时才返回true,因此只要in 操作符返回true 而hasOwnProperty()返回false,就可以确定属性是原型中的属性。alert("name" in person1); // true //两者同时使用就可知道该属性是存在对象中还是原型中 function hasPrototypeProperty(object, name){ return !object.hasOwnProperty(name) && (name in object); }
- 原型链
让原型对象等于另一个类型的实例,此时的原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。
定义两个类型SuperObj和SubObj,它们的主要区别是SuperObj继承了SubObj,而继承是通过创建SuperObj的实例,并将该实例赋给SubObj.prototype 实现的。实现的本质是重写原型对象,让原来存在于SuperObj的实例中的所有属性和方法,现在也存在于SubObj.prototype中了。function SuperObj(){ // this.a = 1; } SuperObj.prototype.getSuperValue = function(){ return this.a; } function SubObj(){ this.b = 2; } SubObj.prototype = new SuperObj();// 继承 SubObj.prototype.getSubValue = function(){ return this.b; } var obj = new SubObj(); console.log(obj.getSuperValue()); // 1