引用類型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