【重學】原型鏈

大綱:
構(gòu)造函數(shù)
手寫new命令
原型鏈
Object對象的相關(guān)方法

(x)易錯點

  • constructor表示構(gòu)造函數(shù)和原型對象之間的關(guān)聯(lián)關(guān)系媚送,如果修改了protype屬性温自,要同時修改constructor屬性,防止引用出錯
var P = function () {};
var p = new P();

var C = function () {};
C.prototype = p;  -------- C.prototype修改成了p亿扁,所以c.constructor === p.constructor === P.prototype.constructor,
var c = new C();

c.constructor.prototype === p // false --------------- 要想是p,就需要指定c.constructor = C
c.constructro.prototype === P.prototype // true 
(1) 實例只能訪問構(gòu)造函數(shù)prototype上的屬性髓考,不能直接修改構(gòu)造函數(shù)的prototype屬性
(2) 如果要修改,只能通過 x.constructor.prototype.color='yellow'方式修改

function A() {}
A.prototype.color = 'red'
const x = new A()
const y = new A()
x.color = 'yellow' ------------- 因為x.color是給x本身添加屬性并賦值弃酌,而不是修改x的原型對象的屬性
y.color?????  // 'red'
  • instanceof
1. instanceof原理:檢查 ( 右邊構(gòu)造函數(shù)的prototype屬性 ) 是否在 ( 左邊對象的原型鏈上 )

2. instanceof失效的情況:
  - 如果一個對象的__proto__是null氨菇,instanceof就會判斷失效
  - Object.prototype.__prototo__ === null
  - Object.prototype instanceof Ojbect       // false  
  // Object.create(null) instanceof Object   // false儡炼,因為創(chuàng)建的實例沒有任何屬性和方法,也沒有原型

(1)構(gòu)造函數(shù)

  • 函數(shù)名大寫查蓉,this代表將要生成的實例乌询,使用new命令生成實例
  • new命令:執(zhí)行構(gòu)造函數(shù),返回實例對象(new命令本身就可以執(zhí)行構(gòu)造函數(shù)豌研,所以后面的括號可以不要)
  • 如何保證構(gòu)造函數(shù)和new命令一起使用妹田?(忘記使用new了)
    1. 在構(gòu)造函數(shù)內(nèi)部使用嚴格模式:use strict,在嚴格模式下this不能指向window鹃共,默認是undefined鬼佣,undefined不能添加屬性,就會報錯
    2. 在構(gòu)造函數(shù)內(nèi)部判斷是否使用了new命令
  • new命令的原理霜浴?
    1. 生成一個空對象(作為要返回的實例對象)
    2. 將空對象的隱式原型指向構(gòu)造函數(shù)的prototype屬性
    3. 將構(gòu)造函數(shù)中的this指向新生成的空對象
    4. 執(zhí)行構(gòu)造函數(shù)
  • 手寫new命令
前置知識:

1. new命令返回值
  - new命令總是返回一個對象晶衷,要么是( 實列對象 ),要么return后面所跟的 (對象)

2. 構(gòu)造函數(shù)中的return語句阴孟,使用new命令時的返回情況
  - return 一個原始類型的值晌纫,使用new命令返回的是:-------------------------- this對象
  - return 一個對象,使用new命令返回的是:--------------------------------- return后面緊跟的那個對象温眉,而不是this對象
  - 如果構(gòu)造函數(shù)中沒有return語句缸匪,則默認返回的是:-------------------------- this對象

3. 如何判斷一個數(shù)據(jù)的數(shù)據(jù)類型?
  - typeof:返回 number类溢,string凌蔬,boolean,undefined闯冷,symbol砂心,ojbect,function(七種)
  - instanceof:- 原理是檢測 ( 右邊構(gòu)造函數(shù)的顯示原型prototype )是否在左邊 ( 實列對象的原型鏈上 )
                - instanceof只能用于對象蛇耀,不能用于原始類型的值
  - Object.prototype.toString().call(參數(shù)) ----------- 返回"[object 類型]"
  - js中的數(shù)據(jù)類型 number, string, boolean, null, undefined, symbol, object (七種)

4. arguments對象
  - 返回實參組成的類似數(shù)組的對象辩诞,該對象具有l(wèi)ength屬性
 
5. 如何把arguments對象轉(zhuǎn)換成真正的數(shù)組
  - Array.from(arguments)
  - Array.prototype.slice.call(arguments)

6. new命令的原理
  - 新建一個空對象,作為要返回的實列對象
  - 將空對象的隱式原型__proto__指向構(gòu)造函數(shù)的顯示原型prototype
  - 將構(gòu)造函數(shù)中的this指向空對象
  - 執(zhí)行構(gòu)造函數(shù)

7. 如何新建一個對象
  - Object.create(b) : 以參數(shù)對象為原型纺涤,生成實列對象
  - new Object()
  - 對象字面量
  - 注意:const a = Object.create(b) 即可以實現(xiàn) a.__proto__ === b == 構(gòu)造函數(shù).prototype

