日期:2014-05-16  浏览次数:20566 次

JavaScript面向对象的程序设计1—基础篇

1. 理解JavaScript的对象
??? 面向对象的的语言都有类的概念,类抽象了对象共有的属性和行为,根据类可以创建不同的对象。
??? 可是Javascript中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。
??? ECMA-262把对象定义为:"无序属性的集合",其属性可以是基本值,对象,或者函数。(严格来讲,这就相当于说对象是一组没有特定顺序的值)
??? JavaScript中每个对象都是基于一个引用类型创建的,包括JavaScript的原生类型(如Array,Date等),也可以是开发人员自定义的类型。

?

2. 创建对象
??? 1) 利用Object类型
??????? 创建自定义对象最简单的方法就是创建一个Object的实力,然后再为它添加属性和行为,如下:

???????????

var person = new Object();
person.name = "anser";                          //属性
person.age = 22;
person.job = "Software Engineer";
person.sayName = function() {               //行为
    alert(this.name);
}

??? ?2) 工厂模式
???????? 使用Object类型创建不同类型的对象的缺点:使用同一个接口创建很多对象,会产生很多重复的代码。如上面,分别创建person1,person2......
??????? 因此使用工厂模式,封装特定接口创建对象的细节,上面示例修改如下:

?

        function createPerson(name, age, job) {
            var person  = new Object();
            person.name = name;
            person.age = age;
            person.job = job;
            person.sayName = function() {
                alert(this.name);
            }
            return person;
        }

??????? 使用工厂模式虽然解决了创建多个相似对象的问题,可是却没有解决对象识别的问题(及怎么样知道一个对象的类型:通过 instanceof 操作符)。

? 3) 构造函数模式
??????? ECMAScript中的构造函数可用来创建特定类型的对象。像Object,Array这样的原生构造函数,在运行时会自动出现在执行环境中。
??????? 此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。改写以上的例子如下:

 function Person(name, age, job) {
            this.name = name;
            this.age = age;
            this.job = job;
            this.sayName = function() {
                alert(this.name);
            }           
        }
        Person person1 = new Person("anser", 22, "Software Engineer");
        Person person2 = new Person("xhc", 22, "Player");

????????注意到构造函数模式和工厂模式的不同:
??????????? a. 没有显示地创建对象,在工厂模式中创建了新的Object对象;
??????????? b. 直接将属性和方法赋给了this对象,在工厂模式中赋给了新创建的Object对象;
??????????? c. 没有return语句, 在工厂模式中在工厂方法中返回显示创建的Object对象。
??????
??????? 要创建新的Person对象,使用new操作符,以这种方式调用构造函数实际上会经历一下4个步骤:
??????????? a. 创建一个新对象;
??????????? b. 将构造函数的作用域赋给新对象(因此this就指向了这个新对象);
??????????? c. 执行构造函数中的代码(为这个新对象添加属性);
??????????? d. 返回新对象。

??????? 通过构造函数创建的对象都有一个constructor(构造函数)属性,指向Person构造函数:
????????

alert(person1.constructor == Person);   //true;
alert(person2.consturcotr == Person);    //ture;

?

??????? 但是检测对象类型还是使用instanceof操作符更可靠一些(因为在后面会介绍到,对象的构造函数不一定是这个类型的构造函数)。

        alert(person1 instanceof Object);    //true; 所有的对象均继承自Objec
        alert(person1 instanceof Person);    //true;

?

??????? 使用构造函数,可以将它的实例标识为一种特定的类型,这正是构造函数模式胜过工厂模式的地方。
?理解构造函数:
??????? 1. 构造函数名首字母尽量大写,主要为了区分ECMAScript中的其他函数,因为构造函数本身也是函数,只不过可以用来创建对象而已。
??????? 2. 构造函数与其他函数的唯一区别,就在于调用它们的方式不同。任何函数通过new操作符来调用,那它就可以作为构造函数。
??????????? 如上面的构造函数Person:

//当作构造函数使用
Person person = new Person("anser", 22, "Software Engineer");
person.sayName();    //anser

//作为普通函数使用
Person("name1", 27, "job");    //添加到window,此时调用函数Person的作用域为window对象
window.sayName();               //name1

//在另一个对象的作用域中调用
Object o = new Object();
o.Person("object", 1, "test");
o.sayName();    //object

?
??????? 3. 构造函数的问题
??????????? 使用构造函数的缺点:就是每个方法都要在每个对象的实例上重新创建一遍。
??????????? 如前面例子中的person1和person2对象都有一个名为sayName()的方法,但那两个方法不是同一个Function的实例。
??????????? ECMAScript中函数也是对象,因此每定义一个函数,也就是实例化了一个对象。
??????????? 因此上面的构造函数实际相当于:

function Person(name, age, job) {
    this.name = name;
    this.age = age;
     this.job = job;
    this.sayName = new Function(" alert(this.name);") ;    //与声明函数在逻辑上是等价的
}
alert(person1.sayName == person2.sayName);    //false