Javascript中对象的创建

本文介绍了JavaScript中五种创建对象的方法:Object构造函数、字面量、工厂模式、构造函数模式和原型模式,并详细分析了各自的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1、Object构造函数和字面量的方式创建对象

通过Object构造函数的方式创建对象,代码如下:

var person = new Object();
person.name="张三";
person.age=24;

通过字面量的方式创建对象,代码如下:

var someone = {
 name:'Obama',
 age:29,  
}

2、工厂模式创建对象

工厂模式创建对象的代码如下:

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

var person1 = person("张三",21);
var person2 = person("李四",22);

由上述代码可以发现,所谓的工厂模式只是将原先通过Object构造器创建对象的代码封装在一个function函数中而已,具体属性的值是通过函数的形参传递进来的。

工厂模式的优点:当需要大量创建person对象时,工厂模式可以省去大量的重复代码。
工厂模式的缺点:无法识别对象,即所有通过工厂模式创建的对象都是Obejct对象的实例。
这里写图片描述
如上所示,通过工厂模式创建一个对象后,使用typeof关键字来检测person1的类型,发现返回的类型是object。所以说工厂模式虽然方便了创建对象的过程,但是在对于对象识别这一部分也是有缺陷的。

3、构造函数模式创建对象

构造函数模式创建对象的代码为:

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        alert(this.name);
    }
}
var person1 = new Person("张三三",21);

使用构造函数模式创建的步骤如下:

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

对于新创建的person1对象,可以使用instanceof来检测其类型。
这里写图片描述
根据以上结果可知,创建自定义的构造函数以为着可以将它的实例标识为一种特定的类型,这就是构造函数模式由于工厂模式的地方。

使用构造函数模式创建对象需要注意:
1、构造函数与其他函数的唯一区别也仅仅是调用的方式不同,所以它还是一个函数,如果使用new关键字来调用,则它就是构造函数,如果不使用new关键字来调用,那么它就是一个普通的函数。
2、构造函数的缺点,回顾构造函数的定义

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName = function(){
        alert(this.name);
    }
}

如果此时创建多个对象p1和p2,代码如下:

var p1 = new Person("张三三",21);
var p2 = new Person("李四四",22);

此时,两个Person的实例中都有sayName()方法,问题就在于两个实例所拥有的方法却不是同一个Function的实例(在js中,函数也是对象)。也就是说,每创建一个对象,Function对象都会被实例化一遍。所以,使用构造函数创建对象的代码在逻辑上等价于

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName = new Function("alert(this.name)");
}

为每一个Person实例都创建一个完成同样同样任务的Function实例是完全没有必要的,于是,上述代码可以改造为如下所示,也就是将函数的定义转移到构造函数之外,将其变成一个全局的函数,然后在构造函数内部引用这个全局函数即可。

function Person(name,age){
    this.name = name;
    this.age = age;
    this.sayName = sayName;
}
function sayName(){
    alert(this.name);
}

不过这种方法却破坏了封装性。

4、原型模式创建对象

在JavaScript中,当我们声明一个函数的时候, 浏览器默认就会在内存中创建一个对象B,而且每个函数都默认会有一个属性 prototype,这个prototype属性的值指向了这个对象B( 即:prototype的属性的值是这个对象 )。
所以,浏览器为我们声明的函数所创建的这个对象就是原型对象
这个原型对象B,默认会有一个属性即constructor,而constructor属性的值则指向了这个函数A ( 意思就是说:constructor属性的值是函数A )。
示意图如下图所示:

这里写图片描述

现在我们可以尝试一下使用函数的原型对象来创建对象了,使用原型对象的好处是可以让所有对象实例都共享它的所拥有的属性和方法,这样就不比在构造函数中去定义属性和方法了。所以创建对象的代码可以改写为,

function Person(){}

Person.prototype.name="张三";
Person.prototype.age=24;
Person.prototype.sayName = function(){
    alert(this.name)
};

测试结果如下:
这里写图片描述

1、为什么新创建的对象p1是一个空对象,但是却能访问到name和age值?
答:name和age值是在原型对象中的。因为一旦在原型对象中定义了属性或函数,那么由该原型对象的constructor属性所指向的函数所创建的对象都将共享这些属性或函数。可以通过Person.prototype来查看该函数对应的原型中所定义的属性和方法。
这里写图片描述
2、如果对象实例和原型对象中都对某一个属性进行了初始化,那么最后通过对象实例访问该属性,到底获取的是哪一个值?
答:先搜索实例对象中是否定义过该属性,如果找到则返回该值,如果没找到,则继续在原型对象中搜索,如果找到则返回该值。所以,在实例对象中定义的属性的值将会屏蔽原型对象中定义的属性的值。

使用原型模式需要注意的几点:

  1. 原型模式有更简单的语法,即使用字面量的方式。
    这里写图片描述
    这种方式会导致一个问题,即原型对象中的constructor属性将无法指向构造函数。
    先测试第一种,可以发现Person.prototype.constructor能正确的指向Person
    这里写图片描述
    再测试第二种,发现此时Person.prototype.constructor已经不指向Person了。
    这里写图片描述
    如果坚持要使用这种简化的字面量的方式创建对象的话,可以手动添加constructor属性
    这里写图片描述
    2、原型模式创建对象的缺点
    它省略了为构造函数传递初始化参数这一环节,结果所有实例在默认情况先都将取得相同的属性值。原型中所有属性是被很多实例共享的,这种共享对于函数来说非常合适,但是,对于包含引用类型值的属性来说,问题就比较突出。

5、原型对象与构造函数模式混合使用创建对象

这里写图片描述

function Person(name,age){
    this.name = name;
    this.age = age;
}
Person.prototype = {
    constructor:Person,
    sayName:function(){
        alert(this.name);
    }
}

这种混合的方式集原型和构造器两种创建对象的优点于一身,但是有一个缺点也很明显,它没有任何封装性可言。于是对其进行稍微的改进,改进后的代码如下:

function Person(name,age){
    this.name = name;
    this.age = age;
    if(typeof this.sayName != "function"){
        Person.prototype = {
            sayName:function(){alert(this.name);}
        }
    }
}

完美的一B!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值