《JavaScript 高级程序设计》学习总结六(3)

引言:继承是面向对象语言中的一个最为人津津乐道的概念。许多面向对象都支持两种继承方式:接口继承与实现继承,接口继承只继承方法签名,而实现继承则继承实际的方法。如前所述,由于JavaScript 中函数没有签名,所以在ECMAScript 中无法实现接口继承。ECMAScript 只支持实现继承,而实现继承主要依靠原型链来实现的。

 

原型链:

概念:每个构造函数都要一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型对象的指针,那么假如我们让原型对象等于另一个类型的实例结果会怎么样呢?显然,此时的原型对象将包含一个指向另一个原型的指针,相应的,另一个原型中也包含着一个指向另一个构造函数的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实例与原型的链条。

说的太抽象了,我们直接看案例:实现原型链有一种基本模式:

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 的实例所拥有的全部属性和方法, 而且其内部还有一个指针,指向了 SuperType 的原型。最终结果就是这样的:instance 指向 SubType 的原型, SubType 的原型又指向 SuperType 的原型。 getSuperValue() 方法仍然还在 SuperType.prototype 中,但 property 则位于 SubType.prototype 中。这是因为 property 是一 个实例属性,而 getSuperValue()则是一个原型方法。既然 SubType.prototype 现在是 SuperType的实例,那么 property 当然就位于该实例中了。此外,要注意 instance.constructor 现在指向的 是 SuperType,这是因为原来 SubType.prototype 中的 constructor 被重写了的缘故(① 实际上,不是 SubType 的原型的 constructor 属性被重写了,而是 SubType 的原型指向了另一个对象—— SuperType 的原型( SubType.prototype = new SuperType()),而这个原型对象的 constructor 属性指向的是 SuperType。)。

 

别忘记默认的原型:

我们知道,所有引用类型默认都继承了 Object,而 这个继承也是通过原型链实现的。大家要记住,所有函数的默认原型都是 Object 的实例,因此默认原型都会包含一个内部指针,指向 Object.prototype。这也正是所有自定义类型都会继承 toString()、 valueOf()等默认方法的根本原因。所以,我们说上面例子展示的原型链中还应该包括另外一个继承层 次。

如图:

 

一句话,SubType 继承了 SuperType,而 SuperType 继承了 Object。当调用 instance.toString() 时,实际上调用的是保存在 Object.prototype 中的那个方法。

 

确定原型与实例的关系:

 确定原型和实例的关系 可以通过两种方式来确定原型和实例之间的关系。第一种方式是使用 instanceof 操作符。

第二种:是使用 isPrototypeOf()方法。同样,只要是原型链中出现过的原型,都可以说是该 原型链所派生的实例的原型,因此 isPrototypeOf()方法也会返回 true

举个例子:

alert(Object.prototype.isPrototypeOf(instance)); //true

 

谨慎地定义方法:

子类型有时候需要重写超类型中的某个方法,或者需要添加超类型中不存在的某个方法。但不管怎 样,给原型添加方法的代码一定要放在替换原型的语句之后。来看下面的例子

  

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; 
};

 //重写超类型中的方法
 SubType.prototype.getSuperValue = function (){
   return false;
 };
 var instance = new SubType();
 alert(instance.getSuperValue()); //false

 

