从零开始,学习web前端之js高级

面向对象

在学习js的面向对象的时候着实懵逼了,因为之前学过java,发现js的面向对象简直太扯淡了。但是没办法,还是要耐着性子学一学,不过有了ECMAScript6之后,相信以后学过强类型语言的同学再去学习js的面向对象会好一些。


首先要明确的是,面向对象是一种解决问题的思路,是一种编程思想。

早期的编程是面向过程的。“面向过程”(Procedure Oriented)是一种以过程为中心的编程思想。就是把解决问题的关注点,放到解决问题的每一个详细的步骤上面。

面向对象(Object Oriented,简称OO)是一种以事物为中心的编程思想。就是把解决问题的关注点放到事物(对象)上。

比如我想实现 点击按钮给div设置红色背景 这个功能。
如果是用面向过程的思想来解决问题的话,大致分为以下几个步骤。
1.获取button
2.给button添加点击事件
3.获取div
4.改变div的背景色

示例:

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<style type="text/css">
			div {
				width: 200px;
				height: 200px;
				border: 1px solid black;
			}
			
			.red {
				background: red;
			}
		</style>

		<script>
			window.onload = function() {
				/*1.获取button*/
				var btn = document.querySelector("button");
				/*2.给button添加点击事件*/
				btn.addEventListener("click", function() {
					/*3.获取div*/
					var divNode = document.querySelector("div");
					/*4.改变div的背景色*/
					divNode.classList.add("red");
				});
			}
		</script>
	</head>

	<body>

		<div id="box">
		</div>

		<button>点击变色</button>

	</body>

</html>

这里写图片描述

如果使用面向对象的思想来解决这个问题的话,我需要有两个对象
1.按钮对象
2.div对象

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<style type="text/css">
			div {
				width: 200px;
				height: 200px;
				border: 1px solid black;
			}
			
			.red {
				background: red;
			}
		</style>

		<script>
			/*按钮对象*/
			var btn = {
				getTag: function(tagName) {
					return document.querySelector(tagName);
				}
			};

			/*div对象*/
			var div = {
				getTag: function(tagName) {
					return document.querySelector(tagName);

				},
				setBg: function(node, className) {
					node.classList.add(className);
				}
			};

			window.onload = function() {
				btn.getTag("button").addEventListener("click", function() {
					var divNode = div.getTag("div");
					div.setBg(divNode, "red");
				})
			}
		</script>
	</head>

	<body>

		<div id="box">

		</div>

		<button>点击变色</button>

	</body>

</html>

这里写图片描述

通过代码可以看到,实现的功能一样,只不过解决问题的思路不同。
面向过程的思想是我实现这个功能需要哪些步骤,然后按照步骤来走。
面向对象的思想是我实现这个功能需要什么对象。然后是对象中哪些属性和方法。


什么是对象
在之前的js基础中我们已经了解了什么是js对象。在这里我们了解一下什么是广义的对象。
万物皆对象。也就是说,世界上的所有事物都是对象。注意,对象是指一个具体的事物

这里写图片描述
“路边的汽车”,这里的汽车不是对象,而是一类事物,因为路边汽车有很多。
“我的那台黑色的宝马汽车”,这里的汽车就是一个对象了,因为具体到一个事物了。

对象具有状态和行为,对应对象中的属性和方法。


js中的面向对象
在传统的面向对象中,比如java。是有class(类)的概念的。而在js中(ECMAScript6之前),是没有类(class)的概念的,传统的面向对象是基于类的面向对象,而js中的面向对象实际上是基于原型的。
也就是说,js种面向对象是跟一些强类型语言(比如java)是有一定区别的。


面向对象三大特性

  • 封装
  • 继承
  • 多态

封装
在js中,封装实际上就是把数据和方法封装在一起。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<script>
			var name = "yzq";
			var age = 23;
			function eat() {
				console.log("吃")
			}
			
			/*封装  好处是不会污染全局变量 便于管理*/
			var yzq={
				name:"yzq",
				age:23,
				eat:function  () {
					console.log("吃");
				}
			}
			
			yzq.eat();
		</script>
	</head>

	<body>
	</body>

</html>

继承
在现实生活,最直接的继承就是财产继承。比如,小明的父亲有一辆车,小明自己没有车,小明的父亲去世后,小明通过继承得到了这辆车。并可以去使用它。
在js中,继承就是自己没有, 别人有,拿过来为自己所用, 并成为自己的东西。

多态
在js中实际上是没有多态的体现的,我们只需要了解大致意思即可。下面的java代码看不懂也没关系。
多态,顾名思义就是对象的多种状态。多态是发生在继承的基础上的。

以java语言为例。
多态分为2种情况
1.引用多态

首先一个Animal父类

package duotai;

public class Animal {

	public void eat() {
		System.out.println("吃");

	}

}

Dog子类

package duotai;

public class Dog extends Animal {

}

Main方法

package duotai;

public class test {

	public static void main(String[] args) {
		Animal ani = new Animal();
		// 父类引用指向子类对象
		Animal dog = new Dog();
	}

}

父类引用指向子类对象,这就是引用多态。

2.方法多态

调用的对象不同,执行的结果不同
创建本类的对象时,调用的本类的方法
创建子类对象时,调用的是子类重写的方法或者继承来的方法。

父类

package duotai;

public class Animal {

