this & 原型鏈 & 繼承

What's this?

由于運(yùn)行期綁定的特性,JavaScript 中的 this 含義非常多纪挎,它可以是全局對(duì)象沽甥、當(dāng)前對(duì)象或者任意對(duì)象屯换,這完全取決于函數(shù)的調(diào)用方式

隨著函數(shù)使用場(chǎng)合的不同杠娱,this的值會(huì)發(fā)生變化挽牢。但是有一個(gè)總的原則谱煤,那就是this指的是摊求,調(diào)用函數(shù)的那個(gè)對(duì)象

作為函數(shù)調(diào)用

  • 在函數(shù)被直接調(diào)用時(shí)this綁定到全局對(duì)象。在瀏覽器中刘离,window 就是該全局對(duì)象
 var a = 1
    console.log(this) //全局對(duì)象window
    function fn(){
        console.log(a) //1
        console.log(this) //window
        console.log(b) //b is nor defined
    }
    fn()

內(nèi)部函數(shù)

  • 函數(shù)嵌套產(chǎn)生的內(nèi)部函數(shù)的this不是其父函數(shù)室叉,仍然是全局變量
 function fn(){
       function fn1(){
           console.log(this) //window
       }
       fn1()
   }
   fn()

setTimeout、setInterval

  • 這兩個(gè)方法執(zhí)行的函數(shù)this也是全局對(duì)象
document.addEventListener('click', function(e){
  console.log(this); //document
    setTimeout(function(){
        console.log(this); //window
    }, 200);
}, false);
  • 如果想在setTimeout硫惕、setInterval執(zhí)行的函數(shù)中返回的this是document茧痕,方法一只需要有一個(gè)中間變量,保存this即可恼除。
 document.addEventListener('click',function(e){
       console.log(this) //document
       var _this = this
       setTimeout(function(){
           console.log(_this) //document
       })
   })
  • 如果想在setTimeout踪旷、setInterval執(zhí)行的函數(shù)中返回的this是document,方法二豁辉,使用bind令野,使其第一個(gè)參數(shù)為this
document.addEventListener('click',function(e){
        setTimeout(function(){
            console.log(this) //document
        }.bind(this))
    })

作為構(gòu)造函數(shù)調(diào)用

  • 所謂構(gòu)造函數(shù),就是通過(guò)這個(gè)函數(shù)生成一個(gè)新對(duì)象(object)徽级。這時(shí)气破,this就指這個(gè)新對(duì)象

new 運(yùn)算符接受一個(gè)函數(shù) F 及其參數(shù):new F(arguments...)。這一過(guò)程分為三步:

  1. 創(chuàng)建類的實(shí)例餐抢。這步是把一個(gè)空的對(duì)象的 proto 屬性設(shè)置為 F.prototype 现使。
  2. 初始化實(shí)例。函數(shù) F 被傳入?yún)?shù)并調(diào)用旷痕,關(guān)鍵字 this 被設(shè)定為該實(shí)例碳锈。
  3. 返回實(shí)例。

具體實(shí)例:

function People(name){
       this.name = name
   }
   People.prototype.sayName = function(){
       console.log(this.name)
   }
   var p1 = new People('lili')
  • 作為對(duì)象方法調(diào)用
    在 JavaScript 中欺抗,函數(shù)也是對(duì)象殴胧,因此函數(shù)可以作為一個(gè)對(duì)象的屬性,此時(shí)該函數(shù)被稱為該對(duì)象的方法,在使用這種調(diào)用方式時(shí)团滥,this 被自然綁定到該對(duì)象
var obj = {
       name: 'kasck',
       fn: function(){
           console.log(this) //obj
       }
   }
   obj.fn()
  • 對(duì)象方法的嵌套
var obj2 = {
       name: 'lll',
        obj3: {
           fn: function(){
               console.log(this) // obj3
           }
        }
    }
    obj2.obj3.fn()
  • 小陷阱
  var obj = {
       name: 'kasck',
       fn: function(){
           console.log(this) 
       }
   }
   obj.fn()

    var fn2 = obj.fn
    fn2() //window.fn2() this === window

Function.prototype.bind

bind:返回一個(gè)函數(shù)竿屹,并且使函數(shù)內(nèi)部的this為傳入的第一個(gè)參數(shù)

var obj = {
       name: 'kasck',
       fn: function(){
           console.log(this)
       }
   }
   obj.fn()
    obj3 = {a:3}
    var fn3 = obj.fn.bind(obj3) //fn3函數(shù)內(nèi)部的this為bind傳入的第一個(gè)參數(shù)
    fn3() // this = obj3

