javascript - 原型对象的constructor

查看:95
本文介绍了javascript - 原型对象的constructor的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问 题

function Super(){
    this.name = "this is super";
}

Super.prototype = {
    say:function(){
        console.log(this.name);
    }
}

function Sub(){
    this.name = "this is sub";
}

Sub.prototype = new Super();

var o = new Sub();
o.say(); //this is sub

实例 o 的原型对象的constructor是Super,那么 this.name 应该是Super的构造函数。但是输出是 this is sub

解决方案

首先纠正题主理解上的错误:
对象o的constructor是Sub而不是Super。对象o的指向是Sub,然后Sub继承自Supervar o = new Sub()执行的是构造函数Sub,而Sub中又执行了this.name = "this is sub";

下面我们来深入分析一下题主代码的原理以及通过prototype继承发生的事情。别的不多说,我们来run一遍代码:

这是题主的源代码:

function Super(){
    this.name = "this is super";
}

Super.prototype = {
    say:function(){
        console.log(this.name);
    }
}

function Sub(){
    this.name = "this is sub";
}

Sub.prototype = new Super();

var o = new Sub();
o.say(); //this is sub

我们来看执行,前面的一堆声明我们先不看。

 

第一步,原型链继承

Sub.prototype=new Super();

这里发生了几件事:

  1. Sub.prototype设置为了new Supper

  2. 执行new Super,构建对象,暂且称这个对象为temp

  3. temp的原型指向挂在temp.__proto__下,大体可理解为temp.__proto__ = Sub.prototype

  4. 设置temp的属性,即这段代码:

    temp.name="this is super"

当这句Sub.prototype = new Super()执行完了之后,Sub.prototype是个什么状态呢?console一下我们就知道了:

{
   name : "this is super",
   __proto__ : {
        say : function () {
            console.log(this.name);
        },
        __proto__:...
   }
}

或者我们可以简单的理解为这样:

Sub.prototype={
   name : "this is super",
   say : function () {
      console.log(this.name);
   }
};

其实这时候,Sub已经成功继承了Super,内存指向如图。

 

第二步,创建对象o

var o = new Sub();

这里发生了几件事:

  1. 执行构造函数Sub

  2. 设置o.__proto__=Sub.prototype,这时候对象o大概可以理解为这样:

    {
        name: 'this is super',
        say: function () {
            console.log(this.name);
        }
    }

  3. 然后执行的,就是题主困惑的地方:构造函数Sub中执行了代码this.name="this is sub",即设置了o.name="this is sub",执行完了这里,对象o大体已经长成这样了:

    {
        name: 'this is sub',
        say: function () {
            console.log(this.name);
        }
    }

相比到了这里,大家应该知道是怎么一回事了吧,这时候内存指向如图:

所以最后,当执行o.say();的时候,输出的是this is sub

-------------- update - 应题主后来的追问:

题主后来追问内容:

var o = new Sub(); // 之前 Sub.prototype已经修改了,很疑惑构造函数是Sub。
Sub.prototype.constructor === Sub //false
new Sub() 执行的构造函数 不根据Sub.prototype.constructor 的指向么?

 

首先constructor是不安全属性,它是允许被重写的:

function Foo() {
    this.name = 'foo';
}

Foo.prototype = {};

var foo = new Foo;//{ }
foo.constructor == Foo.prototype.constructor //true
foo instanceof Foo //true

更鲜明一点的例子,我们直接声明一个对象:

var foo = { };
foo.constructor == Object.prototype.constructor //true

源代码中,prototype.constructor已经被重写为Object,因为这几段关键代码:

//省略部分代码

Super.prototype = {
    //这时候Super.prototype.constructor就已经指向Object了
    say: function () {
        console.log(this.name);
    }
}

//省略部分代码

//这时候Sub.prototype.constructor也已经指向了Object
Sub.prototype = new Super();

所以在题主的源代码上,这两段代码可以印证一切:

Super.prototype.constructor === Object //true
Sub.prototype.constructor === Object //true

因为constructor是不安全属性,它是允许被重写的,所以题主追问的判定代码并不正确。

另外constructor在对象的实现上是在构造函数里传递指向的,具体的实现可以参阅《ECMA-262标准实现规范 —— createdynamicfunction()》。

也即是说,是先运行构造函数,后指向constructor的(在构造函数里指向constructor)。


  • 本答案原创于 @linkFly ,和segmentfault.com共享,转载需保留本声明。

  • 前端开发QQ群:377786580

这篇关于javascript - 原型对象的constructor的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