成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專(zhuān)欄INFORMATION COLUMN

換個(gè)思路理解Javascript中的this

ninefive / 2065人閱讀

摘要:事件處理函數(shù)中的把函數(shù)綁定到事件時(shí),可以當(dāng)作在上增加一個(gè)函數(shù)方法,當(dāng)觸發(fā)這個(gè)事件時(shí)調(diào)用上對(duì)應(yīng)的事件方法??偨Y(jié)在需要判斷的指向時(shí),我們可以安裝這種思路來(lái)理解判斷在全局中函數(shù)中,若在全局中則指向全局,若在函數(shù)中則只關(guān)注這個(gè)函數(shù)并繼續(xù)判斷。

在網(wǎng)上很多文章都對(duì) Javascript 中的 this 做了詳細(xì)的介紹,但大多是介紹各個(gè)綁定方式或調(diào)用方式下 this 的指向,于是我想有一個(gè)統(tǒng)一的思路來(lái)更好理解 this 指向,使大家更好判斷,以下有部分內(nèi)容不是原理,而是一種解題思路。

從call方法開(kāi)始

call 方法允許切換函數(shù)執(zhí)行的上下文環(huán)境(context),即 this 綁定的對(duì)象。

大多數(shù)介紹 this 的文章中都會(huì)把 call 方法放到最后介紹,但此文我們要把 call 方法放在第一位介紹,并從 call 方法切入來(lái)研究 this ,因?yàn)?call 函數(shù)是顯式綁定 this 的指向,我們來(lái)看看它如何模擬實(shí)現(xiàn)(不考慮傳入 null 、 undefined 和原始值):

Function.prototype.call = function(thisArg) {
    var context = thisArg;
    var arr = [];
    var result;

    context.fn = this;

    for (let i = 1, len = arguments.length; i < len; i++) {
        arr.push("arguments[" + i + "]");
    }

    result = eval("context.fn(" + arr + ")");

    delete context.fn;

    return result;
}

從以上代碼我們可以看到,把調(diào)用 call 方法的函數(shù)作為第一個(gè)參數(shù)對(duì)象的方法,此時(shí)相當(dāng)于把第一個(gè)參數(shù)對(duì)象作為函數(shù)執(zhí)行的上下文環(huán)境,而 this 是指向函數(shù)執(zhí)行的上下文環(huán)境的,因此 this 就指向了第一個(gè)參數(shù)對(duì)象,實(shí)現(xiàn)了 call 方法切換函數(shù)執(zhí)行上下文環(huán)境的功能。

對(duì)象方法中的this

在模擬 call 方法的時(shí)候,我們使用了對(duì)象方法來(lái)改變 this 的指向。調(diào)用對(duì)象中的方法時(shí),會(huì)把對(duì)象作為方法的上下文環(huán)境來(lái)調(diào)用。

既然 this 是指向執(zhí)行函數(shù)的上下文環(huán)境的,那我們先來(lái)研究一下調(diào)用函數(shù)時(shí)的執(zhí)行上下文情況。

下面我門(mén)來(lái)看看調(diào)用對(duì)象方法時(shí)執(zhí)行上下文是如何的:

var foo = {
    x : 1,
    getX: function(){
        console.log(this.x);
    }
}
foo.getX();

從上圖中,我們可以看出getX方法的調(diào)用者的上下文是foo,因此getX方法中的 this 指向調(diào)用者上下文foo,轉(zhuǎn)換成 call 方法為foo.getX.call(foo)。

下面我們把其他函數(shù)的調(diào)用方式都按調(diào)用對(duì)象方法的思路來(lái)轉(zhuǎn)換。

構(gòu)造函數(shù)中的this
function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = new Foo();
foo.getX();

執(zhí)行 new 如果不考慮原型鏈,只考慮上下文的切換,就相當(dāng)于先創(chuàng)建一個(gè)空的對(duì)象,然后把這個(gè)空的對(duì)象作為構(gòu)造函數(shù)的上下文,再去執(zhí)行構(gòu)造函數(shù),最后返回這個(gè)對(duì)象。

var newMethod = function(func){
    var context = {};
    func.call(context);
    return context;
}
function Foo(){
    this.x = 1;
    this.getX = function(){
        console.log(this.x);
    }
}
var foo = newMethod(Foo);
foo.getX();

DOM事件處理函數(shù)中的this
DOMElement.addEventListener("click", function(){
    console.log(this);
});

