Javascript構(gòu)造函數(shù)零院、new溉跃、原型以及隱式原型

  • prototype原型對(duì)象
    無(wú)論什么時(shí)候,只要?jiǎng)?chuàng)建了一個(gè)新函數(shù)告抄,就會(huì)根據(jù)一組特定的規(guī)則為該函數(shù)創(chuàng)建一個(gè) prototype 屬性prototype既是屬性也是對(duì)象(事實(shí)上撰茎,他是一個(gè)指向某個(gè) 叫做 “原型對(duì)象"的對(duì)象 的屬性)
    這個(gè)原型對(duì)象的用途就是去包含所有共享的屬性和方法。例子是Array(Array是一個(gè)構(gòu)造數(shù)組的函數(shù)打洼,創(chuàng)建數(shù)組時(shí)被執(zhí)行)的slice就存在這里面

簡(jiǎn)單來(lái)說(shuō):prototype是一個(gè)容器龄糊,存著這個(gè)函數(shù)所有將共享的屬性和方法。
值得注意的是 :prototype其實(shí)是一個(gè)函數(shù)對(duì)象

  • __ proto__隱式原型
    js萬(wàn)物皆對(duì)象募疮,這些對(duì)象都有__ proto__屬性炫惩,即:對(duì)象具有屬性__ proto__,可稱(chēng)為隱式原型阿浓。
    一個(gè)對(duì)象的隱式原型指向構(gòu)造該對(duì)象的構(gòu)造函數(shù)的原型(下文通過(guò)new論證如何實(shí)現(xiàn))這也保證了實(shí)例能夠訪(fǎng)問(wèn)在構(gòu)造函數(shù)原型中定義的屬性和方法他嚷。(就像下面自定義屬性和方法那樣)

__ proto__指向這個(gè)實(shí)例的構(gòu)造器的原型即prototype,好比數(shù)組的__ proto__就指向了Array的原型芭毙,因此我們可以通過(guò)給Array的原型添加新的方法(比如切割)來(lái)玩弄數(shù)組爸舒。
為什么只能是Array而非我自己的構(gòu)造器呢?
因?yàn)槌悄悴挥肁rray這個(gè)構(gòu)造器來(lái)建立數(shù)組稿蹲,否則這個(gè)數(shù)組的__ proto__顯然是指向Array這個(gè)構(gòu)造器的原型而非是你的。所以理論上你如果可以用你自己的構(gòu)造器新建數(shù)組的話(huà)鹊奖,那這是ok的
特殊:函數(shù)本身的構(gòu)造器是Function苛聘,于是函數(shù)的__ proto__指向Function.prototype(寫(xiě)在js內(nèi)部)

通過(guò)constructor(暫不知why) 我們還可繼續(xù)為原型對(duì)象添 加其他屬性和方法 (如下方2.1)

  • 構(gòu)造函數(shù):一個(gè)返回this對(duì)象的函數(shù)
    • 構(gòu)造函數(shù)和普通函數(shù)的區(qū)別在于:調(diào)用方式不一樣。作用也不一樣(構(gòu)造函數(shù)用來(lái)新建實(shí)例對(duì)象)配合new可以實(shí)現(xiàn)自動(dòng)化

    • 構(gòu)造函數(shù)的函數(shù)名與類(lèi)名相同:Person( ) 這個(gè)構(gòu)造函數(shù)忠聚,Person 既是函數(shù)名设哗,也是這個(gè)對(duì)象的類(lèi)名

    • 內(nèi)部用this 來(lái)構(gòu)造屬性和方法

    • 構(gòu)造流程

let Parent = function (name, age) {
    //1.創(chuàng)建一個(gè)新對(duì)象,賦予this两蟀,這一步是隱性的网梢,
    // let this = {};
    //2給this指向的對(duì)象賦予構(gòu)造屬性
    this.name = name;
    this.age = age;
    //3.如果沒(méi)有手動(dòng)返回對(duì)象,則默認(rèn)返回this指向的這個(gè)對(duì)象赂毯,也是隱性的
    // return this;
};

注意:上面的三步走并不是指這個(gè)函數(shù)會(huì)這么執(zhí)行战虏,而是new的時(shí)候幫它執(zhí)行這三步了
是new幫它return的 當(dāng)然 你可以手動(dòng)創(chuàng)建that 然后return

  • new的過(guò)程發(fā)生了什么
    ? 以構(gòu)造器的prototype屬性(即存放公共方法或?qū)傩缘哪莻€(gè)對(duì)象)為原型(即__ proto__)拣宰,創(chuàng)建新對(duì)象,即:還是個(gè)空對(duì)象時(shí)烦感,就有了那些公共屬性
    ? 將this(也就是上一句中的新對(duì)象)和調(diào)用參數(shù)傳給構(gòu)造器巡社,執(zhí)行;
    ? 如果構(gòu)造器沒(méi)有手動(dòng)返回對(duì)象手趣,則返回第一步創(chuàng)建的對(duì)象

  • 原型鏈
    age是怎么找到的呢晌该,首先會(huì)去person1的私有屬性(本身的屬性),有沒(méi)有age绿渣,如果有的話(huà)就去這個(gè)屬性的值朝群,如果沒(méi)有就會(huì)查找person1.__ proto__指向上的對(duì)象(即Person.prototype)有沒(méi)有該屬性有的話(huà)就會(huì)返回該屬性的值,如果沒(méi)有接著查找person1.__ proto__.__ proto__* 即指向了Object.prototype (因?yàn)開(kāi)_ proto__也是由Object構(gòu)造器構(gòu)造的嘛)然后看有沒(méi)有你寫(xiě)的屬性或者方法 沒(méi)有的就返回undefined了中符。上述的查找過(guò)程就是作用域鏈姜胖。
    什么叫'直到Object.prototype指向的對(duì)象有沒(méi)有'*)?
    就是一路按相同規(guī)則查找就完事了 修改在上面了。

