關(guān)鍵詞:類鞋既,實例症革,原型
構(gòu)造函數(shù)定義:
構(gòu)造函數(shù)用于創(chuàng)建特定類型的對象——不僅聲明了使用的對象汉柒,構(gòu)造函數(shù)還可以接受參數(shù)以便第一次創(chuàng)建對象的時候設(shè)置對象的成員值强戴。你可以自定義自己的構(gòu)造函數(shù),然后在里面聲明自定義類型對象的屬性或方法残家。
如果你剛接觸構(gòu)造函數(shù)榆俺,上面的概念可以完全忽略了,因為你根本看不懂在講什么坞淮,直接跳過就好了茴晋。
先從工廠模式開始寫, 應該能更好理解構(gòu)造函數(shù)回窘。
工廠模式:
function create(name,age) {
var obj={};
obj.name=name;
obj.age=age;
obj.createJs=function () {
console.log(this.name+'和'+this.age)
}
return obj;
}
var p1=create('js',19);
p1.createJs();
如果把它改寫成構(gòu)造函數(shù)诺擅,就應該是這樣的:
function Create(name,age) {
// var obj={};
this.name=name;
this.age=age;
this.createJs=function () {
console.log(this.name+'和'+this.age)
}
// return obj;
}
var p1=new Create('js',19);
p1.createJs();
乍一看,差別很大啊啡直,是怎么改寫的呢烁涌?
搞明白構(gòu)造函數(shù)的特點,會更容易理解它們的區(qū)別酒觅。
1撮执、函數(shù)名大寫(不是規(guī)定,約定俗成的一種規(guī)范)舷丹;
2抒钱、執(zhí)行 new Create()
之后,Create
就有了一個新的名字:類(它依然是函數(shù)颜凯,也要形成一個私有作用域继效,形參賦值,預解釋装获,代碼從上到下執(zhí)行)
它的特點(與普通函數(shù)不同的地方)是:在代碼執(zhí)行之前瑞信,不用自己手動創(chuàng)建對象obj
了,所以看不到 obj
穴豫,瀏覽器會默認創(chuàng)建一個對象數(shù)據(jù)類型值(這個對象相當于構(gòu)造函數(shù)中的obj)凡简,也就是函數(shù)中的this。
3精肃、工廠模式里返回值是一個對象 p1秤涩,那么構(gòu)造函數(shù)里的返回值呢?
構(gòu)造函數(shù)里的代碼從上到下執(zhí)行司抱,默認地把創(chuàng)建的實例 p1 作為了返回值筐眷。并且以當前的實例(p1)為執(zhí)行的主體,把屬性名和屬性值賦給當前的實例 p1习柠。
如果再創(chuàng)造另一個實例 var p2=new CreateJs('js',19)
;那么 p1 和 p2 有什么關(guān)系匀谣,它們是獨立的照棋,沒有任何關(guān)系。p1==p2 //false;
上面的函數(shù)繼續(xù)改寫
function Create(name,age) {
var name='xiaoming';
this.name=name;
this.age=age;
this.createJs=function () {
console.log(this.name+'和'+this.age)
}
}
var p1=new Create('js',19);
上面只增加了一行代碼武翎,那么增加的一行代碼和實例有什么關(guān)系呢烈炭?答案是沒有任何關(guān)系,該如何理解呢宝恶?
先從概念上解析這句話符隙,構(gòu)造函數(shù)執(zhí)行后返回的是一個實例(對象),構(gòu)造函數(shù)把** 實例相關(guān)( this ) **的屬性和屬性值對實例進行賦值(別忘了 瀏覽器事先創(chuàng)建了一個obj
垫毙,最后把這個obj
返回出去變成了p1)霹疫, var name='xiaoming'
和obj沒有任何關(guān)系,它是構(gòu)造函數(shù)內(nèi)部私有變量综芥。
繼續(xù)改寫代碼
function Create(name,age) {
var name='xiaoming';
this.name=name;
this.age=age;
this.createJs=function () {
console.log(this.name+'和'+this.age)
}
return name;
// return function (){ console.log(11)};
}
var p1=new Create('js',19);
console.log(p1); //Create { name: 'xiaoming', age: 19, createJs: [Function] }
//console.log(p1);//結(jié)果是手動返回的函數(shù)
構(gòu)造函數(shù)執(zhí)行后丽蝎,默認返回一個對象。如果手動添加一個基本類型返回值毫痕,它的返回值依然是瀏覽器添加的默認返回值征峦;如果手動添加的返回值是一個引用數(shù)據(jù)類型迟几,那么它默認的返回值就會被覆蓋掉消请;所以最好不要給構(gòu)造函數(shù)添加返回值。
既然有了工廠模式类腮,為什么還要設(shè)計構(gòu)造函數(shù)模式呢?
/*工廠模式*/
function create(name, age) {
var obj={}
obj.name=name;
obj.age=age;
obj.createJs=function () {
console.log(this.name+'和'+this.age)
}
return obj;
}
var p1=create('js',18);
var p2=create('jss',19);
console.log(p1==p2)//false(完全不同的內(nèi)存地址)
/*構(gòu)造函數(shù)模式*/
function Create(name, age) {
this.name=name;
this.age=age;
this.createJs=function () {
console.log(this.name+'和'+this.age)
}
}
var p11=new Create('js',18);
var p22=new Create('jss',19);
console.log(p11==p22)//false
他們相似的地方是臊泰,每一個實例對象,都有自己的屬性和方法的副本蚜枢,每個實例都會占用不同的內(nèi)存空間缸逃。但是,如果每個實例上的** 共同屬性(不變的屬性) **都寫在構(gòu)造函數(shù)(類)內(nèi)部厂抽,那么每創(chuàng)造一個實例需频,就會把所有相關(guān)的屬性(包括共同屬性)拷貝到對應實例的內(nèi)存空間下,這是極大的資源浪費筷凤。例如:
function Create(name, age) {
this.name=name;
this.age=age;
this.chara=function(){ console.log('我們是公有屬性') };
this.createJs=function () {
console.log(this.name+'和'+this.age)
}
}
var p11=new Create('js',18);
var p22=new Create('js',18);
console.log(p11.chara==p22.chara);//false
this.chara
是每個實例共同擁有的方法昭殉,每次實例化就會拷貝到自對應實例的內(nèi)存空間下,造成了極大的浪費藐守,這是new方法的缺陷挪丢。
構(gòu)造函數(shù)為了解決這個問題,引入了原型prototype
卢厂,prototype
是一個對象乾蓬,是用來存儲實例的公有屬性和方法的。
Create.prototype.chara=function () {
console.log('share')
}
console.log(p11.chara) //function
console.log(p11.chara==p22.chara);//true
實例一旦創(chuàng)建慎恒,將自動引用prototype
對象的屬性和方法任内。也就是說撵渡,實例對象的屬性和方法,分成了兩種族奢,一種是本地的(私有的)姥闭,另一種是引用的(公有的)。
現(xiàn)在越走,chara
屬性放在prototype
對象里棚品,是兩個實例對象共享的。只要修改了prototype
對象廊敌,就會同時影響到兩個實例對象铜跑。
檢測實例是否屬于類
console.log(p1 instanceof Create); //true;
var arr=[];
console.log(arr instanceof Array); //true;