把函數(shù)綁定到DOM事件時(shí),可以當(dāng)作在DOM上增加一個(gè)函數(shù)方法,當(dāng)觸發(fā)這個(gè)事件時(shí)調(diào)用DOM上對(duì)應(yīng)的事件方法。

DOMElement.clickHandle = function(){
    console.log(this);
}
DOMElement.clickHandle();

普通函數(shù)中的this
var x = 1;
function getX(){
    console.log(this.x);
}
getX();

這種情況下,我們創(chuàng)建一個(gè)虛擬上下文對(duì)象,然后普通函數(shù)作為這個(gè)虛擬上下文對(duì)象的方法調(diào)用,此時(shí)普通函數(shù)中的this就指向了這個(gè)虛擬上下文。

那這個(gè)虛擬上下文是什么呢?在非嚴(yán)格模式下是全局上下文,瀏覽器里是 window ,NodeJs里是 Global ;在嚴(yán)格模式下是 undefined 。

var x = 1;
function getX(){
    console.log(this.x);
}

[viturl context].getX = getX;
[viturl context].getX();

閉包中的this
var x = 1;
var foo = {
    x: 2,
    y: 3,
    getXY: function(){
        (function(){
            console.log("x:" + this.x);
            console.log("y:" + this.y); 
        })();
    }
}
foo.getXY();

這段代碼的上下文如下圖:

這里需要注意的是,我們?cè)傺芯亢瘮?shù)中的 this 指向時(shí),只需要關(guān)注 this 所在的函數(shù)是如何調(diào)用的, this 所在函數(shù)外的函數(shù)調(diào)用都是浮云,是不需要關(guān)注的。因此在所有的圖示中,我們只需要關(guān)注紅色框中的內(nèi)容。

因此這段代碼我們關(guān)注的部分只有:

(function(){
    console.log(this.x);
})();

與普通函數(shù)調(diào)用一樣,創(chuàng)建一個(gè)虛擬上下文對(duì)象,然后普通函數(shù)作為這個(gè)虛擬上下文對(duì)象的方法立即調(diào)用,匿名函數(shù)中的 this 也就指向了這個(gè)虛擬上下文。

參數(shù)中的this
var x = 1;
var foo = {
    x: 2,
    getX: function(){
        console.log(this.x);
    }
}
setTimeout(foo.getX, 1000);

函數(shù)參數(shù)是值傳遞的,因此上面代碼等同于以下代碼:

var getX = function(){
    console.log(this.x);
};
setTimeout(getX, 1000);

然后我們又回到了普通函數(shù)調(diào)用的問(wèn)題。

全局中的this

全局中的 this 指向全局的上下文

var x = 1;
console.log(this.x);

復(fù)雜情況下的this
var x = 1;
var a = {
    x: 2,
    b: function(){
        return function(){
            return function foo(){
                console.log(this.x);
            }        
        }
    }
};

(function(){
    var x = 3;
    a.b()()();
})();

看到上面的情況是有很多個(gè)函數(shù),但我們只需要關(guān)注 this 所在函數(shù)的調(diào)用方式,首先我們來(lái)簡(jiǎn)化一下如下:

var x = 1;
(function(){
    var x = 3;
    var foo = function(){
        console.log(this.x);
    }
    foo();
});

this 所在的函數(shù) foo 是個(gè)普通函數(shù),我們創(chuàng)建一個(gè)虛擬上下文對(duì)象,然后普通函數(shù)作為這個(gè)虛擬上下文對(duì)象的方法立即調(diào)用。因此這個(gè) this指向了這個(gè)虛擬上下文。在非嚴(yán)格模式下是全局上下文,瀏覽器里是 window ,NodeJs里是 Global ;在嚴(yán)格模式下是 undefined 。

總結(jié)

在需要判斷 this 的指向時(shí),我們可以安裝這種思路來(lái)理解:

判斷 this 在全局中OR函數(shù)中,若在全局中則 this 指向全局,若在函數(shù)中則只關(guān)注這個(gè)函數(shù)并繼續(xù)判斷。

判斷 this 所在函數(shù)是否作為對(duì)象方法調(diào)用,若是則 this 指向這個(gè)對(duì)象,否則繼續(xù)操作。

創(chuàng)建一個(gè)虛擬上下文,并把this所在函數(shù)作為這個(gè)虛擬上下文的方法,此時(shí) this 指向這個(gè)虛擬上下文。

在非嚴(yán)格模式下虛擬上下文是全局上下文,瀏覽器里是 window ,Node.js里是 Global ;在嚴(yán)格模式下是 undefined 。

圖示如下:

歡迎關(guān)注:Leechikit
原文鏈接:segmentfault.com

