JavaScript面向对象

JavaScript面向对象


资料:《JavaScript+jQuery交互式Web前端开发》 黑马程序员编著


文中有错的地方请及时提醒,谢谢!

效果图:

代码分享:

html和js代码:

<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>JavaScript面向对象</title>
	<link rel="stylesheet" type="text/css" href="js_Class.css" />
</head>
	<p style="font-size: 20px;text-align: center;font-weight: bold">JavaScript面向对象</p>
	<h3>JavaScript面向对象(ES6)</h3>
	<p>面向对象是软件开发领域中非常重要的一种编程思想,尤其在大型项目设计中可以发挥巨大的作用。面向对象思想是计算机百年城技术发展到一定阶段后的产物,已经日趋成熟,并被广泛应用到数据库系统、交互式界面、应用平台、分布式系统、网络管理结构、人工智能等其他领域。</p>
	<ul><li>面向对象概述</li></ul>
	<p class="one1">
		<span class="one2">面向过程和面向对象</span>
		面向过程:面向过程就是分析出解决问题需要的步骤,然后用函数把这些步骤一步步实现,使用的时候依次调用。
		
		面向对象:面向对象就是把需要解决的问题分解成一个个对象,建立对象不是为了实现一个步骤,而是为了描述每个对象在解决问题中的行为。面向对象的核心是对象。
		
		面向过程思想注重的是具体的步骤,只有按照步骤一步一步地执行,才能够完成这件事情;而面向对象思想注重的是一个个对象,这些对象各司其职,只要找到相应的对象做具体的事情即可。
		
		<span class="one2">面向对象的优势和特征</span>
		在面向过程思想中,白那些的代码都是一些变量和函数,随着程序功能的不断增加,变量和函数就会越来越多,此时容易遇到命名冲突的问题。由于各种功能的代码交织在一起,导致代码结构混乱,变的难以理解、维护和复用。
		而面向对象思想,可以将同一类事物的操作代码封装成对象,将用到的变量和函数作为对象的属性和方法。然后通过对象去调用,这样可以使代码结构清晰、层次分明。因此,在团队中,使用面向对象思想编程可以帮助团队更好地写作分工,提高开发效率。
		需要注意的是,面向对象编程没有面向过程的性能高,因为面向对象为了提高开发效率增加了一些额外开销,在提高开发效率的同时稍微降低了性能。但大部分情况下,开发效率的重要性远远超过了面向对象带来的性能开销,如果不是在对性能要求极其苛刻
		的情况下,推荐使用面向对象进行项目开发。
		
		优势:1、模块化更深,封装性强;2、更容易实现复杂的业务逻辑;3、更易维护、易复用、易扩展。
		
		特征:面向对象的特征主要可以概括为封装性、继承性和多态性。
		1、封装性:封装指的是隐藏内部的实现细节,只对外开放操作接口。接口就是对象的方法,无论对象的内部多么复杂,用户只需直到这些接口怎么使用即可。封装的优势在于,无论一个对象内部的代码经过了多少次修改,只要不改变接口,就不会影响到使用
		这个对象时编写的代码。
		2、继承性:继承是指一个对象继承另一个对象的成员,从而在不改变另一个对象的前提下进行扩展。 在开发中,利用继承一方面可以在保持接口兼容的前提下对功能进行扩展,另一方面增强了代码的复用性,为程序的修改和补充提供便利。
		3、多态性:多态指的是同一个操作作用于不同的对象,会产生不同的执行结果。实际上JavaScript被设计成一种弱类型语言(即一个变量可以存储任何类型的数据),就是多态性的体现。在面向对象中,多态性的实现往往离不开继承,因为继承可以让所有的
		同类对象拥有相同的方法,然后每个对象可以再根据自己的特点来改变同名方法的执行结果。
		
		虽然面向对象提供了封装、继承、多态这些设计思想,但并不表示只要满足这些特征就可以设计出优秀的程序,开发人员还需要考虑如何合理地运用这些特征。例如,在封装时,如何给外部调用者提供完整且最小的接口,使外部调用者可以顺利得到想要的
		功能,不需要研究其内部的细节;在进行继承和多态设计时,如何为同类对象设计一套相同的方法进行操作等。
		
	</p>
	<ul><li>ES6面向对象语法:在传统的面向对象语言(如Java)中,都存在类的概念,类就是对象的模板,对象就是类的实例。JavaScript从ES6(ECMAScript6.0)版本开始,也加入了类的概念,增加了一些面向对象语法。</li></ul>
	<p class="one1">
		<span class="one2">类和对象:</span>面向对象让程序更贴近实际生活,使用面向对象可以通过代码来描述现实世界的事物。事物分为具体的事物(对象)和抽象的事物(类)。类的作用是将对象的特征抽象出来,形成一段代码。用一个已经写好的类,可以批量地创建同一类对象,不同的类
		创建出来的就是不同类的对象。步骤:1、抽取出对象共同的属性和行为,组织成一个类。2、对类进行实例化,获取类的对象。
		
		创建同类对象的意义在于,这些同类对象拥有相同的属性名和方法名(即拥有相同的特征),当使用一个对象的时候,只要知道这个对象是哪个类的,就知道这个对象如何使用了。
		
		<span class="one2">类的基本语法:</span>ES6中增加了class关键字,用来定义一个类,在类中可以定义constructor()构造方法,用来初始化对象的成员。语法:class 类名{constructor(参数){//初始化对象成员}},其中,constructor()构造方法在使用类创建对象时会自动调用,调用时
		会将实例化的参数传递过来。在命名习惯上,类名使用首字母大写的形式。如果一个类中没有编写constructor()构造方法,程序会在类中自动创建一个constructor()构造方法。
		
		<span class="one2">类中的方法:</span>语法:class 类名{方法名(){} 方法名(){}},在定义方法时,不需要使用function关键字,并且多个方法之间不需要使用逗号分隔。在方法中,this表示实例对象。
		
		<span class="one2">继承和super关键字</span>
		继承:现实生活中,继承一般指的是子女继承父辈的财产。而在JavaScript中,继承用来表示两个类之间的关系,子类可以继承父类的一些属性和方法,在继承以后还可以增加自己独有的属性和方法。类的继承使用extends关键字。
		
		super关键字:super关键字用于访问和调用对象在父类上的方法,可以调用父类的构造方法,也可以调用父类的普通方法。语法:构造方法:super();普通方法:super.父类方法名();其中,在子类的构造函数中调用父类的构造方法时,
		super必须放在this的前面,否则会报错。也就是说,子类必须先调用父类的构造方法,才能继续执行自己的构造方法。
		
	</p>
	<h3>JavaScript面向对象(ES6之前)</h3>
	<p>上节介绍了ES6的面向对象编程思想,以及类的基本使用。这节介绍ES6之前,在开发中如何实现面向对象编程的。内容包括构造函数和原型对象的使用、原型链的结构、this指向问题、程序的错误处理,最后介绍如何利用构造函数和原型对象实现子类继承父类的属性和方法。</p>
	<ul><li>构造函数和原型对象:在ES6之前,JavaScript并没有引入类的概念,若要使用JavaScript进行面向对象编程,需要通过构造函数和原型对象来实现。</li></ul>
	<p class="one1">
		<span class="one2">构造函数:</span>构造函数主要用来创建对象,并未对象的成员赋初始值。可以把对象中的一些公共属性和方法抽取出来,封装到构造函数中。语法:function Person(参数列表){this.属性名=参数;this.属性名=参数;this.方法名=function(){};}
		
		<span class="one2">静态成员和实例成员:</span>在面向对象中有静态成员和实例成员的概念,实例成员是指实例对象的成员,而静态成员是通过类或构造函数访问的成员,不需要创建实例对象就能访问。如:Person.school='大学';Person.school;需要注意的是,在静态方法中不能使用this访问实例对象,因为静态方法与实例对象没有关联,在静态方法如果使用this,访问到的是构造函数本身,即Person。
		
		<span class="one2">构造函数和类的区别:</span>使用构造方法创建对象虽然简单、方便、但是与类存在一定的区别。类中的成员方法是定义在类中的,使用类创建对象后,这些对象的方法都是引用了同一个方法,这样可以节省内存空间,而使用构造函数创建的对象并不是引用同一个方法。
		
		<span class="one2">原型对象:</span>原型对象就是解决使用构造函数创建引用的不是同一个方法的问题。在JavaScript中,每个构造函数都有一个原型对象存在,这个原型对象通过构造函数的prototype属性来访问。利用原型对象,可以实现为所有的实例对象共享方法,可以将实例方法定义在原型对象中,然后所有的实例方法就可以访问原型对象的方法了。原型对象其实就是所有实例对象的原型。如:Person.prototype.sayHello=function(){};p1.sayHello===p2.sayHello;
		
	</p>
	<ul><li>原型链:在JavaScript中,对象有原型对象,原型对象也有原型对象,这就形成了一个链式结构,简称原型链。</li></ul>
	<p class="one1">
		<span class="one2">访问对象的原型对象和构造函数</span>
		访问对象的原型对象:在JavaScript中,每个对象都有一个__proto__属性,这个属性指向了对象的原型对象。如果知道了一个对象的构造函数,可以用构造函数的prototype属性访问原型对象。如果不知道对象的构造函数,可以用__proto__属性直接访问原型
		对象。如:p1.__proto__;注意:__proto__是一个非标准的属性,是浏览器为了方便用户查看对象的原型而提供的,在实际开发中不推荐使用这个属性。
		
		访问对象的构造函数:在原型对象里面有一个constructor属性,该属性指向了构造函数。由于实例对象可以访问原型对象的属性和方法,所以通过实例对象的constructor属性就可以访问实例对象的构造函数。如:p1.constructor;注意:如果将构造函数的
		原型对象修改为另一个不同的对象,就无法使用constructor属性访问原来的构造函数了。例:function Person(){} Person.prototype={say:function(){//内容}},此时,p1.constructor访问的结果是Object构造函数。因为Person.prototype赋值了一个新的
		字面量对象。可以在新的原型对象中将constructor属性指向Person构造函数。如:Person.prototype={constructor:Person,say:function({//内容})};
		
		<span class="one2">原型对象的原型对象:</span>原型对象也是对象,这个对象应该也会有一个原型对象存在。Person.prototype.__proto__的对象其实就是Object.prototype对象,这个对象是所有Object实例对象的原型对象。由此可见,JavaScript中,原型对象与原型对象是像链条
		一样连起来的,这个链条的尽头的对象就是Object.prototype。
		
		<span class="one2">绘制原型链:</span>原型链的结构:1、每个构造函数都有一个prototype属性指向原型对象。2、原型对象通过constructor属性指向构造函数。3、通过实例对象的__proto__属性可以访问原型对象。4、Object的原型对象的__prototype__属性为null。
		
		函数的构造函数:在JavaScript中,函数可以像对象一样拥有属性和方法,所以函数也是对象。函数的构造函数是Function()函数,而Function()函数的构造函数是它本身。实例化Function构造函数的方式创建函数:new Function('参数1','参数2',······'参数N',
		'函数体');其中,参数数量是不固定的,最后一个参数表示用字符串保存的新创建函数的函数体,前面的参数(数量不固定)表示新创建函数的参数名称。
		
		<span class="one2">成员查找机制:</span>当访问一个实例对象的成员的时候,JavaScript首先会判断实例对象有没有这个成员,如果有,就直接使用,如果没有,再判断原型对象中有没有这个成员。如果在原型对象中找到了这个成员,就使用,没有找到,就继续查找原型对象的
		原型对象,如果直到最后都没有找到,则返回undefined。注意:成员查找机制只对访问操作有效,对于添加或修改操作,都是在当前对象中进行的。
		
	</p>
	<ul><li>this指向:在JavaScript中,函数有多种调用的环境,如直接通过函数名调用、作为对象的方法调用、作为构造函数调用等。根据函数不同的调用方式,函数中的this指向会发生改变。</li></ul>
	<p class="one1">
		<span class="one2">分析this指向:</span>1、构造函数内部的this指向新创建的对象。2、直接通过函数名调用函数时,this指向的是全局对象window。3、如果将函数作为对象的方法调用,this将会指向该对象。4、静态方法中调用,指向构造函数。
		
		<span class="one2">更改this指向:</span>除了遵循默认的this指向规则,函数的调用者还可以利用JavaScript提供的两种方式手动控制this的指向。一种是通过apply(对象,[数组参数])方法,另一种是通过call(对象,参数列表)方法。apply()和call()方法的区别在于第2个参数。
		apply()的第2个参数表示调用函数时传入的参数,通过数组的形式传递;而call()则使用第2~N个参数来表示调用函数时传入的函数。
		
		bind()方法:bind()方法的含义是绑定,用于在调用函数前制定this的含义,实现提前绑定的效果,在绑定时,还可以提前传入调用函数时的参数。如:function method(a,b){};var test=method.bind({name:'李四'},'3','4');后可以通过test()访问。
		通过bind()绑定后,其返回值test用来代替method()函数,在调用test()时this指向绑定时传入的对象。
		
	</p>
	<ul><li>错误处理:在Java等传统面向对象语言中,人们引入了异常(Exception)的概念,利用try...catch进行异常处理。JavaScript也提供了和异常处理类似的错误处理机制,同样可以使用try...catch语法进行错误处理。</li></ul>
	<p class="one1">
		<span class="one2">如何进行错误处理:</span>在编写JavaScript程序时,经常会遇到各种各样的错误,如调用了不存在的方法、引用了不存在的变量等。例:o.func();,从控制台上可以看到未捕获的错误类型和错误提示。当发生错误时,JavaScript引擎会抛出一个错误对象,
		利用try...catch语法可以对错误对象进行捕获,捕获后可以查看错误信息。当try中的代码发生错误时,利用catch可以进行错误处理。注意:如果try中有多行代码,只要其中一行出现错误,后面的代码都不会执行;如果错误已经被处理,则catch后面的代码
		会继续执行。由此可见,编写在try中的代码量应尽量减少,从而避免错误发生时造成的影响。
		
		<span class="one2">错误对象的传递:</span>在发生错误时,错误出现的位置、错误的类型、错误信息等数据,都会以一个对象的形式传递给catch语句,通过catch(e)的方式来接受,其中e是错误对象的变量名。错误对象会在函数之间传递。当try中的代码调用了其他函数时,如果在
		其他函数中出现发现了错误,且没有使用try...catch处理时,程序就会停下来,将错误传递到调用当前函数的上一层函数,如果上一层函数仍然没有处理,则继续向上传递。
		
		<span class="one2">抛出错误对象:</span>除了在JavaScript程序中出现错误时自动抛出错误对象,用户也可以使用throw关键字手动抛出错误对象,例:throw new Error('错误信息');Error对象是错误对象的构造函数,通过它可以创建一个自定义的错误对象,其参数表示错误信息。
		在通过catch捕获后,通过e.message可以获取错误信息。
		
		<span class="one2">错误类型:</span>在JavaScript中,共有7种标准错误类型,每个类型都对应一个构造函数。当发生错误时,JavaScript会根据不同的错误类型抛出不同的错误对象。其中,在通过try...catch来处理错误时,无法处理语法错误(SyntaxError)。如果程序存在语法错误,
		则整个代码都无法执行。该行代码的前面还有其他代码也不会执行。
		<p style="text-align: center">错误类型</p>
		<table align="center">
			<tr bgcolor="#C0C0C0">
				<th>类型</th>
				<th>说明</th>
			</tr>
			<tr>
				<td>Error</td>
				<td>表示普通错误,其余6种类型的错误对象都继承自该对象</td>
			</tr>
			<tr>
				<td>EvalError</td>
				<td>调用eval()函数错误,已经弃用,为了向后兼容,低版本还可以使用</td>
			</tr>
			<tr>
				<td>RangeError</td>
				<td>数值超出有效范围,如"new Array(-1)"</td>
			</tr>
			<tr>
				<td>ReferenceError</td>
				<td>引用了一个不存在的变量,如"var a=1;a+b;"(变量b未定义)</td>
			</tr>
			<tr>
				<td>SyntaxError</td>
				<td>解析过程语法错误,如"{;}" "if()" "var a=new;"</td>
			</tr>
			<tr>
				<td>TypeError</td>
				<td>变量或参数不是与其类型,如调用了不存在的函数或方法</td>
			</tr>
			<tr>
				<td>URIError</td>
				<td>解析URI编码出错,调用了encodeURI()、escape()等URI处理函数时出现</td>
			</tr>
		</table>
	</p>
	<ul><li>继承:在ES6之前,JavaScript中并没有extends继承,如果要实现继承的效果,可以通过构造函数和原型对象来模拟实现。</li></ul>
	<p class="one1">
		<span class="one2">借用构造函数继承父类属性:</span>在ES6中,继承时通过定义两个类,然后子类用extends关键字继承父类。而在ES6之前,只能用构造函数来代替类,在子类中利用call()方法将父类的this指向子类的this,这样就可以实现子类继承父类的属性。
		如:function Father(uname,age){} function Son(uname,age,score){Father.call(this,uname,age)}
		
		<span class="one2">利用原型对象继承父类方法:</span>若要实现继承父类的方法,可以将父类的实例对象作为子类的原型对象来使用,然后将这个新的原型对象的constructor属性指向子类。
		如:function Father(){}; function Son(){}; 1、Son.prototype=new Father(); 2、Son.prototype.constructor=Son;
		
		class语法的本质:ES6提供了class语法用来定义类,即使没有class语法,在JavaScript中可以用构造函数和原型对象的语法来替代。类和构造函数的使用非常相似,可以互相替代。实际上,ES6中的类的大部分功能,都可以用ES5来实现,
		新的class语法只是让代码更加清晰,更加接近传统的面向对象编程语言。在实际开发中,使用新语法虽然在开发的时候很方便,但是旧的浏览器不支持。为了兼容旧版本的浏览器,通常会借助一些工具(如Gulp、Babel)来自动将新语法转换为旧语法。
		
	</p>
	<hr size="2px" color="blue" />
	<p style="text-align: center;font-size: 16px;font-weight: bold;">未完待续...</p>
<body>
</body>
</html>

css代码:

@charset "utf-8";
/* CSS Document */

.one1 {
	white-space: pre;
	margin-top:-20px;
	margin-bottom:-20px;
}

.one2 {
	color: red;
	font-style: italic;
	font-weight: bold;
}

table{
	border: 1px solid #6B3435;
	border-collapse: collapse;
}
th,td{border: 1px solid #6B3435;white-space: pre;}

.beforeImg:before {
	content: url("arrow.jpg");
}

.beforeImg {
	text-indent: 8em;
	white-space: pre;
}

未完待续,敬请期待...

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值