js 的constructor属性

引用类型null typeof null // object

所有的引用类型都是object

constructor 属性

定义和用法

constructor属性返回对创建此对象的数组函数的引用

demo1

let test = new Array();

console.log(test.constructor===Array)//true

demo2

function people(name,age){
this.name = name;
this.age = age;
}
let p1 = new people('z','18');
document.write(p1.constructor);
//function people(name,age){ this.name = name; this.age = age; }

在js语言中,constructor属性时专门为function而设计的,它存在于每一个function的prototype属性中,这个constructor保存了指向function的一个引用。

在定义一个函数时,function F(){} js内部会执行2个动作

  1 为该函数添加一个原型(prototype)属性

  2 为prototype对象额外添加一个constructor属性并且该属性保存指向函数F的一个引用

这样当我们把函数F作为一个构造函数来创建对象的时候,对象实例内部都会自动保存一个指向其构造函数的prototype对象的一个属性__proto__

所以我们在每一个对象实例中都可以访问构造函数的prototype所有拥有的属性和方法,就好像他们是实例自己的一样。当然该实例也有一个constructor属性了(从prototype那里获得的),每一个对象实例都可以通过constructor对象访问它的构造函数,(如下)

let f = new F()

console.log(f.constructor ===F)//true

console.log(f.constructor === F.prototype.constructor)//true

我们可以利用这个特性来完成下面的事情:

  对象的类型判断,if(f.constructor === F){//do something}

  其实constructor的出现本来就是用来进行对象类型判断的,但是constructor属性易变,不可信赖,所以我们用其他的方法进行判断,如if(f instanceof F){// do someThing}

原型链继承,忧郁constructor存在于prototype对象上,因此我们可以结合constructor 沿着原型链找到最原始的构造函数,

function Base(){}
function Sub1(){}
Sub1.prototype = new Base();
Sub1.prototype.constructor = Sub1;
Sub1.superclass = Base.prototype;
//console.log(Sub1);
//console.log(Sub1.prototype)// function Base(){}
//console.log(Sub1.prototype.constructor)// function Sub1(){}
//console.log(Sub1.superclass)// function Base(){}
function Sub2(){}
Sub2.prototype = new Sub1();
console.log(Sub2.prototype)//function Sub1(){}
Sub2.prototype.constructor = Sub2;
console.log(Sub2.prototype,constructor)//function Sub1(){}
console.log(Sub2.superclass)//undefined
Sub2.superclass = Sub1.prototype;
console.log(Sub2.superclass) //base{}


console.log(Sub2.prototype.constructor);// function Sub2(){}
console.log(Sub2.superclass.constructor);// Sub1(){}
console.log(Sub2.superclass.constructor.superclass.constructor);//Base(){}
上面的例子只是为了说明constructor在原型链中的作用,更实际一点的意思在于:一个子类对象可以获得其父类的所有
属性和方法,称之为继承。
之前说到了constructor易变,那是因为函数的prototype属性容易被更改,我们用demo说明
function F(){
  F.prototype = {
    _name:'123',
    getName:function(){

      return this._name
    }
  
  }
}
let f = new F();
console.log(f.constructor === F)//false
怎么回事?F不是实例对象f的构造函数了嘛?当然是,只不过构造函数F的原型被开发者重写了
这中方式将原来的prototype对象用一个对象的字面量{}来代替了,而新的对象{}只是Object
的一个势力,视同在解析的时候并不会在{}上自动添加一个constructor属性,因为这是function
创建是的专属操作,仅当你声明函数的时候解析器才会做此动作,然而你会发现constructor
并不是不存在的:下面证明
console.log(typeof f.constructor =="undefined")// false
尽然存在那整个constructor到底是从哪里的呢?
因为{}是创建对象的简写,所以这个{}相当于new Object(),那既然{}是Object的实例,
自然而然他获得一个指向构造函数Object()的prototype属性的一个引用__proto__,又因为
Object.prototype上有一个指向Object本身的constructor属性,所以可以看出这个constructor
其实就是Object.prototype的constructor,所以
console.log(f.constructor === Object.prototype.constructor)//true
console.log(f.constructor === Object)//true

一个解决办法就是手动回复他的constructor,看下面

function F(){

  F.prototype = {

    constructor:F,

    _name:'123'

}

}

这以后一切都回复正常了,constructor重新获得的构造函数的引用,我们可以再一次验证

let f= new F();

console.log(f.constructor === F);//true

疑问:构造函数上怎么还有一个constructor?他是从哪儿来的?

其实js的内建的构造函数,比如Array,RegExp,String,Number,

Object,Function都是有一个constructor的,

console.log(typeof Array.constructor != 'undefined')//true

这个东西不要搞混了,这个跟prototype上的constructor不是同一个对象,

他们是共存的。

console.log(Array.prototype.constructor === Array);//true

不过这件事也好理解,因为构造函数也是函数,是函数就说明它就是Function构造函数的实例对象,自然它内部也有一个指向Function.prototype的内部引用的__proto__,因此我们很用以得出结论,这个constructor其实就是Function构造函数的引用

console.log(Array.constructor === Function)//true

console.log(Fuinctuon.constructor === Function)//true

 

posted @ 2019-01-04 16:06  lieaiwen  阅读(5900)  评论(0编辑  收藏  举报