`
holdbelief
  • 浏览: 704939 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

构造函数而不是类

阅读更多

构造函数而不是类

前面提到过,有关JavaScript OOP的最奇怪的事情是,JavaScript不想C#或C++那样,它没有类。在C#中,在执行类似下面的操作时:

Dog spot = new Dog();

 将返回一个对象,该对象是Dog类的实例。但在JavaScript中,本来就没有类。与访问类最近似的方法是定义构造函数,如下所示:

function DogConstructor(name) 
{
    this.name = name;
    this.respondTo = function(name) 
    {
        if(this.name == name) 
        {
            alert("Woof");        
        }
    };
}

var spot = new DogConstructor("Spot");
spot.respondTo("Rover"); // nope
spot.respondTo("Spot"); // yeah!

 那么,结果会怎么样呢?暂时忽略 DogConstructor 函数定义,看一看这一行:

var spot = new DogConstructor('Spot');

 "new"运算符执行的操作很简单。首先,它创建一个新的空对象,然后执行紧随其后的函数调用,将新的空对象设置为该函数中"this"的值。换句话说,可以认为上面这行包含"new"运算符的代码与下面两行代码的功能相当:

// create an empty object
var spot = {}; 
// call the function as a method of the empty object
DogConstructor.call(spot, 'Spot');

 (call函数的第一个参数是调用DogConstructor()函数的对象,第二个参数是DogConstructor()函数的参数)

正如在DogConstructor主体中看到的那样,调用此函数将初始化对象,在调用期间关键字"this"将引用此对象。这样,就可以为对象创建模板!只要需要创建类似的对象,就可以与构造函数一起调用"new",返回的结果将是一个完全初始化的对象。这与类非常相似,不是吗?实际上,在JavaScript中构造函数的名称通常就是所模拟的类的名称,因此在上面的示例中,可以直接命名构造函数Dog:

// Think of this as class Dog
function Dog(name) {
    // instance variable 
    this.name = name;
    // instance method? Hmmm...
    this.respondTo = function(name) {
        if(this.name == name) {
            alert('Woof');        
        }
    };
}

var spot = new Dog('Spot');

 在上面的Dog定义中,我定义了名为name的实例变量。使用Dog作为其构造函数所创建的每个对象都有它自己的实例变量名称副本(前面提到过,它就是对象词典的条目)。这就是希望的结果。毕竟,每个对象都需要它自己的实例变量副本来表示其状态。但如果看看下一行,就会发现每个Dog实例也都有它自己的responseTo方法副本,这是个浪费;您只需要一个可供各个Dog实例共享responseTo实例!通过在Dog以外定义responseTo,就可以避免此问题,如下所示:

function respondTo() 
{
    // respondTo definition
}

function Dog(name) 
{
    this.name = name;
    // attached this function as a method of the object
    this.respondTo = respondTo;
}

 这样,所有Dog实例(即用构造函数Dog创建的所有实例)都可以共享responseTo方法的一个实例。但随着方法数量的增加,维护工作将越来越难。最后,基本代码中将有很多全局函数,而且随着"类"的增加,事情只会变得更加糟糕(如果它们的方法具有相似的名称,则尤甚)。是使用原型对象可以很好地解决这个问题,这是下一节的主题。

下一节:原型                                                                                                                       返回首页: Top

分享到:
评论

相关推荐

    重写重载构造函数

    如果类不是静态的,C#编译器将为无构造函数的类提供一个公共的默认构造函数,以便该类可以实例化。 私有构造函数可以阻止类被实例化。例如: C#复制代码 class NLog { // Private Constructor: private NLog() {...

    构造函数与静态块的执行顺序

    构造函数主要用于初始化对象的状态,而静态块则是在类加载到内存中时执行的一段代码,通常用于类级别的初始化。 ### 构造函数与静态块的基本概念 构造函数是一种特殊的方法,它与类同名,并没有返回类型,其主要...

    构造函数不能为虚函数的理由

    当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码- -既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。因此,它使用的 V PTR 必须是对于这个类的 V TABLE。而且,只要它是最后的构造...

    C++ 课程作业 类与对象2——构造函数、拷贝构造函数、析构函数(计算两个日期间的天数)

    2、请使用构造函数实现的类的初始化工作,并判断日期和时间的有效性。年月日时分秒应该在正确的范围内。考虑闰年时候二月份的情况。时间的格式是xx:xx:xx,小时不是超过23,分钟和秒不能超过59。 1)如果日期无效...

    C++有子对象的派生类的构造函数

    1. 初始化顺序:成员对象的构造顺序是由它们在类声明中的顺序决定的,而不是它们在成员初始化列表中的顺序。先声明的成员先构造。 2. 深拷贝与浅拷贝:在派生类构造函数中,如果子对象是其他类的引用或指针,需要...

    C++规定与类同名的函数就是拷贝构造函数

    例如,如果类的成员是一个动态分配的内存块,那么默认的拷贝构造函数只会复制指针,而不是实际的数据。这意味着两个对象将共享同一块内存,这是不安全的,因为它们可能通过各自的析构函数试图释放相同的内存,从而...

    为什么构造函数不能是虚函数

    - 在构造函数中调用虚函数时,实际上只会调用当前类的版本,而不是继承体系中其他类的版本。 - 这是因为构造函数调用的顺序是从基类到派生类,而在构造函数中调用虚函数时,虚拟表(VTable)中的指针还未被更新为...

    C++复制构造函数详解

    - **浅拷贝与深拷贝**:默认情况下,复制构造函数执行的是浅拷贝,只复制对象的成员变量的指针,而不是指针所指向的数据。如果类中有动态分配的资源,需要确保执行深拷贝以避免共享资源和内存泄漏。 - **自赋值优化...

    构造函数(转)

    - **定义**:虽然不是构造函数,但它与复制构造函数相似,用于将一个对象的值赋给另一个对象。 - **示例**: ```cpp class Complex { public: Complex& operator=(const Complex& rhs) { if (this == &rhs) ...

    类构造函数与析构函数

    需要注意的是,如果类中定义了带参数的构造函数,而没有定义无参数的构造函数,那么系统将无法创建不带参数的对象。在上面的代码中,我们定义了一个带参数的构造函数Teacher(char *input_name),那么如果我们尝试...

    枚举类型与构造函数.doc

    枚举类型与构造函数 枚举类型是一种特殊的数据类型,它可以在程序中定义一组固定的常量,...枚举类型和构造函数是Java中两种重要的概念,枚举类型可以定义一组固定的常量,而构造函数可以用于初始化对象的实例变量。

    C++构造函数初始化列表

    构造函数初始化列表是C++中一个非常重要的特性,它允许程序员在对象创建时直接对类中的成员进行初始化,而不是先分配内存再赋值,这在效率和安全性上都有显著优势。 #### 构造函数初始化列表的作用与语法 构造函数...

    C++构造函数分类讲解

    C++构造函数分类讲解,常见的构造函数都有讲解,虽然讲解的不是很详细但是能有利于新手的记忆。

    c++中拷贝构造函数实例

    - **深复制**:如果类中包含动态分配的资源(如动态数组或复杂对象),拷贝构造函数需要进行深复制,即为每个对象分配新的内存并复制数据,确保新旧对象独立。 **知识点二:自定义拷贝构造函数** 对于包含动态内存...

    构造函数不能声明为虚函数,析构函数可以声明为虚函数

    这不仅可以确保代码的安全性,还可以提高代码的可扩展性,允许未来添加更多的派生类而无需修改现有代码。 ### 实例分析 为了更好地理解上述概念,我们可以考虑以下示例代码: ```cpp #include class A { public...

    C 拷贝构造函数.rar

    2. **函数参数传递**:当对象作为函数参数传递时,如果传入的是对象而不是引用或指针,拷贝构造函数会被调用来创建函数内部使用的副本。 ```cpp void func(ClassName obj) { // ... } ClassName obj1; func(obj1); ...

    拷贝构造函数.rar

    3. **返回对象**:当函数返回一个对象时,如果该对象不是引用或常量引用,编译器会创建一个临时对象,并调用拷贝构造函数将函数内部的对象复制到这个临时对象上。 在代码实例中,你可能会看到类似这样的拷贝构造...

    c#析构构造函数c#析构构造函数c#析构构造函数

    它们不同于常规的构造函数,构造函数用于初始化对象,而析构函数则是为了清理。 C#中析构函数的主要用途是处理非托管资源,如文件句柄、数据库连接或显卡内存等。这些资源不是由.NET Framework自动管理的,因此...

    C++构造函数的剖析

    这意味着构造函数主要用于对象的初始化,而不是返回任何值。 3. **定义对象时,编译系统自动调用构造函数**。这是构造函数的核心特点之一,保证了对象在创建时就能处于正确的初始状态。 4. **构造函数可以在类中定义...

    Javascript 设计模式之构造函数模式.zip

    类表达式提供了一种更直观的方式来声明构造函数和方法,但其内部机制仍然遵循构造函数模式。 总结,JavaScript的构造函数模式是创建对象的主要方式之一,它结合原型和原型链提供了面向对象编程的基础。理解并掌握这...

Global site tag (gtag.js) - Google Analytics