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

面向对象

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


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

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

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

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

示例:




	
		
		

		

		
	

	

		

从零开始,学习web前端之js高级_第1张图片

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




	
		
		

		

		
	

	

		

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


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

从零开始,学习web前端之js高级_第2张图片
“路边的汽车”,这里的汽车不是对象,而是一类事物,因为路边汽车有很多。
“我的那台黑色的宝马汽车”,这里的汽车就是一个对象了,因为具体到一个事物了。

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


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


面向对象三大特性

  • 封装
  • 继承
  • 多态

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




	
		
		

		
	

	
	


继承
在现实生活,最直接的继承就是财产继承。比如,小明的父亲有一辆车,小明自己没有车,小明的父亲去世后,小明通过继承得到了这辆车。并可以去使用它。
在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看看




	
		
		

		
	

	
	


这里写图片描述

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




	
		
		

		
	

	
	


从零开始,学习web前端之js高级_第3张图片
可以看到,我们给原型对象添加了一个skill属性和eat方法。这些属性和方法可以直接被new出来的对象使用。实际上,这就是js中继承的一种体现。所以,我们可以将一些重复的属性或方法放到prototype中去。
访问对象的属性和方法时,如果对象本身有,则访问对象本身的,如果没有,就去原型中找。

对象的__proto__属性

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




	
		
		

		
	

	
	


从零开始,学习web前端之js高级_第4张图片

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

	console.log(p.constructor.prototype);

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

你可能感兴趣的:(web前端,从零开始,学习web前端)