javascript--创建对象

面向对象(Object-Oriented,OO)的语言有一个特点,那就是它们都有类的概念。而javascript中没有类的概念,因此它的对象也与基于类的语言中的对象有所不同。

ECMA-262把对象定义为:“无序属性的集合,其属性可以包含基本值、对象或函数”,我们可以把对象想象成散列集:无非就是一组名值对,其中值可以是数据或函数。下面介绍几种创建对象的按方法。

一、Object构造函数或对象字面量

var person={
            name:"Bob",
            age:"24",
            sayName:function(){
                alert(this.name);    
            }
        }

这种方法有明显缺陷:会产生大量重复代码。

二、工厂模式

考虑到ECMAscript中无法创建类,开发人员想到用函数封装以特定接口创建对象的细节。

function createPerson(name,age){
            return {
                name:name,
                age:age,
                sayName:function(){
                    alert(this.name);
                }
            }
        }
        var person1=createPerson("Bob","24");

工厂模式虽然定义接口创建对象,单却没有解决对象识别的问题(即怎样知道一个对象的类型)。

三、构造函数模式

大家都知道在javascript中用构造函数可创建特定类型的对象,如:Object、Array。此外,也可以创建自定义的构造函数,从而定义自定义对象类型的属性和方法。

function Person(name,age){
            this.name=name;
            this.age=age;
            this.sayName=function(){
                alert(this.name);    
            }
        }
        var person1=new Person("Bob","24");    
        var person2=new Person("Rose","27");

创建Person构造函数的新实例,必须使用new操作符。调用构造函数会经历以下几个步骤:

  1. 创建一个新对象;
  2. 将构造函数的作用域赋给新对象--this就指向新对象;
  3. 执行构造函数中的代码;
  4. 返回新对象;

每个对象都有个constructor(构造函数)属性:

alert(person1.constructor==Person);    //true
        alert(person1 instanceof Person);    //true
        alert(person1 instanceof Object);    //true

构造函数模式虽然好用,但也并非没有缺点。每个实例中的方法都是重新创建的,以构造函数模式穿件实例会导致不同的作用域链和标识符解析。因此,不同实例上的同名函数是不相等的。

alert(person1.sayName==person2.sayName)    //false

四、原型模式

每一个创建的函数都有一个prototype属性,指向一个对象,而这个对象的用途是包含了其所有实例共享的属性和方法。因此,我们可以把那些不变的属性和方法直接定义在prototype对象上。

function Person(name,age){
            Person.prototype.name=name;
            Person.prototype.age=age;
            Person.prototype.sayName=function(){
                alert(this.name);    
            }
        } 
var person1=new Person("Bob","24");    
        var person2=new Person("Rose","27");
        person1.sayName();    //Rose
        person2.sayName();    //Rose
        alert(person1.sayName==person2.sayName)    //true

有原型模式创建的实例的属性和方法都指向prototype对象。且原型的属性、方法都是动态的,我们对原型对象所做的任何修改都能从实例上体现出来,所以person1.sayName()输出Rose。但是,实例一般都是要有属于自己的全部属性的,这也是很少有人单独使用原型模式的原因。

五、组合使用构造函数模式和原型模式

由上可知,构造函数模式可以定义每个实例特有的属性和方法,原型模式定义所有实例共享的动态属性和方法。混成模式可谓是集两家之所长!

function Person(name,age){
            this.name=name;
            this.age=age;
            this.sayName=function(){
                alert(this.name);    
            }
        }
        Person.prototype={
            job:"teacher",
            age:"30",
            sayAge:function(){
                alert(this.age);
            }
        }
var person1=new Person("Bob","24");    
        var person2=new Person("Rose","27");
        person1.sayAge();    //24
        person2.sayAge();    //37
        alert(person1.sayName==person2.sayName);    //false
        alert(person1.sayAge==person2.sayAge);    //true

在这个例子中,我们可以把共享的属性和方法,定义在prototype对象上;特有的属性、方法定义在实例对象上。但是上例中,我们在实例和原型中都定义了age属性,实例结果显示实例属性。若我们将实例中的age属性去掉:

function Person(name,age){
            this.name=name;
            this.sayName=function(){
                alert(this.name);    
            }
        }
        Person.prototype={
            job:"teacher",
            age:"30",
            sayAge:function(){
                alert(this.age);
            }
        }
var person1=new Person("Bob","24");    
        var person2=new Person("Rose","27");
        person1.sayAge();    //30
        person2.sayAge();    //30

实例结果都返回原型中的属性值。这是由于当代码读取某个对象的某个属性时,搜索首先从对象实例开始,若实例中存在则返回该值且屏蔽掉原型中的同名属性;若没找到,则继续在原型对象中搜索。

构造函数和原型的混成模式,是目前用来创建自定义类型的一种默认模式!

posted on 2017-02-11 23:07  世界之魂  阅读(173)  评论(0编辑  收藏  举报

导航