什么是面向对象
在js中对象是一个无序的数据集合或者也可以说是属性和方法的集合,可以动态的添加属性可方法。面向对象是一种软件开发的思想和面向过程是相对应的,就是把程序看作一个对象,将属性和方法封装其中,以提高代码的灵活性、复用性、可扩展性。面向过程是按需求一步一步的用代码从上往下实现,这样做代码不易维护、复用、扩展。所以在大型项目中我们需要以面向对象的方式去开发项目,这样就体现了用面向对象的方法写出来的代码易维护、易复用、易扩展。
面向对象的特征:封装、继承、多态、抽象。
封装
我对封装的理解就是把属性和方法封装其中,将不需要对外公开的内容隐藏起来提供接口让用户访问属性和方法。
继承
继承就好比我继承了我爸部分的相貌特征但我和我爸又不完全长一个样子,而且我自己没有钱但我爸有钱,我爸的钱可以给我花。就是指子类构造函数继承了父类构造函数的一些属性和方法,但其本身也有一些自己的方法和属性。
多态
多态性是指相同的操作或函数、过程可作用于多种类型的对象上并获得不同的结果。比如一个我养了条狗和一个猫,我对它们发出“叫”的指令时它们一个是“汪汪汪”的叫一个是“喵喵喵”的叫,我给的指令是一样的它们发出来的声音却不一样。
抽象
先不去考虑细节的东西,从大的方向开始。比如学生就是一个抽象实体,他的属性并不足以描述出一个人,需要更多的细节才能描述一个人的方方面面。使用抽象可以尽可能避免过早考虑一些细节。
创建对象
ECMAScript提供了多个原生对象,如 Object、Array、String、Boolean、Number、Date…等等。
此外,JavaScript允许自定义创建对象。
首先我们先创建多个人
var obj1 = {
name:'豪哥',
age:22,
sex:'男'
};
alert("我的名字叫"+obj1.name+',年龄'+obj1.age+'岁,'+'性别:'+obj1.sex);
//现在我还要创建多一个人
var obj2 = {
name:'明哥',
age:23,
sex:'男'
};
alert("我的名字叫"+obj2.name+',年龄'+obj2.age+'岁,'+'性别:'+obj2.sex);
这种写法需要不断的添加大量的代码明显不符合我的面向对象编程的灵活性和复用性,所以我们需要换种符合面向对象的写法。
工厂模式
工厂模式是软件工程领域一种常见的设计模式,这种模式抽象了创建对象的具体过程。
工程模式的过程:原料 => 加工 => 出厂
我们用工厂函数来创建人
function person(name,age,sex){
//原料
var obj = {};
//加工
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.fun = function (){
alert("我的名字叫"+obj.name+',年龄'+obj.age+'岁,'+'性别:'+obj.sex);
}
//出厂
return obj;
}
var obj3 = person('小红',23,'女');//创建
obj3.fun();//调用
var obj4 =person('小豪',18,'男');
obj4.fun();
这样我就可以重复多创建多个人了。但是工厂函数自身也存在一定的问题。
alert(obj3.fun == obj4.fun);//false
alert(obj3.constructor);//function Object() { [native code] }
alert(obj4.constructor);//function Object() { [native code] }
alert(obj3.constructor == obj4.constructor);//ture
alert(obj3 instanceof Object);//true
以上存在的问题不同的对象相同的方法却不是同一个,消耗了内存和性能。而且没办法解决对象类型识别的问题。
构造函数
当任意一个普通函数用于创建一类对象,并且通过new操作符来调用时,它就可以作为构造函数。
作用:构造新对象,设置对象的属性和方法
//构造函数首字母开头大写(ps:非强制,用于区分普通函数和构造函数)
function Person(name,age,sex){
//构造函数内部默认var this={};
//构造函数内部的this指向实例对象
this.name = name;
this.age = age;
this.sex = sex;
this.fun = function (){
alert("我的名字叫"+this.name+',年龄'+this.age+'岁,'+'性别:'+this.sex);
}
//构造函数内部默认 return this;
}
var haoge = new Person('豪哥',22,'男');
var xiaohong = new Person('小红',23,'女');
haoge.fun();
xiaohong.fun();
alert(obj3 instanceof Person);//true
alert(haoge.constructor == xiaohong.constructor)//true
alert(haoge.fun == xiaohong.fun);//false
构造函数的实现过程和工厂模式都差不多,不过它解决了对象类型识别的问题但是创建多个对象时仍然存在多个相同的方法,所以我们也可以把构造函数看作js内置的工厂模式。
原型模式
每个函数都有一个prototype(原型)属性,这个属性指向一个对象,即原型对象。
所有添加到prototype中的属性和方法都将被所有对象实例共享。(继承)
function Person(){};
Person.prototype.name = '豪哥';
Person.prototype.fun = function (){
alert('我的名字叫'+Person.prototype.name);
}
var haoge = new Person();
var xiaohong = new Person();
alert(haoge.fun == xiaohong.fun);//true
alert(haoge instanceof Person);//true
alert(haoge.name == xiaohong.name)//true
上面的原型模式解决了之前的类型不能识别的问题和创建多个对象时仍然存在多个相同的方法的问题,但是
省略了为构造函数传参的环节,所以导致了所有的方法和属性都共享到不同的实例对象。对于函数来说是合适的,但是属性共享问题就大了!
混合模式
混合模式 = 构造函数+原型模式
function Person(name,age,sex){
this.name = name;
this.age = age;
this.sex = sex;
};
Person.prototype.fun = function (){
alert("我的名字叫"+this.name+',年龄'+this.age+'岁,'+'性别:'+this.sex);
}
var haoge = new Person('豪哥',22,'男');
var xiaohong = new Person('小红',23,'女');
haoge.fun();
xiaohong.fun();
alert(haoge.fun == xiaohong.fun);//true
alert(haoge instanceof Person);//true
alert(haoge.constructor == xiaohong.constructor)//true
alert(haoge.name == xiaohong.name)//false
混合模式解决了上面的类型不能识别、创建多个对象时存在多个相同的方法、属性共享等问题。是目前JS中使用最广泛、认同度最高的一种创建对象的方法。