使用call和apply設(shè)置this

  • call和apply調(diào)用一個(gè)函數(shù)傳入函數(shù)執(zhí)行上下文參數(shù)。
fn.call(context,parma1,parma2...);
fn.apply(context,paramArray);

語(yǔ)法很簡(jiǎn)單灸姊,第一個(gè)參數(shù)都是希望設(shè)置的this對(duì)象拱燃,不同之處在于call方法接收參數(shù)列表,而apply接收參數(shù)數(shù)組力惯。

fn2.call(obj1);
fn2.apply(obj2);
  • call的實(shí)例
 var value = 100;
   var obj4 = {
       value: 200
   };
    function fn4(a,b){
       console.log(this.value + a + b)
    }
    fn4(3,4) //107
    fn4.call(obj4,3,4) //207
  • apply的實(shí)例
//與call對(duì)比碗誉,僅僅是調(diào)用參數(shù)的方式不同
    fn4.apply(obj4,[3,4]) 207

更多用法

function joinStr(){
        console.log(Array.prototype.join.call(arguments)) //a,b,c
        console.log(Array.prototype.join.call(arguments,'-')) //a-b-c
        var join = Array.prototype.join.bind(arguments)
        console.log(join('-')) //a-b-c
    }
   joinStr('a','b','c')

得到一個(gè)數(shù)組的最大值和最小值

    var arr = [1,3,5,9]
    console.log(Math.max.apply(null,arr)) //9
    console.log(Math.max.call(null,arr)) //NAN
    console.log(Math.max.call(null,1,3,5,9)) //9

call與apply的不同之處:

  • apply:
    最多只能有兩個(gè)參數(shù):新this對(duì)象和一個(gè)數(shù)組argArray。如果給該方法傳遞多個(gè)參數(shù)父晶,則把參數(shù)都寫進(jìn)這個(gè)數(shù)組里面哮缺,當(dāng)然,即使只有一個(gè)參數(shù)甲喝,也要寫進(jìn)數(shù)組里面尝苇。如果argArry不是一個(gè)有效的數(shù)組或者不是arguments對(duì)象,那么將導(dǎo)致一個(gè)TypeError埠胖。如果沒(méi)有提供argArry和thisObj任何一個(gè)參數(shù)糠溜,那么Global對(duì)象將被用作thisObj,并且無(wú)法被傳遞任何參數(shù)直撤。
  • call:
    則是直接的參數(shù)列表非竿,主要用在JS對(duì)象各方法互相調(diào)用的時(shí)候,使當(dāng)前this實(shí)例指針保持一致或在特殊情況下需要改變this指針谋竖。如果沒(méi)有提供thisObj參數(shù)红柱,那么Global對(duì)象將被用作thisObj。

caller

在函數(shù)A調(diào)用函數(shù)B時(shí)蓖乘,被調(diào)用函數(shù)B會(huì)自動(dòng)生成一個(gè)caller屬性锤悄,指向調(diào)用它的函數(shù)對(duì)象,如果函數(shù)當(dāng)前未被調(diào)用驱敲,或并非被其他函數(shù)調(diào)用铁蹈,則caller為null

    function fn(){
        function fn1(){
            console.log(fn1.caller) //fn
        }
        fn1()
    }
    fn()

arguments

  1. 在函數(shù)調(diào)用時(shí),會(huì)自動(dòng)在該函數(shù)內(nèi)部生成一個(gè)名為 arguments的隱藏對(duì)象
  2. 該對(duì)象類似于數(shù)組众眨,可以使用[]運(yùn)算符獲取函數(shù)調(diào)用時(shí)傳遞的實(shí)參
  3. 只有函數(shù)被調(diào)用時(shí)握牧,arguments對(duì)象才會(huì)創(chuàng)建,未調(diào)用時(shí)其值為null
  function fn(name,age){
        console.log(arguments)
        var name = "frank"
        console.log(arguments)
        arguments[1] = 14
        console.log(arguments)
    }
    fn('lili',23)

函數(shù)的執(zhí)行環(huán)境

一個(gè)函數(shù)被執(zhí)行時(shí)娩梨,會(huì)創(chuàng)建一個(gè)執(zhí)行環(huán)境(ExecutionContext)沿腰,函數(shù)的所有的行為均發(fā)生在此執(zhí)行環(huán)境中,構(gòu)建該執(zhí)行環(huán)境時(shí)狈定,JavaScript 首先會(huì)創(chuàng)建 arguments變量颂龙,其中包含調(diào)用函數(shù)時(shí)傳入的參數(shù)

