Javascript 中的构造函数

在静态语言中,一般一个类都有自己的构造函数。对于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中,理解并接纳其本身不同于其他语言的特色才是较为重要的。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容