面向对象是一种编程思想,我们通过类(构造函数)和对象实现的面向对象编程,满足下述三个特定:封装、继承和多态。
封装
封装创建对象的函数
封装即把实现一个功能的代码封装到一个函数中,以后实现这个功能,只需要执行该函数即可。实现低耦合,高内聚。
现在我们把属性和方法封装成一个对象:
如果我们想创建一个不同性别不同姓名的对象,就需要再写一遍上述代码:
如果我们想要创建多个对象的话,写起来就非常麻烦,所以要去封装创建对象的函数解决代码重复的问题。
然后生成实例对象,就等于是在调用函数:
上述过程可以类比为开工厂生产酸奶:第一步:需要原料;第二步:加工酸奶;第三步:出厂售卖;我们通过var声明空对象的这一步就相当于第一步原料,添加属性和函数就相当于第二步加工,通过return返回对象就相当于第三步出厂。这种符合上述1、2、3步骤的函数叫做工厂函数,这种设计函数的思路,叫做工厂设计模式。
通过new调用函数
官方函数创建对象的方法是通过new的方法,当我们不使用new创建对象的时候,函数内部的this会指向窗口。
所以当我们在函数内部给this.name赋值为xxxx时,可以通过window.name输出xxxx,因为如果这个函数没有主人的话它的主人就是window对象。
但是如果这个函数通过new运算符去调用,那么这个函数中的this,就会指向新创建的对象。
当我们通过new运算符去调用函数的时候,它首部和尾部会自动的生成以下两步:1、原料操作:强制改变this指向this = new Object(); 3、出厂操作:将this返回return this;。
所以现在我们改造一下之前创建的函数,调用的时候全部都通过new去调用,并且将函数中的person改成this。
构造函数
我们把这种可以创建对象的函数,叫做构造函数。(功能就是用来构造对象)
为了和别的函数,进行区分,我们把构造函数首字母大写。官方的构造函数:Array、Object、Date。
我们通过typeof可以看到官方通过new创建的Object、Array、Date本质上都是function函数。而且所有被该函数,创建的对象,对象的方法都是一套,arr1.push === arr2.push返回值是true。
但是通过调用函数生成的对象方法,彼此之间没有联系,不能反映出它们是同一个原型对象的实例。alert(p1.showName === p2.showName);返回值为false。
我们声明两个数组
给数组添加求和的函数
调用arr1.sum可以输出arr1的和为150,但是调用arr2.sum会系统报错,提示arr1.sum不是一个函数。因为arr1和arr2是单独的两个对象,给arr1添加一个方法,arr2并不会拥有这个方法。所以我们之前通过new调用函数生成对象后,他们的方法是相互独立的。
每一个实例对象,都有自己的属性和方法的副本。这不仅无法做到数据共享,也是极大的资源浪费。
原型prototype
prototype对象的引入:所有实例对象需要共享的属性和方法,都放在这个对象中,那些不需要共享的属性和方法,就放在构造函数中。以此来模拟类。
所以想让arr2也拥有求和函数就需要再重新写一个arr2.sum,这样就会造成浪费,我们想让对象共用一个方法,这时候就需要引入原型prototype。在JS中一切皆对象,函数也是对象。 每一个被创建的函数,都有一个官方内置的属性,叫做prototype(原型)对象 ,我们输出一下show.protoype,得到结果[object Object]。
所有实例对象需要共享的属性和方法,都放在这个对象里面;那些不需要共享的属性和方法,就放在构造函数里面。
如果,我们想要让该函数创建出来的对象,公用一套函数,那么我们应该将这套函数,添加该函数的prototype原型。 所以我们如果想让两个数组都拥有求和的方法,就需要将这个方法添加在Array的原型上。
现在arr1和arr2都可以使用这个函数,并且arr1.sum == arr2.sum,他们使用的这个函数都是原型上的同一个方法。
我们可以通过混合法,让用户自定义构造函数,封装一个可以创建对象的函数,并且调用的是同一个方法。
面向对象编程案例
现在我们要测试100辆不同品牌的汽车,记录他们在道路上行驶的性能指数。
创建一个可以构造各式各样车的构造函数
在Car的原型上添加功能:让车跑在路上,计算时速。
1. Car.prototype.run = function(road){2. alert(`一辆${this.type}品牌的${this.name}系列,时速为${this.speed}km/h的车,跑在长度为${road.length}km的${road.name},最终的成绩是${road.length / this.speed}小时`);3. }
创建一个可以构造各式各样马路的构造函数
添加第一个测试用例car1:
1. var kuahaidaqiao = new Road("跨海大桥