8. push unshift  和  pop shift
- push unsift 向數(shù)組添加數(shù)據(jù)译暂,改變原數(shù)組,有參數(shù)撩炊,返回值是添加過后的數(shù)組長度 ( 不是返回添加的值外永,因為參數(shù)中已經(jīng)知道 )
- pop shift 刪除數(shù)據(jù),改變原數(shù)組拧咳,沒有參數(shù)伯顶,所以返回值是刪除的數(shù)據(jù)值

9. new命令實行后的效果:
  - 生成的對象可以訪問構(gòu)造函數(shù)的屬性
  - 生成的對象可以訪問構(gòu)造函數(shù)prototype上的屬性

10. 手寫new命令

function Constructor(name, age) {
  this.name = name
  this.age = age
  // 構(gòu)造函數(shù)如果執(zhí)行new命令,默認返回的是this對象
  // 這里模擬的是new命令,所以手動返回this對象

  // 如果返回其他對象祭衩,不是this對象灶体,需要在構(gòu)造函數(shù)返回值中做判斷
  return this
}
Constructor.prototype.address = function() {
  console.log('shanghai')
}
function _new() {
  const obj = new Object()
  // 等于 const obj = {}
  // 等于 const obj = Object.create(null)       -------   以null為原型,生成實例對象

 const paramsConstructor =  Array.prototype.shift.call(arguments)
  // 等于 [].prototype.shift.call(arguments)
  // 等于 Array.prototype.shift.apply(arguments)
  // shift 刪除數(shù)組的第一個參數(shù)掐暮,改變原數(shù)組蝎抽,返回被刪除的值 ---------- push, unshift 返回被添加刪除的值
  // unshift 在數(shù)組的最前面添加數(shù)據(jù),返回添加過后數(shù)組的長度 ---------- pop, shift 返回更新后的數(shù)組長度
  // 把arguments對象中的構(gòu)造函數(shù)參數(shù)取出
  
  obj.__proto__ = paramsConstructor.prototype
  // 將空對象的隱式原型指向構(gòu)造函數(shù)的顯示原型

  const res = paramsConstructor.apply(obj, arguments)
  // 將構(gòu)造函數(shù)中的this指向空對象
  // 空對象就能訪問構(gòu)造函數(shù)中的屬性
  // apply第二個參數(shù)是數(shù)組路克,但是類似數(shù)組的對象也可以织中,會轉(zhuǎn)化成數(shù)組

  return /Object/.test(Object.prototype.toString.call(res)) ? res : obj
  // 如果構(gòu)造函數(shù)的返回的是一個和this無關(guān)對象則返回該對象,即res(this對象也返回)
  // 如果返回不是對象衷戈,就返回this對象,即空對象ojb
}
const b =  _new(Constructor, 'wu', 10)
console.log(b)

1.https://github.com/mqyqingfeng/Blog/issues/13

  1. https://segmentfault.com/a/1190000014452865

  2. https://segmentfault.com/a/1190000015276659

  • new命令可以用Object.setPrototypeOf()方法來模擬
function A() {
  this.name = 'wang'
}
const a = new A()


----

const resa = Object.setPrototypeOf({}, A.prototype) --------------- 將A.prototype設(shè)置成空對象的原型對象
A.call(resa) ------------------------------------------------------ 將構(gòu)造函數(shù)中的this指向空對象层坠,并執(zhí)行構(gòu)造函數(shù)

(2) 原型鏈

  • 原型對象的作用: 定義所有實列對象所共享的屬性和方法
  • 所有對象都是 Objecr.prototype 的實例殖妇,所有對象都有toString和valueOf方法,因為都繼承了Object.prototype上的這兩個方法
  • Object.prototype.__proto__ === null null沒有任何屬性和方法破花,也沒有自己的原型谦趣,原型鏈到此中止
  • constructor屬性定義在prototype上,所以construstor能被所有實例對象所共享
    a.constructor === A.prototype.constructor = A
  1. constructor屬性的作用
  • constructor的作用就是得知:實例對象到底是由哪個構(gòu)造函數(shù)產(chǎn)生的
  • 有了constructor屬性座每,就可以從一個實例新建另一個實例

特殊的原型鏈

特殊的原型鏈:

結(jié)論:
(1) 所有 ( 函數(shù)對象 ) 都是 ( Function構(gòu)造函數(shù) ) 的實例
  - 所以 Function.__proto__ === Function.prototype
  - 所以 fn.__protot__ === Function.prototype
  - 所以 Function instanceof Function  // true

(2) 所有函數(shù)的prototype對象都是Obect構(gòu)造函數(shù)的實例(!但是Object除外)
  - Function.prototype instanceof Object // true
  - function.prototype.__proto__ === Object.prototype
  - Object.protype instanceof Object  // false

(3)
Function instanceof Function   ------------------- true
Function instanceof Object     ------------------- true
Object instanceof Object       ------------------- true
Object instanceof Function     ------------------- true
原型鏈
20170503152146141.png

(3)Object對象的相關(guān)方法