到此本文結(jié)束,歡迎提問(wèn)和指正。
寫(xiě)原創(chuàng)文章不易,若本文對(duì)你有幫助,請(qǐng)點(diǎn)贊、推薦和關(guān)注作者支持。

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/84283.html

相關(guān)文章

  • 「前端面試題系列4」this的原理以及用法

    摘要:但是有一個(gè)總的原則那就是總會(huì)指向,調(diào)用函數(shù)的那個(gè)對(duì)象。作為對(duì)象方法的調(diào)用函數(shù)作為某個(gè)對(duì)象的方法調(diào)用,這時(shí)就指這個(gè)上級(jí)對(duì)象。 showImg(https://segmentfault.com/img/bVbnvF7?w=750&h=422); 這是前端面試題系列的第 4 篇,你可能錯(cuò)過(guò)了前面的篇章,可以在這里找到: 偽類(lèi)與偽元素的區(qū)別及實(shí)戰(zhàn) 如何實(shí)現(xiàn)一個(gè)圣杯布局? 今日頭條 面試題和思...

    fnngj 評(píng)論0 收藏0
  • 2017-07-25 前端日?qǐng)?bào)

    摘要:前端日?qǐng)?bào)精選三思而后行想提高團(tuán)隊(duì)技術(shù),來(lái)試試這個(gè)套路如何開(kāi)發(fā)一個(gè)插件學(xué)習(xí)筆記塊級(jí)作用域綁定譯文詳解帶來(lái)的個(gè)重大變化中文周二放送畫(huà)圖知乎專(zhuān)欄第期新特性譯配置譯高性能視差滾動(dòng)行代碼構(gòu)建區(qū)塊鏈知乎專(zhuān)欄渲染器修仙之路之拷貝對(duì)象已 2017-07-25 前端日?qǐng)?bào) 精選 SSR 三思而后行想提高團(tuán)隊(duì)技術(shù),來(lái)試試這個(gè)套路!如何開(kāi)發(fā)一個(gè) Atom 插件ES6學(xué)習(xí)筆記:塊級(jí)作用域綁定【譯文】詳解VUE2...

    bluesky 評(píng)論0 收藏0
  • 和少婦白潔一起學(xué)JavaScript

    摘要:我們已經(jīng)回答了的構(gòu)造函數(shù)和原型都是誰(shuí)的問(wèn)題,現(xiàn)在牽扯出來(lái)一個(gè),我們繼續(xù)檢查的構(gòu)造函數(shù)是全局對(duì)象上屬性叫的對(duì)象的原型是個(gè)匿名函數(shù),按照關(guān)于構(gòu)造函數(shù)的約定,它應(yīng)該是構(gòu)造函數(shù)的屬性我們給這個(gè)對(duì)象起個(gè)名字,叫。 我不確定JavaScript語(yǔ)言是否應(yīng)該被稱(chēng)為Object-Oriented,因?yàn)镺bject Oriented是一組語(yǔ)言特性、編程模式、和設(shè)計(jì)與工程方法的籠統(tǒng)稱(chēng)謂,沒(méi)有一個(gè)詳盡和大家...

    DevTTL 評(píng)論0 收藏0
  • javascript自定義事件原理

    摘要:我們就需要我們自己去定義事件其實(shí)就是我們寫(xiě)的函數(shù),尤其是組件開(kāi)發(fā)過(guò)程中,用的尤為多??赡苡写_定按鈕取消按鈕等操作。但是自定義事件的基本原理就是如上描繪的那樣 我們都知道,鼠標(biāo)點(diǎn)擊click,觸屏的touch等事件,可以觸發(fā)相應(yīng)的事件處理程序,也可以為這些事件添加事件處理程序,實(shí)際開(kāi)發(fā)過(guò)程中可供我們使用的事件很少,click、doubleclick,mouseover、mousemove...

    JowayYoung 評(píng)論0 收藏0
  • vue你不知道的奇淫絕技

    摘要:之前做過(guò)的組件配置系統(tǒng)核心就是它。但是如果你想改動(dòng)到這個(gè)元素的樣式,但是又不想改動(dòng)公用模板。 1.placeholder與computed巧用 表單開(kāi)發(fā)肯定是日常開(kāi)發(fā)中必不可少的環(huán)節(jié),可是設(shè)計(jì)圖經(jīng)常會(huì)有表單默認(rèn)值的設(shè)計(jì),比如:showImg(https://segmentfault.com/img/remote/1460000012955169?w=559&h=392); 需求方的需求...

    ixlei 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<