JavaScript相关-深入面向对象

 1,对象创建

在js中并不存在类,所以可以直接通过Object来创建对象。

1 var person = new Object();
2 person.name = "Leon";
3 person.age = 33;
4 person.say = function() {
5     alert(this.name+","+this.age);
6 }

但是使用如上方式创建,带来最大的问题是,由于没有类的约束。无法实现对象的重复利用,并且没有一种约定,在操作时会带来问题。

2,json表示法

json的意思就是javascript simple object notation。json就是js的对象,但是它省去了xml中标签,而是通过{}来完成对象的说明。

1 var person = {
2     name:"张三",
3     age:22,
4     say:function(){
5         alert(this.name+this.age);
6     }
7 }
8 person.say();

3,工厂方式创建对象

 1  /* 在createPerson中创建一个对象
 2  * 然后为这个对象设置相应的属性和方法
 3  * 之后返回这个对象
 4  */
 5 function createPerson(name,age) {
 6     var o = new Object();
 7     o.name = name;
 8     o.age = age;
 9     o.say = function() {
10         alert(this.name+","+this.age);
11     }
12     return o;
13 }
14 var p1 = createPerson("Leon",22);
15 var p2 = createPerson("Ada",33);
16 p1.say();
17 p2.say();

使用工厂的方式,虽然有效的解决了类的问题,但是依然存在另外一个问题,无法检测对象p1和p2的数据类型

4,构造函数方式创建

两种方式:(1)

 1 function Person(name,age) {
 2     this.name = name;
 3     this.age = age;
 4     //以下方式带来的问题是所有的对象都会为该行为分配空间
 5     this.say = function() {
 6         alert(this.name+","+this.age);
 7     }
 8 }
 9 /*
10  * 通过new Person来创建对象
11  */
12 var p1 = new Person("Leon",22);
13 var p2 = new Person("Ada",32);
14 p1.say();
15 p2.say();
16 alert(p1 instanceof Person);//使用构造函数的方式可以通过以下方式来检测对象的类型
17 alert(p1.say==p2.say);//false

以上方式带来的问题是所有的对象都会为该行为分配空间。每一个对象中都会存在一个方法的拷贝,如果对象的行为很多的话空间的占用率就会大大增加可以将函数放到全局变量中定义,这样可以让类中的行为指向同一个函数。

(2)

function Person(name,age) {
    this.name = name;
    this.age = age;
    this.say = say;
}
/**
 * 将行为设置为全局的行为,如果将所有的方法都设计为全局函数的时候 这个函数就可以被window调用,此时就破坏对象的封装性
 * 而且如果某个对象有大量的方法,就会导致整个代码中充斥着大量的全局函数这样将不利于开发
 */
function say() {
    alert(this.name+","+this.age);
}
var p1 = new Person("Leon",22);
var p2 = new Person("Ada",32);
p1.say(); 
p2.say();
alert(p1 instanceof Person);
alert(p1.say==p2.say);

 5,基于原型的方式

 当一个函数创建后,会产生一个原型对象,当通过这个函数的构造函数创建了一个具体的对象之后,在这个具体对象中就会有一个属性指向原型。
 1 function Person(){
 2 
 3 }
 4 Person.prototype.name = "zhangsan";
 5 Person.prototype.age = "23";
 6 Person.prototype.say = function(){
 7     alert(this.name+","+this.age);
 8 }
 9 var p1 = new Person();
10 p1.say();
11 //检测摸个对象是否是某个函数的原型
12 alert(Person.prototype.isPrototypeOf(p1));//ture
13 //检测某个属性是否是自己的属性
14 alert(p1.hasOwnProperty("name"));//false
15 p2 = new Person();
16 p2.name = "lisi";
17 p2.say();
18 // delete p2.name; //可以通过delete删除属性
19 alert(p2.hasOwnProperty("name"));//true(没delete)
20 //检测某个对象在原型或自己是否包含某个属性,通过in检测
21 alert("name" in p1) //true

JavaScript相关-深入面向对象

6,原型重写

可以通过json进行原型的重写。由于原型重写,而且没有通过Person.prototype来指定,此时的constructor不会再指向Person而是指向Object

1 Person.prototype = {
2     constructor:Person,
3     name:"Leon",
4     age:23,
5     say:function (){
6         alert(this.name+","+this.age);
7     }
8 }

原型重写可能出现问题,要注意。

JavaScript相关-深入面向对象

8,组合创建对象

为了解决原型所带来的问题,此处需要通过组合构造函数和原型来实现对象的创建。将属性在构造函数中定义,将方法在原型中定义,这种有效集合了两者的优点,是目前最为常用的一种方式。

 1 function Person(name,age,friends){
 2     //属性在函数中定义
 3     this.name = name;
 4     this.age = age;
 5     this.friends = friends;
 6 }
 7 Person.prototype = {
 8     constructor:Person,//手动指定constructor
 9     //方法在原型中定义
10     say:function (){
11         alert(this.name+"["+this.friends+"]");
12     }
13 }
14 var p1 = new Person("Leon",23,["Ada","Chris"]);
15 p1.name = "John";
16 p1.friends.push("Mike");
17 p1.say();//John[Ada,Chris,Mike]
18 var p2 = new Person("Ada",22,["Leno"]);
19 p2.say();//Ada[Leno]
 1 function Person(name,age,friends){
 2     //属性在函数中定义
 3     this.name = name;
 4     this.age = age;
 5     this.friends = friends;
 6     if(!Person.prototype.say) {
 7             Person.prototype.say = function() {
 8                 alert(this.name+"["+this.friends+"]");
 9             }    
10         }
11 }
12 var p1 = new Person("Leon",23,["Ada","Chris"]);
13 p1.name = "John";
14 p1.friends.push("Mike");
15 p1.say();
16 var p2 = new Person("Ada",22,["Leno"]);
17 p2.say();