function Person1(){ }
Person1.prototype.name = "Nicholas"; 
Person1.prototype.age = 29; 
Person1.prototype.job = "Software Engineer";
Person1.prototype.sayName = function(){ alert(this.name); };

var Person2 = function(){
this.name = 'pj';
Person1.prototype.name = "jy"; //寫(xiě)外面也行
}

var person1 = new Person1();
person1.sayName(); //"Nicholas"
person1.age; // 29
var person2 = new Person2;//()可有可無(wú)
person2.name;//pj 而非jy
  • constructor來(lái)鞏固原型鏈
    原型對(duì)象有一個(gè)默認(rèn)屬性舟茶,叫做constructor谭期,這個(gè)屬性指回原構(gòu)造函數(shù)。即Person.prototype.constructor===Person
    如此 p.constuctor 順著原型鏈:找不到這個(gè)名字吧凉,那就找__ proto__ 而所有除了函數(shù)外的對(duì)象的__ proto__其實(shí)都指向了構(gòu)造器的prototype(原理上面講了) 于是隧出,找到了constructor,發(fā)現(xiàn)阀捅,constructor永遠(yuǎn)指向這個(gè)構(gòu)造函數(shù)本身胀瞪,于是,就指回了他爸Person
function Person(name) {
    this.name = name
}
// 修改原型
Person.prototype.getName = function() {}
var p = new Person('jack')
console.log(p.__proto__ === Person.prototype) // true
console.log(p.constructor === Person) // true
console.log(p.__proto__ === p.constructor.prototype) // true
  • 自己實(shí)現(xiàn)一切:
    • 先熟悉apply是什么
1.apply示例:  
  
<script type="text/javascript">   
/*定義一個(gè)人類(lèi)*/   
function Person(name,age) {   
    this.name=name; this.age=age;   
}   
 /*定義一個(gè)學(xué)生類(lèi)*/   
functionStudent(name,age,grade) {   
    Person.apply(this,arguments); this.grade=grade;   
}   
//創(chuàng)建一個(gè)學(xué)生類(lèi)   
var student=new Student("qian",21,"一年級(jí)");   
//測(cè)試   
alert("name:"+student.name+"\n"+"age:"+student.age+"\n"+"grade:"+student.grade);   
//大家可以看到測(cè)試結(jié)果name:qian age:21 grade:一年級(jí)   
//學(xué)生類(lèi)里面我沒(méi)有給name和age屬性賦值啊,為什么又存在這兩個(gè)屬性的值呢,這個(gè)就是apply的神奇之處.   
</script>   

分析: Person.apply(this,arguments);
this:在創(chuàng)建對(duì)象在這個(gè)時(shí)候代表的是student這個(gè)對(duì)象//為什么這時(shí)student就是對(duì)象了饲鄙?
arguments:是一個(gè)數(shù)組,也就是[“qian”,”21”,”一年級(jí)”];
也就是通俗一點(diǎn)講就是:用student去執(zhí)行Person這個(gè)類(lèi)里面的內(nèi)容,在Person這個(gè)類(lèi)里面存在this.name等之類(lèi)的語(yǔ)句,這樣就將屬性創(chuàng)建到了student對(duì)象里面
以黑盒子理解:傳一個(gè)對(duì)象和一堆參數(shù)(數(shù)組)進(jìn)去凄诞。只要目標(biāo)函數(shù)(Person)是個(gè)合格的構(gòu)造函數(shù),那他就會(huì)幫你把這個(gè)對(duì)象的屬性給生成好忍级!
拓展:call也差不多

  • 正式開(kāi)始:
// 構(gòu)造器函數(shù)
let Parent = function (name, age) {
    this.name = name;
    this.age = age;
};
Parent.prototype.sayName = function () {
    console.log(this.name);
};
//自己定義的new方法
let newMethod = function (Parent, ...rest) {
    //執(zhí)行三步走戰(zhàn)略
    // 1.以構(gòu)造器的prototype屬性為原型帆谍,創(chuàng)建新對(duì)象;
    let child = Object.create(Parent.prototype);
    // 2.將this和調(diào)用參數(shù)傳給構(gòu)造器執(zhí)行 利用apply 把child的屬性生成好
    Parent.apply(child, rest);
    // 3.返回第一步的對(duì)象
    return child;
};
//創(chuàng)建實(shí)例轴咱,將構(gòu)造函數(shù)Parent與形參作為參數(shù)傳入
const child = newMethod(Parent, 'echo', 26);
child.sayName() //'echo';

