構(gòu)造函數(shù)
根據(jù)調(diào)研锈锤,在使用new操作符通過構(gòu)造函數(shù)實(shí)例化一個(gè)對象時(shí),經(jīng)過了以下過程:
創(chuàng)建一個(gè)空對象闲询。
將這個(gè)空對象的__proto__成員指向了構(gòu)造函數(shù)對象的prototype成員對象久免。
將構(gòu)造函數(shù)的作用域賦給新對象,因此構(gòu)造函數(shù)中的this指向新對象扭弧,然后再在該對象上下文中調(diào)用構(gòu)造函數(shù)阎姥。
返回新創(chuàng)建對象。
注意:在JavaScript標(biāo)準(zhǔn)中鸽捻,并沒有__prop__這個(gè)屬性丁寄,不過它現(xiàn)在已經(jīng)是一些主流的JavaScript執(zhí)行環(huán)境默認(rèn)的一個(gè)標(biāo)準(zhǔn)屬性氨淌,用于指向構(gòu)造函數(shù)的原型。該屬性是默認(rèn)不可見的伊磺,而且在各執(zhí)行環(huán)境中實(shí)現(xiàn)的細(xì)節(jié)不盡相同,例如IE瀏覽器中不存在該屬性删咱。我們只要知道Javascript對象內(nèi)部存在指向構(gòu)造函數(shù)原型的指針就可以了屑埋,這個(gè)指針是在調(diào)用new表達(dá)式的時(shí)候自動(dòng)賦值的,并且我們不應(yīng)該去修改它痰滋。
function Person(msg){
//特權(quán)屬性(公有屬性)
this.myMsg = msg; //只在被實(shí)例化后的實(shí)例中可調(diào)用
this.address = '大連';
//私有屬性
var name = 'Sumer';
var age = 21;
var that = this;
//私有方法
function getName(){
alert(that.name);
}
//公有方法摘能,能被外部公開訪問,這個(gè)方法每次實(shí)例化都要重新構(gòu)造而prototype是原型共享敲街,所有實(shí)例化后团搞,都共同引用同一個(gè)
this.getAge = function(){
alert(age); //在公有方法中可以訪問私有成員
}
//私有和公有成員在函數(shù)的內(nèi)部,在構(gòu)造函數(shù)創(chuàng)建的每個(gè)實(shí)例中都會包含同樣的私有和公有成員的副本多艇,因而實(shí)例越多占用的內(nèi)存越多
//而且私有成員僅僅是在對象創(chuàng)建時(shí)逻恐,由構(gòu)造函數(shù)在對象上下文下運(yùn)行,不具有該對象的直接引用峻黍。
}
注意:由于JS函數(shù)的閉包特性复隆,這些私有成員,被所有在構(gòu)造函數(shù)中定義的公有方法所共享姆涩,而且僅被在構(gòu)造函數(shù)中定義的公有方法所共享挽拂。這意味著,在prototype中定義的類成員將不能訪問在構(gòu)造體中定義的私有成員骨饿。成員)亏栈。
//公有方法,適用于通過new關(guān)鍵字實(shí)例化的該對象的每個(gè)實(shí)例宏赘,向prototype中添加成員將會把新方法添加到構(gòu)造函數(shù)的底層中去
Person.prototype.sayHello = function(){
alert('hello world!');
}
//靜態(tài)屬性
//適用于對象的特殊實(shí)例绒北,就是作為Function對象實(shí)例的構(gòu)造函數(shù)本身
Person.name = 'china';
//靜態(tài)方法
Person.alertname = function(){
alert(this.name);
}
//實(shí)例化
var m1 = new Person('me');
//---- 測試屬性 ----//
//console.log(Person.name); //china
//console.log(m1.name); //undefined, 靜態(tài)屬性不適用于一般實(shí)例
//console.log(m1.constructor.name); //china, 想訪問類的靜態(tài)屬性,先訪問該實(shí)例的構(gòu)造函數(shù)置鼻,然后在訪問該類靜態(tài)屬性
//console.log(Person.address); //undefined,Person中的this指的不是函數(shù)本身镇饮,而是調(diào)用address的對象,而且只能是對象
//console.log(m1.address); //大連 此時(shí)this指的是實(shí)例化后的m1
//---- 測試方法 ----//
//Person.alertname(); //china,直接調(diào)用函數(shù)的類方法
//m1.alertname(); //FF: m1.alertname is not a function, alertname 是Person類的方法箕母,和實(shí)例對象沒有直接關(guān)系
//m1.constructor.alertname(); //china, 調(diào)用該對象構(gòu)造函數(shù)(類函數(shù))的方法(函數(shù))
//m1.sayHello(); //hello everyone, myObject類的prototype原型下的方法將會被實(shí)例繼承
//Person.sayHello(); //Person.sayHello is not a function储藐,sayHello是原型方法,不是類的方法
//---- 測試prototype ----//
//console.log(m1.prototype); //undefined, 實(shí)例對象沒有prototype
//console.log(Person.prototype); //Object
//alert(Person.prototype.constructor); //console.log返回Person(msg)嘶是,此時(shí)alert()更清楚钙勃,相當(dāng)于Person
//console.log(Person.prototype.constructor.name); //china, 相當(dāng)于Person.name;
由此分析可以清楚的了解到,使用私有成員聂喇,是以犧牲代碼可讀性為代價(jià)的辖源。而且這種實(shí)現(xiàn)更多的是一種JavaScript技巧蔚携,因?yàn)樗⒉皇钦Z言本身具有的機(jī)制。不應(yīng)該過多的應(yīng)用在JS的模型構(gòu)建中克饶。公有成員的使用酝蜒,更能提高我們代碼的可讀性,使我們構(gòu)建的模型更加清晰矾湃。