这里有新鲜出炉的 Javascript 教程,程序狗速度看过来!
Javascript 是一种由 Netscape 的 LiveScript 发展而来的原型化继承的基于对象的动态类型的区分大小写的客户端脚本语言,主要目的是为了解决服务器端语言,比如 Perl,遗留的速度问题,为客户提供更流畅的浏览效果。
原型链是 JavaScript 中继承的主要方法。本文重点给大家介绍 JavaScript 基于原型链的继承,非常不错,具有参考借鉴价值,感兴趣的朋友一起学习吧
Javascript 并不是一门面向对象的语言,没有提供传统的继承方式,但是它提供了一种原型继承的方式,利用自身提供的原型属性来实现继承。
原型链是 JavaScript 中继承的主要方法。
原型链的基本思想是:利用原型让一个引用类型继承另一个引用类型的属性和方法。
构造函数、原型和实例的关系:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的内部指针。
如果让原型对象等于另一个对象的实例,这样原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数的指针。
实现原型链的基本模式:
- function SuperType() {
- this.property = true;
- }
- SuperType.prototype.getSuperValue = function() {
- return this.property;
- };
- function SubType() {
- this.subproperty = false;
- }
- // 继承SuperType
- SubType.prototype = new SuperType();
- SubType.prototype.getSubValue = function() {
- return this.subproperty;
- };
- var instance = new SubType();
- alert(instance.getSuperValue()); // true
SubType 继承了 SuperType, 继承是通过创建 SuperType 的实例,并将该实例赋给 SubType.prototype 实现的。实现的本质是重写原型对象,换成一个新类型的实例。这样,原来存在于 SuperType 的实例中的属性和方法,也存在与 SubType.prototype 中了。然后给 SubType.prototype 添加一个方法,这样就继承了 SuperType 的属性和方法的基础上又添加了一个方法。
上例中的实例关系表示如下:
上面没有使用 SubType 默认提供的原型,而是给它换了一个新原型;这个新原型就是 SuperType 的实例。新原型内部还有一个执行 SuperType 的原型的指针。结果变成了 instance 指向 SubType 的原型,SubType 的原型又指向 SuperType 的原型。getValue() 方法仍然还在 SuperType.prototype 中,但 prototype 则位于 SubType.prototype 中。这是因为 property 是一个实例属性,而 getSuperValue() 则是一个原型方法。既然 SubType.prototype 现在是 SuperType 的实例,那么 property 自然位于该实例中。
注意:instance.constructor 现在指向的是 SuperType,因为 SubType 的原型指向了另一个对象——SuperType 的原型,这个原型对象的 constructor 属性指向的是 SuperType。
当以读取模式访问一个属性时,首先会在实例中搜索该属性。如果没有找到该属性。则会继续搜索实例的原型。通过原型链实现继承的情况下,搜索过程就得以沿着原型链继续向上。
默认的原型
所有引用类型都默认继承了 Object,而这个继承也是通过原型链实现的。所有函数的默认原型都是 Object 的实例。因此默认原型都会包含一个内部指针,指向 Object.prototype。这就是为什么自定义类型都会继承 toString()、valueOf() 等方法的原因。
完整的原型链:
在上面的继承体系中,SubType 继承了 SuperType,SuperType 继承了 Object。当调用了 instance.toString() 时,实际调用的是保存在 Object.prototype 中的那个方法。
确定实例和原型的关系
可以通过两种方式来确定原型和实例之间的关系:
使用 instanceof 操作符
- alert(instance instanceof Object);
- alert(instance instanceof SuperType);
- alert(instance instanceof SubType);
由于原型链的关系,上面全部返回 true。
使用 isPrototypeOf() 方法
- alert(Object.prototype.isPrototypeOf(instance));
- alert(SuperType.prototype.isPrototypeOf(instance));
- alert(SubType.prototype.isPrototypeOf(instance));
谨慎定义方法
给原型添加方法的代码一定要放在替换原型的语句之后。
- function SuperType() {
- this.property = true;
- }
- SuperType.prototype.getSuperValue = function() {
- return this.property;
- };
- function SubType() {
- this.subproperty = false;
- }
- SuperType.prototype = new SuperType();
- // 添加方法
- SubType.prototype.getSubValue = function() {
- return this.subproperty;
- };
- // 覆盖超类中的方法
- SubType.prototype.getSuperValue = function() {
- return false;
- };
- var instance = new SubType();
- alert(instance.getSuperValue()); // false
上面的例子必须注意的是,在用 SuperType 的实例替换原型之后,再定义那两个方法。
另外,在通过原型链实现继承时,不能使用该对象字面量创建原型方法。因为这样做会重写原型链:
- function SuperType() {
- this.property = true;
- }
- SuperType.prototype.getSuperValue = function() {
- return this.property;
- };
- function SubType() {
- this.subproperty = false;
- }
- // 继承SuperType
- SubType.prototype = new SuperType();
- // 使用字面量添加新方法,导致上一行代码无效
- SubType.prototype = {
- getSubValue: function() {
- return this.subproperty;
- },
- someOtherMethod: function() {
- return false;
- }
- };
- var instance = new SubType();
- alert(instance.getSuperValue()); // error
上例将 SuperType 的实例赋值给原型,紧接着又将原型替换成一个对象字面量而导致的问题。现在的原型包含一个 Object 的实例,而非 SuperType 的实例,SubType 和 SuperType 之间已经没有关系了。
原型链的问题
前面已经介绍过,包含引用类型值得原型属性会被所有实例共享;而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。
- function SuperType() {
- this.colors = ["red", "blue", "green"];
- }
- function SubType() {
- }
- SubType.prototype = new SuperType();
- var instance1 = new SubType();
- instance1.colors.push("black");
- alert(instance1.colors); // "red", "blue", "green", "black"
- var instance2 = new SubType();
- alert(instance2.colors); // "red", "blue", "green", "black"
在上面的例子中,SuperType 构造函数中定义了一个 colors 属性,该属性包含一个数组,SuperType 的每个实例都会有各自包含自己数组的 colors 属性。当 SubType 通过原型链继承了 SuperType 之后,SubType.prototype 就变成了 SuperType 的一个实例,所以它也拥有了一个它自己的 colors 属性。但是,SubType 的所有实例都会共享这一个 colors 属性。
另一问题是,没有办法在不影响所有对象实例的情况下,给超类的构造函数传递参数。
以上所述是小编给大家介绍的 JavaScript 基于原型链的继承 的相关知识,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 phperz 网站的支持!
来源: http://www.phperz.com/article/17/0405/264639.html