接下來(lái)創(chuàng)建作用域鏈习蓬,然后初始化變量。首先初始化函數(shù)的形參表措嵌,值為 arguments變量中對(duì)應(yīng)的值躲叼,如果 arguments變量中沒(méi)有對(duì)應(yīng)值,則該形參初始化為 undefined企巢。

如果該函數(shù)中含有內(nèi)部函數(shù)枫慷,則初始化這些內(nèi)部函數(shù)。如果沒(méi)有浪规,繼續(xù)初始化該函數(shù)內(nèi)定義的局部變量或听,需要注意的是此時(shí)這些變量初始化為 undefined,其賦值操作在執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功后笋婿,函數(shù)執(zhí)行時(shí)才會(huì)執(zhí)行誉裆,這點(diǎn)對(duì)于我們理解JavaScript中的變量作用域非常重要,最后為this變量賦值缸濒,會(huì)根據(jù)函數(shù)調(diào)用方式的不同足丢,賦給this全局對(duì)象,當(dāng)前對(duì)象等

至此函數(shù)的執(zhí)行環(huán)境(ExecutionContext)創(chuàng)建成功绍填,函數(shù)開(kāi)始逐行執(zhí)行霎桅,所需變量均從之前構(gòu)建好的執(zhí)行環(huán)境(ExecutionContext)中讀取

三種變量

  1. 實(shí)例變量:(this)類的實(shí)例才能訪問(wèn)到的變量
  2. 靜態(tài)變量:(屬性)直接類型對(duì)象能訪問(wèn)到的變量
  3. 私有變量:(局部變量)當(dāng)前作用域內(nèi)有效的變量
function fn(){
        var a = 1 //局部變量
        this.b = 3 //實(shí)例變量
}
fn.c = 5 //靜態(tài)變量

原型鏈

  • 代碼示例:
    function Person(name,age){
        this.name = name;
        this.age = age
    }
    Person.prototype.sayName = function(){
        console.log(this.name)
    }
    var p1 = new Person('lili',1);
    var p2 = new Person('llll',3);
    p1.sayName()
    p2.sayName()
  • 原型圖


    捕獲.PNG
     p1.__proto__.constructor === Person
    Person.prototype.constructor === Person
    p1.constructor === Person
  1. 我們通過(guò)函數(shù)定義了類Person栖疑,類(函數(shù))自動(dòng)獲取屬性prototype
  2. 每個(gè)類的實(shí)例都會(huì)有一個(gè)內(nèi)部屬性__proto__讨永,指向類的prototype·

如果想看某一個(gè)對(duì)象xx是由誰(shuí)創(chuàng)建的,只需要看xx.proto.constructor === y,就由y創(chuàng)建遇革。

原型鏈相關(guān)問(wèn)題

有如下代碼卿闹,解釋Person、 prototype萝快、proto锻霎、p、constructor之間的關(guān)聯(lián)揪漩。

function Person(name){
    this.name = name;
}
Person.prototype.sayName = function(){
    console.log('My name is :' + this.name);
}
var p = new Person("若愚")
p.sayName();
  • 通過(guò)函數(shù)定義了類Person旋恼,類(函數(shù))自動(dòng)獲取屬性prototype;
  • 每個(gè)類的實(shí)例都會(huì)有一個(gè)內(nèi)部屬性__proto__奄容,指向類的prototype冰更;
  • P是構(gòu)造函數(shù)Person的一個(gè)實(shí)例,p的__proto__指向了Person的prototype屬性昂勒;
  • prototype是構(gòu)造函數(shù)內(nèi)部的原型函數(shù)蜀细,所以擁有prototype和__proto__屬性,其中contructor屬性指向構(gòu)造函數(shù)Person戈盈,__proto__指向該對(duì)象的原型奠衔。

上例中谆刨,對(duì)對(duì)象 p可以這樣調(diào)用 p.toString()。toString是哪里來(lái)的? 畫出原型圖?并解釋什么是原型鏈归斤。

p.toString()方法是繼承構(gòu)造函數(shù)Object的原型對(duì)象里定義的toString()方法痊夭,首先p會(huì)找到自己的toString()方法,如果沒(méi)有找到脏里,會(huì)沿著__proto__屬性繼續(xù)到構(gòu)造函數(shù)Person的prototype里找toString()方法生兆,如果還是未找到,再繼續(xù)往Person.prototype__proto__找膝宁。