加粗的部分是两个方法的定义。第一个方法 getSubValue()被添加到了 SubType 中。第二个方法 getSuperValue()是原型链中已经存在的一个方法,但重写这个方法将会屏蔽原来的 那个方法。换句话说,当通过 SubType 的实例调用 getSuperValue()时,调用的就是这个重新定义 的方法;但通过 SuperType 的实例调用 getSuperValue()时,还会继续调用原来的那个方法。这里 要格外注意的是,必须在用 SuperType 的实例替换原型之后,再定义这两个方法(也就是上面的://继承了 SuperType SubType.prototype = new SuperType(); )

 

PS :值得注意的是:通过原型链实现继承时2,不能用对象字面量创建原型方法,因为这样会重写原型链。比如我们将上面的代码改成

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 之间已经没有关系了。

 

原型链的问题

上一章节我们提到,原型模式的自身问题,那就是原型可以实现属性共享,而这也正是为什么要在构造函数中,而不是在原型对象中定义属性的原因。在通过原型来实现继承时,原型实际上会变成另一个类型的实例。于是,原先的实例属性也就顺理成章地变成了现在的原型属性了。举个例子:

 1 function SuperType(){ this.colors = ["red", "blue", "green"];
 2 
 3 }
 4 
 5 function SubType(){ }
 6 
 7 //继承了
 8 
 9 SuperType SubType.prototype = new SuperType();
10 
11 var instance1 = new SubType();
12 
13 instance1.colors.push("black");
14 
15 alert(instance1.colors); //"red,blue,green,black"
16 
17 var instance2 = new SubType(); alert(instance2.colors); //"red,blue,green,black"

  这个例子中的 SuperType 构造函数定义了一个 colors 属性,该属性包含一个数组(引用类型值)。 SuperType 的每个实例都会有各自包含自己数组的 colors 属性。当 SubType 通过原型链继承了 SuperType 之后,SubType.prototype 就变成了 SuperType 的一个实例,因此它也拥有了一个它自 己的 colors 属性——就跟专门创建了一个 SubType.prototype.colors 属性一样。但结果是什么 呢?结果是 SubType 的所有实例都会共享这一个 colors 属性。而我们对 instance1.colors 的修改 能够通过 instance2.colors 反映出来,就已经充分证实了这一点。

   原型链的第二个问题是:在创建子类型的实例时,不能向超类型的构造函数中传递参数。实际上, 应该说是没有办法在不影响所有对象实例的情况下,给超类型的构造函数传递参数。有鉴于此,再加上 前面刚刚讨论过的由于原型中包含引用类型值所带来的问题,实践中很少会单独使用原型链。

 

----------------------------------------------------------------------本章节完------------------------------------------------------------

下一章节预告:本章节我们总结学习了继承,同时也了解到原型链继承机制碰到的问题,那么这个问题我们会在下一章节进行学习总结。

(JavaScript的继承是这个语言的重点部分,我在写这篇博文时一直在想怎么总结才好,要不要自己用自己的理解与语言重写,纠结了好一会后自己写了一篇,但是不如人意,决定还是使用书中的文字,以后随着深入,再重开一篇单独讲继承。还有一个比较尴尬,我现在才发现博客的“插入代码”功能可以帮助更好的排版,所以我又得重新将前面的博文重新排版了)

 

转载于:https://www.cnblogs.com/wxhhts/p/9479926.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 《JavaScript高级程序设计》(第三版)是一本经典的JavaScript技术书籍。此书由Nicholas C. Zakas撰写,涵盖了广泛的主题,适合有一定JavaScript基础的读者。本书详细介绍了JavaScript语言的各个方面,包括基本语法、DOM操作、BOM操作、事件处理、Ajax、浏览器兼容性问题等。 这本书的优点之一是作者对JavaScript的深刻理解和独特的教学方法。他将复杂的概念和技术变得简单易懂,通过实际的例子和案例来解释和演示。读者可以通过跟随书中的练习和项目,逐渐提升自己的JavaScript编程能力。 此外,本书还包含了一些高级主题,如函数、闭包、面向对象编程等。这些主题对于想要深入理解JavaScript的读者来说十分有价值。此外,作者还介绍了一些最佳实践和优化技巧,帮助读者编写更高效、可维护的JavaScript代码。 《JavaScript高级程序设计》(第三版)最大的优点之一是其综合性。它涵盖了JavaScript的各个方面,并且通过详细的目录、索引和附录,方便读者在需要进行查找和参考。此外,书中还有大量的实例代码和详细的解释,使得读者能够更好地理解和应用所学的知识。 总结来说,《JavaScript高级程序设计》(第三版)是一本非常全面、详尽的JavaScript技术书籍。它不仅适合有一定基础的读者,也适合那些想要深入了解JavaScript编程的人。无论是作为学习教材还是作为参考书,这本书都是非常有价值的。阅读本书将有助于读者提升自己的JavaScript编程能力,并掌握一些高级技术和最佳实践。 ### 回答2: 《JavaScript高级程序设计(第三版)》是一本经典的JavaScript编程指南,由著名的JavaScript专家尼古拉斯·泽卡斯(Nicholas C. Zakas)撰写。该书自2009年首次出版以来,一直被广泛用作学习JavaScript的参考书籍。 这本书从基础知识讲起,逐渐引导读者深入了解JavaScript的各个方面。作者详细介绍了JavaScript的语法、数据类型、运算符、函数、对象、数组等核心概念,并通过大量的实例和案例进行讲解,帮助读者理解和应用这些知识。 《JavaScript高级程序设计(第三版)》特别关注JavaScript高级特性和最佳实践。作者深入浅出地讲解了闭包、原型链、作用域链等概念,并详细探讨了JavaScript的错误处理、异步编程和模块化等重要主题。读者通过学习这些内容,可以编写出更加高效、可维护和可扩展的JavaScript代码。 此外,书中还介绍了如何在浏览器环境和服务器环境中使用JavaScript,包括DOM操作、事件处理、Ajax、Web存储等技术。作者还对跨浏览器兼容性进行了讨论,帮助读者解决在不同浏览器中遇到的兼容性问题。 总之,《JavaScript高级程序设计(第三版)》是一本非常全面和权威的JavaScript学习资料。它适合初学者学习JavaScript的基础知识,也适合有一定经验的开发者深入了解和掌握JavaScript高级特性。无论是前端开发还是后端开发,读者都能从中获得宝贵的经验和知识。 ### 回答3: 《JavaScript高级程序设计》(第三版)是一本经典的JavaScript编程教材。该书由Nicholas C. Zakas撰写,对JavaScript的核心概念和高级技术进行了深入讲解。 该书主要分为三个部分。第一部分介绍了JavaScript语言的基础知识,包括语法、数据类型、流程控制、函数等内容。这一部分的目的是帮助读者建立对JavaScript基础的扎实理解,为后续的高级概念打下基础。 第二部分是该书的核心内容,讨论了JavaScript的面向对象编程和浏览器环境中的DOM操作。读者将学习使用构造函数、原型和继承等概念来开发复杂的JavaScript应用程序。此外,本书还给出了大量的示例代码和实践项目,帮助读者提升编程实战能力。 第三部分则涵盖了一些高级主题,如错误处理、数据存储、正则表达式、Ajax等。这些议题是现代Web开发中非常重要的部分,对于提升网页交互性和用户体验至关重要。 《JavaScript高级程序设计》(第三版)在内容上更为详尽全面,适合具备一定JavaScript基础的读者学习。此外,该书侧重于实践应用,深入浅出地讲解了一些复杂的概念,并通过实例和项目帮助读者学以致用。 总的来说,该书通过系统性的介绍和练习,帮助读者逐步掌握JavaScript的核心概念和高级技术,为他们成为出色的JavaScript开发者奠定坚实的基础。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值