//最后檢驗(yàn)汛蝙,與使用new的效果相同
child instanceof Parent//true
child.hasOwnProperty('name')//true
child.hasOwnProperty('age')//true
child.hasOwnProperty('sayName')//false
  • constuctor
    可以理解為一個(gè)標(biāo)記作用 方便追溯分類(lèi)構(gòu)造器
var arr = []
//  恒為真
arr.constructor === Array
var num = 2
//  恒為真
num.constructor === Number
var str = '123'
//  恒為真
str.constructor === String
  • instanceof檢測(cè)Parent的原型是否在child的原型鏈中
    • constructor改變后 不會(huì)改變instanceof child instanceof Parent == true
      如何改變instanceof的結(jié)果呢?方法如下:
      Parent.prototype = {};//覆寫(xiě)原型 使得原型鏈斷掉
      child.prototype.__proto__ !== Parent.prototype
  • ownProperty 用于確定某個(gè)屬性是在實(shí)例上還是在原型上 如果是,返回true
  • 方法和屬性要寫(xiě)在prototype還是構(gòu)造器里朴肺?
    • 如果寫(xiě)在構(gòu)造器:每次構(gòu)造對(duì)象時(shí)窖剑,這些屬性和方法將被完全重新生成并寫(xiě)入該對(duì)象(為了實(shí)現(xiàn)私有),會(huì)耗費(fèi)對(duì)應(yīng)的內(nèi)存
    • 如果寫(xiě)在prototype里:每次構(gòu)造對(duì)象時(shí)戈稿,會(huì)將__ proto__指過(guò)來(lái)西土,從而不用重新生成,也就是說(shuō)鞍盗,他是所有對(duì)應(yīng)實(shí)例所共享的需了,無(wú)論是person1還是person2訪(fǎng)問(wèn)的都是相同的屬性跳昼,相同的sayname(),這個(gè)過(guò)程叫做原型繼承援所,顯然庐舟,誰(shuí)都可以訪(fǎng)問(wèn),就無(wú)法私有了
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末住拭,一起剝皮案震驚了整個(gè)濱河市挪略,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌滔岳,老刑警劉巖杠娱,帶你破解...
    沈念sama閱讀 217,277評(píng)論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異谱煤,居然都是意外死亡摊求,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,689評(píng)論 3 393
  • 文/潘曉璐 我一進(jìn)店門(mén)刘离,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)室叉,“玉大人,你說(shuō)我怎么就攤上這事硫惕〖牒郏” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 163,624評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵恼除,是天一觀(guān)的道長(zhǎng)踪旷。 經(jīng)常有香客問(wèn)我,道長(zhǎng)豁辉,這世上最難降的妖魔是什么令野? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,356評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮徽级,結(jié)果婚禮上气破,老公的妹妹穿的比我還像新娘。我一直安慰自己餐抢,他們只是感情好堵幽,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,402評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著弹澎,像睡著了一般。 火紅的嫁衣襯著肌膚如雪努咐。 梳的紋絲不亂的頭發(fā)上苦蒿,一...
    開(kāi)封第一講書(shū)人閱讀 51,292評(píng)論 1 301
  • 那天,我揣著相機(jī)與錄音渗稍,去河邊找鬼佩迟。 笑死团滥,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的报强。 我是一名探鬼主播灸姊,決...
    沈念sama閱讀 40,135評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼秉溉!你這毒婦竟也來(lái)了力惯?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 38,992評(píng)論 0 275
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤召嘶,失蹤者是張志新(化名)和其女友劉穎父晶,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體弄跌,經(jīng)...
    沈念sama閱讀 45,429評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡甲喝,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,636評(píng)論 3 334
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了铛只。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片埠胖。...
    茶點(diǎn)故事閱讀 39,785評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖淳玩,靈堂內(nèi)的尸體忽然破棺而出直撤,到底是詐尸還是另有隱情,我是刑警寧澤凯肋,帶...
    沈念sama閱讀 35,492評(píng)論 5 345
  • 正文 年R本政府宣布谊惭,位于F島的核電站,受9級(jí)特大地震影響侮东,放射性物質(zhì)發(fā)生泄漏圈盔。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,092評(píng)論 3 328
  • 文/蒙蒙 一悄雅、第九天 我趴在偏房一處隱蔽的房頂上張望驱敲。 院中可真熱鬧,春花似錦宽闲、人聲如沸众眨。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,723評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)娩梨。三九已至,卻和暖如春览徒,著一層夾襖步出監(jiān)牢的瞬間狈定,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,858評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留纽什,地道東北人措嵌。 一個(gè)月前我還...
    沈念sama閱讀 47,891評(píng)論 2 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像芦缰,于是被迫代替她去往敵國(guó)和親企巢。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,713評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容