1. Object.getPrototypeOf

Object.getPrototypeOf()返回參數(shù)對象的原型對象前鹅,是獲取原型對象的標準方法

Object.getPrototypeOf(params) 返回參數(shù)對象的原型對象,是獲取原型對象的標準方法

    function A() {}
    const a = new A()
    const res = Object.getPrototypeOf(a)
    console.log(a.__proto__ === res) // true
    console.log(A.prototype === res) // true

2. Object.setPrototypeOf(origin, pro)

將第二個參數(shù)設(shè)置成第一個參數(shù)的原型峭梳,返回該參數(shù)對象即第一個對象

Object.setPrototype(a,b) 將b對象設(shè)置成a對象的原型對象舰绘,返回值是a對象

    const a = {}
    const b = {name: 'wang'}
    const res = Object.setPrototypeOf(a, b)
    console.log(res) // {}
    console.log(Object.getPrototypeOf(a)) // {name: 'wang'}

Object.setPrototypeOf(a, b)可以用來模擬new命令

function A() {
  this.name = 'wang'
}
const a = new A()


----


const resa = Object.setPrototypeOf({}, A.prototype) --------------- 將A.prototype設(shè)置成空對象的原型對象
A.call(resa) ------------------------------------------------------ 將構(gòu)造函數(shù)中的this指向空對象,并執(zhí)行構(gòu)造函數(shù)

3. Object.create()

Object.create()以參數(shù)對象為原型葱椭,返回實例對象

以下生成對象的方式等價
Object.create({})
Object.create(Object.prototype)
new Object()

如果想要生成不繼承任何屬性的對象捂寿,可以用如下寫法

var obj = Object.create(null)


obj.valueOf()
// TypeError: Object [object Object] has no method 'valueOf'

因為obj的原型是null,所以obj不具備 Object.prototype上掛在的屬性和方法孵运,比如 valueOf秦陋,toString

Object.create()參數(shù)必須是個對象,不能為空或者不是對象

4. Object.prototype.isPrototypeOf

實例對象的isPrototypeOf用來判斷該對象是否為參數(shù)對象的原型

var o1 = {};
var o2 = Object.create(o1); // o1是o2的原型對象
var o3 = Object.create(o2); // o2是o3的原型對象

o2.isPrototypeOf(o3) // true ---------------------- 實例對象的isPrototypeOf用來判斷該實例對象是否是參數(shù)對象的原型
o1.isPrototypeOf(o3) // true
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末治笨,一起剝皮案震驚了整個濱河市驳概,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌旷赖,老刑警劉巖顺又,帶你破解...
    沈念sama閱讀 218,858評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異杠愧,居然都是意外死亡待榔,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,372評論 3 395
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來锐锣,“玉大人腌闯,你說我怎么就攤上這事〉胥荆” “怎么了姿骏?”我有些...
    開封第一講書人閱讀 165,282評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長斤彼。 經(jīng)常有香客問我分瘦,道長,這世上最難降的妖魔是什么琉苇? 我笑而不...
    開封第一講書人閱讀 58,842評論 1 295
  • 正文 為了忘掉前任嘲玫,我火速辦了婚禮,結(jié)果婚禮上并扇,老公的妹妹穿的比我還像新娘去团。我一直安慰自己,他們只是感情好穷蛹,可當我...
    茶點故事閱讀 67,857評論 6 392
  • 文/花漫 我一把揭開白布土陪。 她就那樣靜靜地躺著,像睡著了一般肴熏。 火紅的嫁衣襯著肌膚如雪鬼雀。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,679評論 1 305
  • 那天蛙吏,我揣著相機與錄音源哩,去河邊找鬼。 笑死出刷,一個胖子當著我的面吹牛璧疗,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播馁龟,決...
    沈念sama閱讀 40,406評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼崩侠,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了坷檩?” 一聲冷哼從身側(cè)響起却音,我...
    開封第一講書人閱讀 39,311評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎矢炼,沒想到半個月后系瓢,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,767評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡句灌,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,945評論 3 336
  • 正文 我和宋清朗相戀三年夷陋,在試婚紗的時候發(fā)現(xiàn)自己被綠了欠拾。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,090評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡骗绕,死狀恐怖藐窄,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情酬土,我是刑警寧澤荆忍,帶...
    沈念sama閱讀 35,785評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站撤缴,受9級特大地震影響刹枉,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屈呕,卻給世界環(huán)境...
    茶點故事閱讀 41,420評論 3 331
  • 文/蒙蒙 一微宝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧虎眨,春花似錦芥吟、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,988評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽钉稍。三九已至涤躲,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間贡未,已是汗流浹背种樱。 一陣腳步聲響...
    開封第一講書人閱讀 33,101評論 1 271
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留俊卤,地道東北人嫩挤。 一個月前我還...
    沈念sama閱讀 48,298評論 3 372
  • 正文 我出身青樓,卻偏偏與公主長得像消恍,于是被迫代替她去往敵國和親岂昭。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 45,033評論 2 355

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