面向对象的思想主要是以对象为主,将一个问题抽象出具体的对象,并且将抽象出的对象和对象的属性和方法封装成一个类。
面向过程就是分析出解决问题所需要的步骤,然后用函数把这些步骤一步一步实现,使用时候依次调用函数。
面向对象是把构成问题事务分解成各个对象,建立对象的目的不是为了完成一个步骤而是为了描述某个事物在整个解决问题的步骤中的行为
面向对象思想的特点
1.封装
对于同一个功能,只需要封装一次,以后再使用,只需要调用即可,无需重写,即低耦合高内聚。
2.继承
子类可以继承父类的属性和方法
3.多态:重载和重写
重载:js中没有真正意义上的重载,担忧类似重载的功能,就是传不同的参数,有不同的返回值;
重写:子类可以重写父类的属性和方法。
创建对象
1.工厂模式
这种模式抽象了具体对象的过程,此方法是用函数来封装以特定接口创建对象的细节
function createPerson(name,age,sex) {
var obj = new Object();
obj.name = name;
obj.age = age;
obj.sex = sex;
obj.sayName = function () {
alert(this.name)
}
return obj
}
var person1 = createPerson('james',18,'male');
var person2 = createPerson('curry',20,'male')
函数createPerson()能够根据接收的参数来构建一个包含所有必要信息的person对象。可以多次调用这个函数,每次都返回含有三个属性一个方法的对象。
缺点是无法确定创建对象的类型。应为都是Object,没有区分度,不能像Date,Array一样。
2.构造函数模式
javascript中有像Object和Array一样的原生构造函数,除此之外,我们为您可以创建自定义的构造函数,从而自定义对象的属性和方法。
构造函数的命名采用大驼峰式命名
function Person(name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex;
this.sayName = function (){
alert(this.name)
}
}
var person1 = new Person('james',18,'male');
var person2 = new Person('curry',20,'male')
要创建Person的实例,必须使用new操作符,以这种方式调用构造函数会经历以下三个步骤:
(1)创建一个this对象
var this = {}
(2)将构造函数的作用域赋值给新对象并执行构造函数中那个的代码
this = { name : name, age : age, sex : sex, sayName : function () {alert(this.name)} }
(3)返回新对象
return this
构造函数方法的主要问题是每个方法都要在每个实例上重新创建一遍,person1和person2都有sayName()的方法,但两个方法不是同一个Functon的实例。说明白些,以这种方式创建函数,会导致不同的作用域链和标识符解析,但创建Function新实例的机制是相同的,因此不同实例上的同名函数是不相等的,如下:
console.log(person1.sayname == person2.sayName) //false
3.原型模式
我们创建的每个函数都有一个prototype属性,prototype是通过调用构造函数创建的实例的原型对象。使用原型对象可以让所有对象实例共享它所包含的属性和方法。
function Person() {}
Person.prototype,name = 'james';
Person.prototype.age = 18;
Person.prototype.sex = 'male'
Person.prototype.sayName = function () {
alert(this.name)
}
var person1 = new Person();
person1.sayName() //'james'
var person2 = new Person();
person2.sayName(); //'james'
alert(person1.sayName == person2.sayName); //true
前面例子中每添加一个属性和方法就要敲一遍 Person.prototype。为减少
不必要的输入,也为了从视觉上更好地封装原型的功能,更常见的做法是用一个包含所有属性和方法的
对象字面量来重写整个原型对象
function Person() {}
Person.prototype, = {
constructor : Person,
name : 'james',
age : 18,
sex : 'male',
sayName : function () {
alert(this,name)
}
}
以上代码特意包含了一个 constructor 属性,并将它的值设置为 Person,从而确保了通过该属
性能够访问到适当的值。contrucor是原型对象的一个默认属性,它指向构造函数。
原型模式也不是没有缺点。通过例子可以发现它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况下都将取得相同的属性值。虽然这会在某种程度上带来一些不方便,但还不是原型的最大问题。
原型模式的最大问题是由其共享的本性所导致的。
function Person(){
}
Person.prototype = {
constructor: Person,
name : "james",
age : 218,
sex : "male",
friends : ['Curry','Amy'],
sayName : function () {
alert(this.name);
}
};
var person1 = new Person();
var person2 = new Person();
person1.friends.push("Van");
alert(person1.friends); //'Curry,Amy,Van'
alert(person2.friends); //'Curry,Amy,Van'
alert(person1.friends === person2.friends); //true
有一个实例改变了构造函数原型对象的数组,其他实例所引用的构造函数的数组也会改变。
4.原型+构造函数模式
这种混合模式综合了原型模式和构造函数模式这两种模式的优点
function Person (name,age,sex) {
this.name = name;
this.age = age;
this.sex = sex
this.friends = ['Curry','Amy']
}
Person.prototype = {
constructor : Person,
sayName : function () {
alert(this.name)
}
}
var person1 = new Person('James',18,'male');
var person2 = new Person('Rose',20,'male');
person1.friends.push("Van");
alert(person1.friends); //"Curry,Amy,Van"
alert(person2.friends); //"Curry,Amy"
alert(person1.friends === person2.friends); //false
alert(person1.sayName === person2.sayName); //true
实例属性都是在构造函数中定义的,而由所有实例共享的属性 constructor 和方
法 sayName()则是在原型中定义的。而修改了 person1.friends(向其中添加一个新字符串),并不
会影响到 person2.friends,因为它们分别引用了不同的数组。
所以我们在构造对象的时候,一般是原型模式和构造模式组合使用,变化的用构造模式 不变的公用的用原型模式,就像上面的这个栗子,属性用的构造函数,因为一般不同对象属性都不同,方法用原型模式