	public void eat() {
		System.out.println("动物会吃东西");
	}

}

子类

package duotai;

public class Dog extends Animal {

	public void eat() {
		// TODO Auto-generated method stub
		System.out.println("狗吃东西");
	}

}

main方法

package duotai;

public class test {

	public static void main(String[] args) {
		Animal ani = new Animal();
		// 父类引用指向子类对象
		Animal dog = new Dog();
		// 子类如果重写eat方法时就调用子类中的方法,否则调用父类的eat方法
		dog.eat();
	}

}


同一个方法不同对象调用结果不同,这就是方法多态。


js中创建对象的方式

在前面的js基础中,我们已经了解了三种创建对象的方式,下面我们来看看这三种方式的优缺点。
实际上js中的对象都是通过函数创建的。


1.对象字面量

	var yzq = {
				name: "yzq",
				age: 23,
				eat: function() {
					console.log("吃");
				}
			}

这种方式只能创建一次对象,复用性较差,如果要创建多个对象,代码冗余度太高

2.内置构造函数

			/*内置构造函数*/
			var p=new Object();
			p.name="yzq";
			p.age=3;
			p.eat=function  () {
				console.log("吃");
			}
			
			
			var p1=new Object();
			p1.name="喻志强";
			p1.age=18;
			p1.play=function  () {
				console.log("玩")
			}

同样的,这种方式写起来很麻烦。

3.自定义构造函数

			
			function Person(name,age){
				this.name=name;
				this.age=age;
				this.eat=function  () {
					console.log("吃");
				}
			}
			
			var p2=new Person("yzq",23);
			var p3=new Person("喻志强",18);
			var p4=new Person("yuzhiqiang",24);

这种方法用的较多,也是比较合适的创建对象的方法。
注意:
自定义构造函数创建对象时一定要配合new关键字来使用

构造函数的执行过程
1.使用new关键字创建对象
2.调用构造函数,把新创建出来的对象赋值给构造函数内的this
3.在构造函数内使用this为新创建出来的对象新增成员
4.默认返回新创建的这个对象 (普通的函数,如果不写返回语句,会返回undefined)

构造函数的返回值
1.如果不写返回值,默认返回的是新创建出来的对象 (一般都不会去写这个return语句)
2.如果我们自己写return语句 return的是空值(return;),或者是基本类型的值或者null,都会默认返回新创建出来的对象
3.如果返回的是object类型的值,将不会返回刚才新创建的对象,取而代之的是return后面的值

如果像使用正常的函数一样使用构造函数
构造函数中的this将不再指向新创建出来的对象(因为根本就没有创建对象)
构造函数中的this这个时候指向的就是window全局对象
当使用this给对象添加成员的时候,全部都添加到了window上


原型(prototype)

前面我们提到了,js是基于原型的语言。
js所有的函数(function)都有一个prototype属性,这个属性引用了一个对象,即原型对象,也简称原型。
首先我们来看看prototype到底是个什么东西。
打印prototype看看

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<script>
			function person(name, age) {
				this.name = name;
				this.age = age;
			

			}
			console.log(person.prototype);
		</script>
	</head>

	<body>
	</body>

</html>

这里写图片描述

可以看到,prototype是一个对象,这个对象默认有一个constructor属性,指向函数本身。
既然是一个对象,那么我们就可以给这个对象添加属性和方法。
例如:
给person函数中的原型对象添加属性和方法。

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<script>
			function person(name, age) {
				this.name = name;
				this.age = age;

			}

			person.prototype.skill = "Android"; //添加属性
			/*添加方法*/
			person.prototype.eat = function() {
				console.log("吃饭");
			}

			console.log(person.prototype);
			var p = new person("yzq", 23);
			console.log(p.skill);
			p.eat();
		</script>
	</head>

	<body>
	</body>

</html>

这里写图片描述
可以看到,我们给原型对象添加了一个skill属性和eat方法。这些属性和方法可以直接被new出来的对象使用。实际上,这就是js中继承的一种体现。所以,我们可以将一些重复的属性或方法放到prototype中去。
访问对象的属性和方法时,如果对象本身有,则访问对象本身的,如果没有,就去原型中找。

对象的__proto__属性

每个对象都有__proto__属性,指向创建该对象的函数的prototype。
先看看__proto__都有啥

<!DOCTYPE html>
<html>

	<head>
		<meta charset="UTF-8">
		<title></title>

		<script>
			function person(name, age) {
				this.name = name;
				this.age = age;

			}

			var p = new person("yzq", 23);

			console.log(person.prototype);
			console.log(p.__proto__);
		</script>
	</head>

	<body>
	</body>

</html>

这里写图片描述

可以看到,实例化后的对象的__proto__ 和构造其的函数的prototype是一样的
也就是说对象的__proto__指向的是创建它的函数的prototype。
__proto__是一个隐藏的属性,javascript不希望开发者用到这个属性值,在实际开发中除非有特殊的需求,否则不要轻易的使用实例对象的__proto__属性去修改原型的成员。
这个属性一般用在调试中,去查看实例化对象的原型:

	console.log(p.constructor.prototype);

如果你觉得本文对你有帮助,麻烦动动手指顶一下,算是对本文的一个认可。也可以关注我web前端的博客专栏,我会不定期的更新,如果文中有什么错误的地方,还望指正,谢谢!

©️2020 CSDN 皮肤主题: 书香水墨 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值