美文网首页
Javascript 中的构造函数

Javascript 中的构造函数

作者: 简单的怪石头 | 来源:发表于2020-03-26 21:06 被阅读0次

    在静态语言中,一般一个类都有自己的构造函数。对于Javascript而言,它其实也有自己的‘构造函数’,但是其‘构造函数’和静态语言相比存在很大的差别。
    直观来讲构造函数其实就是在构建一个实例的时候调用的函数,那在Javascript中是不是这样呢?

    普通对象中的构造函数

    为了证明是否会如此,我们先看一下Javascript的构造函数都在哪儿。其实它的构造函数都在其所对应的原型上,只是我们有不同的方式去拿到他。对于普通的对象来讲,如下可以查看其构造函数:

    const objectA = { name: "A's name" };
    objectA.constructor   // ƒ Object() { [native code] }
    objectA.__proto__.constructor // ƒ Object() { [native code] }
    

    由以上例子可见,一个通过对象字面量构建的对象,其构造函数是指向原型链上层Object的。以下测试代码可以帮助更清晰的了解实例对象&Object之间构造函数的关系

    objectA.constructor === objectA.__proto__.constructor // true
    objectA.constructor === Object //  true
    objectA.consturctor === Object.prototype.constructor // true
    

    第一行很好理解,但是第二行和第三行是怎么回事?而且可能你会问Object.constructor又和objectA.constructor是什么关系?

    函数的构造函数

    其实Object在Javascript中本质上是一个函数,一个直观的证明就是

    Object instanceof Function   // true
    

    函数本身来讲也有自己的构造函数,且在声明函数之后,其原型上构造函数就默认指向了自身。

    function funA() { console.log("this's function A");  }
    
    funA.prototype.constructor === funA  // true
    

    通过new关键字来用函数构建一个实例,它的构造函数就是指向函数原型上的构造函数的

    const instanceA = new funA();
    instanceA.constructor === funA   // true
    instanceA.constructor === funA.prototype.constructor  // true
    

    这样一来其实就可以和之前的普通对象的构造函数表现一致了。区别仅仅是在实例化的时候一个使用了对象字面量,一个使用了new关键字。但是本质上来讲对象字面量实例化对象和new Object({a: "name"})没有区别,所以这就能解释为什么objectA.constructor === Object结果为true了

    类中的构造函数

    在es6提供了关键字class,可以使得我们能像静态语言一样去声明一个类,但实质上它不过是一个语法糖,内部还是由函数、原型来实现的。所以就构造函数而言它的表现其实和函数的构造是一致的。

    class ClassA {
      constructor() { console.log("this is classA constructor"); }
    }
    ClassA.prototype.constructor === ClassA // true
    const instanceA = new ClassA();
    
    instanceA.constructor === ClassA   // true
    instanceA.constructor === ClassA.prototype.constructor  // true
    

    是真的构造函数吗

    在静态语言中,我们需要构建一个类的实例,需要使用new关键字去实例化一个对象,在使用new关键时会调用声明在类中的构造函数,那么在Javascript中是不是这样呢。我们可以拿类来做实验,这可能比较直观

    class ClassA {
      constructor() { console.log("this is classA constructor"); }
    }
    ClassA.prototype.constructor === ClassA // true
    const instanceA = new ClassA();  // this is classA constructor
    

    可以看到当我们去使用new关键直的时候,确实调用了在类中声明的构造函数中的代码。但是可能还不能这样直接断定Javascript确实是调用构造函数来构建的,看下面有趣的例子:

    class ClassA {
      constructor() {
       console.log("this is classA constructor");
     }
    }
    ClassA.prototype.constructor === ClassA // true
    const instanceA = new ClassA();  // this is classA constructor
    
    ClassA.prototype.constructor = function() { 
      console.log("this is new constructor")
    }
    const instanceB = new ClassA();  // this is classA constructor
    

    首先需要说明的是,在原型上的constructor是可写的,所以我们是可以重写原型上的constructor的,如上代码所示。如果和静态语言一样,在构建实例的时候,那么就应该使用新声明的构造函数啊,但是并没有这样。这使得Javascript中的class让人难以理解,对于习惯面向对象编程的同学来说更是头疼。就光能直接重写构造函数就已经不可理喻了。但是这个其实并不是什么大问题,因为类其实在Javascript中本来就只是一个语法糖,让习惯类写法的人更加舒畅,但是其背后的本质还是在使用原型机制,所以要将静态语言中类的一套说法硬搬到Javascript是不可能说得明白的。
    那既然如此constructor在Javascript中有什么用处呢?
    之前看到一些比较神奇的用法是,通过它来判断一个对象是不是某个函数的实例

    instanceA.__proto__.constructor === funcA.prototype.constructor
    

    这种比较是极不可靠的,因为我们在上一个示例已经看到,你可以随意的更改一个函数或类的构造函数,但是更改之后的实例化对象仍然应该是这个函数或者类的实例,一个例子一目了然

    class ClassA {
      constructor() {
       console.log("this is classA constructor");
     }
    }
    const instanceA = new ClassA();  
    ClassA.prototype.constructor = function() { 
      console.log("this is new constructor")
    }
    const instanceB = new ClassA();  
    instanceA.__proto__.constructor === instanceB.__proto__.constructor   // false
    instanceA instanceof ClassA   // true
    instanceB instanceof ClassA   // true
    

    constructor的随意告诉你,它是不可靠的,所以一般我们在编程中基本上不会依赖构造函数,即使类中有使用关键字,但是其本质上是在声明函数体中的内容,并不是在声明一个你以为的‘构造函数’。原型上的constructor方法,不过是在声明方法的时候顺手加上去的,仅此而已。

    小结

    Javascript中的构造函数和静态类型中的构造函数是完全不同的,而且Javascript原型上的构造函数其实并没有那么可靠,它在函数声明的时候指向了函数本身,但是在函数声明之后却仍然可以被修改,这个修改并不会修改函数原来的声明。它在Javascript中是随意的也是不可靠的,所以编程中也不会特意去使用或者修改它。就让它静静的呆着就好。
    ES6 提供了类的写法,但是并不能将类的一切东西生搬硬套到Javascript中,理解并接纳其本身不同于其他语言的特色才是较为重要的。

    相关文章

      网友评论

          本文标题:Javascript 中的构造函数

          本文链接:https://www.haomeiwen.com/subject/ruonyhtx.html