QQ圖片20171018133901.png

原型鏈:由于原型對(duì)象本身也是對(duì)象鸦难,而每個(gè)JavaScript對(duì)象都有一個(gè)原型對(duì)象,每個(gè)對(duì)象都有一個(gè)隱藏的proto屬性员淫,原型對(duì)象也有自己的原型合蔽,而它自己的原型對(duì)象又可以有自己的原型,這樣就組成了一條鏈介返,這個(gè)就是原型鏈拴事。在訪問(wèn)對(duì)象的屬性時(shí),如果在對(duì)性本身中沒(méi)有找到圣蝎,則會(huì)去原型鏈中查找刃宵,如果找到,則返回值徘公,如果整個(gè)鏈都沒(méi)有找到牲证,則返回undefined。

instanceOf有什么作用关面??jī)?nèi)部邏輯是如何實(shí)現(xiàn)的坦袍?

instanceOf:判斷一個(gè)對(duì)象是否為另一個(gè)對(duì)象的實(shí)例

//
    function isInstanceOf(obj,fn){ 
        var oldProto = obj.__proto__; 
        do{ 
            if(oldProto === fn.prototype){ //prototype是小寫的! 
                return true; 
            }else{ 
                oldProto = oldProto.__proto__; 
            } 
        }while(oldProto){ 
            return false; 
        } 
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末等太,一起剝皮案震驚了整個(gè)濱河市捂齐,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌缩抡,老刑警劉巖奠宜,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異瞻想,居然都是意外死亡压真,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門内边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)榴都,“玉大人,你說(shuō)我怎么就攤上這事漠其∽旄撸” “怎么了竿音?”我有些...
    開(kāi)封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)拴驮。 經(jīng)常有香客問(wèn)我春瞬,道長(zhǎng),這世上最難降的妖魔是什么套啤? 我笑而不...
    開(kāi)封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任宽气,我火速辦了婚禮,結(jié)果婚禮上潜沦,老公的妹妹穿的比我還像新娘萄涯。我一直安慰自己,他們只是感情好唆鸡,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布涝影。 她就那樣靜靜地躺著,像睡著了一般争占。 火紅的嫁衣襯著肌膚如雪燃逻。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天臂痕,我揣著相機(jī)與錄音伯襟,去河邊找鬼。 笑死握童,一個(gè)胖子當(dāng)著我的面吹牛姆怪,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播舆瘪,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼片效,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼红伦!你這毒婦竟也來(lái)了英古?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤昙读,失蹤者是張志新(化名)和其女友劉穎召调,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體蛮浑,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡唠叛,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了沮稚。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片艺沼。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖蕴掏,靈堂內(nèi)的尸體忽然破棺而出障般,到底是詐尸還是另有隱情调鲸,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布挽荡,位于F島的核電站藐石,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏定拟。R本人自食惡果不足惜于微,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望青自。 院中可真熱鬧株依,春花似錦、人聲如沸延窜。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)需曾。三九已至吗坚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間呆万,已是汗流浹背商源。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留谋减,地道東北人牡彻。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像出爹,于是被迫代替她去往敵國(guó)和親庄吼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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

  • this 相關(guān)問(wèn)題 1. apply严就、call 总寻、bind有什么作用,什么區(qū)別 bind()方法創(chuàng)建一個(gè)新的函數(shù),...
    饑人谷_流水閱讀 242評(píng)論 0 0
  • this:1. apply梢为、call 渐行、bind有什么作用,什么區(qū)別共同作用:通過(guò)傳入?yún)?shù)都可以改變this的值區(qū)...
    24_Magic閱讀 251評(píng)論 0 0
  • 1. apply铸董、call 祟印、bind有什么作用,什么區(qū)別 bind()方法創(chuàng)建一個(gè)新的函數(shù), 當(dāng)被調(diào)用時(shí)粟害,將其...
    謹(jǐn)言_慎行閱讀 179評(píng)論 0 0
  • this 相關(guān)問(wèn)題 1蕴忆、apply、call 悲幅、bind有什么作用套鹅,什么區(qū)別 call方法:語(yǔ)法:call(thi...
    kumabearplus閱讀 240評(píng)論 0 0
  • 問(wèn)題1: apply驻襟、call 有什么作用,什么區(qū)別 1.function.prototype.call() 函數(shù)...
    漂于行閱讀 170評(píng)論 0 0