欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費電子書(shū)等14項超值服

開(kāi)通VIP
js教程:javascript作用域(Scope)

作用域(scope)是javascript語(yǔ)言的基石之一,在構建復雜程序時(shí)也可能是最令我頭痛的東西。記不清多少次在函數之間傳遞控制后忘記 this關(guān)鍵字引用的究竟是哪個(gè)對象,甚至,我經(jīng)常以各種不同的混亂方式來(lái)曲線(xiàn)救國,試圖偽裝成正常的代碼,以我自己的理解方式來(lái)找到所需要訪(fǎng)問(wèn)的變量。

這篇文章將正面解決這個(gè)問(wèn)題:簡(jiǎn)述上下文(context)和作用域的定義,分析可以讓我們掌控上下文的兩種方法,最后深入一種高效的方案,它能有效解決我所碰到的90%的問(wèn)題。

我在哪兒?你又是誰(shuí)

javascript 程序的每一個(gè)字節都是在這個(gè)或那個(gè)運行上下文(execution context)中執行的。你可以把這些上下文想象為代碼的鄰居,它們可以給每一行代碼指明:從何處來(lái),朋友和鄰居又是誰(shuí)。沒(méi)錯,這是很重要的信息,因為 javascript社會(huì )有相當嚴格的規則,規定誰(shuí)可以跟誰(shuí)交往。運行上下文則是有大門(mén)把守的社區而非其內開(kāi)放的小門(mén)。

我們通??梢园堰@些社會(huì )邊界稱(chēng)為作用域,并且有充足的重要性在每一位鄰居的憲章里立法,而這個(gè)憲章就是我們要說(shuō)的上下文的作用域鏈(scope chain)。在特定的鄰里關(guān)系內,代碼只能訪(fǎng)問(wèn)它的作用域鏈內的變量。與超出它鄰里的變量比起來(lái),代碼更喜歡跟本地(local,即局部)的打交道。

具體地說(shuō),執行一個(gè)函數會(huì )創(chuàng )建一個(gè)不同的運行上下文,它會(huì )將局部作用域增加到它所定義的作用域鏈內。javascript通過(guò)作用域鏈的局部向全局攀升方式,在特定的上下文中解析標識符。這表示,本級變量會(huì )優(yōu)先于作用域鏈內上一級擁有相同名字的變量。顯而易見(jiàn),當我的好友們一起談?wù)?#8221;Mike West”(本文原作者)時(shí),他們說(shuō)的就是我,而非bluegrass singer 或是Duke professor, 盡管(按理說(shuō))后兩者著(zhù)名多了。

讓我們看些例子來(lái)探索這些含義:

<script type="text/javascript">var ima_celebrity = "Everyone can see me! I'm famous!",the_president = "I'm the decider!";function pleasantville() {var the_mayor = "I rule Pleasantville with an iron fist!",ima_celebrity = "All my neighbors know who I am!";function lonely_house() {var agoraphobic = "I fear the day star!",a_cat = "Meow.";}}</script>

我們的全明星,ima_celebrity, 家喻戶(hù)曉(所有人都認識她)。她在政治上積極活躍,敢于在一個(gè)相當頻繁的基層上叫囂總統(即the_president)。她會(huì )為碰到的每一個(gè)人簽名和回答問(wèn)題。就是說(shuō),她不會(huì )跟她的粉絲有私下的聯(lián)系。她相當清楚粉絲們的存在 并有他們自己某種程度上的個(gè)人生活,但也可以肯定的是,她并不知道粉絲們在干嘛,甚至連粉絲的名字都不知道。

而在歡樂(lè )市(pleasantville)內,市長(cháng)(the_mayor)是眾所周知的。她經(jīng)常在她的城鎮內散步,跟她的選民聊天、握手并親吻小孩。因為歡樂(lè )市(pleasantville)還算比較大且重要的鄰居,市長(cháng)在她辦公室內放置一臺紅色電話(huà),它是一條可以直通總統的7×24熱線(xiàn)。她還可以看到市郊外山上的孤屋(lonely_house),但從不在意里面住著(zhù)的是誰(shuí)。

而孤屋(lonely_house)是一個(gè)自我的世界。曠恐患者時(shí)常在里面囔囔自語(yǔ),玩紙牌和喂養一個(gè)小貓(a_cat)。他偶爾會(huì )給市長(cháng)(the_mayor)打電話(huà)咨詢(xún)一些本地的噪音管制,甚至在本地新聞看到ima_celebrity后會(huì )寫(xiě)些粉絲言語(yǔ)給她(當然,這是pleasantville內的ima_celebrity)。

this? 那是蝦米?

每一個(gè)運行上下文除了建立一個(gè)作用域鏈外,還提供一個(gè)名為this的關(guān)鍵字。它的普遍用法是,this作為一個(gè)獨特的功能,為鄰里們提供一個(gè)可訪(fǎng)問(wèn)到它的途徑。但總是依賴(lài)于這個(gè)行為并不可靠:取決于我們如何進(jìn)入一個(gè)特定鄰居的具體情況,this表示的完全可能是其他東西。事實(shí)上,我們如何進(jìn)去鄰居家本身,通常恰恰就是this所指。有四種情形值得特別注意:

  • 呼叫對象的方法

    在經(jīng)典的面向對象編程中,我們需要識別和引用當前對象。this極好地扮演了這個(gè)角色,為我們的對象提供了自我查找的能力,并指向它們本身的屬性。

    <script type="text/javascript">    var deep_thought = {    the_answer: 42,    ask_question: function () {    return this.the_answer;    }    };    var the_meaning = deep_thought.ask_question();    </script>

    這個(gè)例子建立了一個(gè)名為deep_thought的對象,設置其屬性 the_answer為42,并創(chuàng )建了一個(gè)名為ask_question 的方法(method)。當deep_thought.ask_question()執行時(shí), javascript為函數的呼叫建立了一個(gè)運行上下文,通過(guò)”.“運算符把this指向被引用的對象,在此是deep_thought這個(gè)對象。之后這個(gè)方法就可以通過(guò)this在鏡子中找到它自身的屬性,返回保存在 this.the_answer中的值:42。

  • 構造函數

    類(lèi)似地,當定義一個(gè)作為構造器的使用new關(guān)鍵字的函數時(shí),this可以用來(lái)引用剛創(chuàng )建的對象。讓我們重寫(xiě)一個(gè)能反映這個(gè)情形的例子:

    <script type="text/javascript">    function BigComputer(answer) {    this.the_answer = answer;    this.ask_question = function () {    return this.the_answer;    }    }    var deep_thought = new BigComputer(42);    var the_meaning = deep_thought.ask_question();    </script>

    我們編寫(xiě)一個(gè)函數來(lái)創(chuàng )建BigComputer對象,而不是直白地創(chuàng )建 deep_thought對象,并通過(guò)new關(guān)鍵字實(shí)例化deep_thought為一個(gè)實(shí)例變量。當new BigComputer()被執行,后臺透明地創(chuàng )建了一個(gè)嶄新的對象。呼叫BigComputer后,它的this關(guān)鍵字被設置為指向新對象的引用。這個(gè)函數可以在this上設置屬性和方法,最終它會(huì )在BigComputer執行后透明地返回。

    盡管如此,需要注意的是,那個(gè)deep_thought.the_question()依然可以像從前一樣執行。那這里發(fā)生了什么事?為何thisthe_question內與BigComputer內會(huì )有所不同?簡(jiǎn)單地說(shuō),我們是通過(guò)new進(jìn)入BigComputer的,所以this表示“新(new)的對象”。在另一方面,我們通過(guò) deep_thought進(jìn)入the_question,所以當我們執行該方法時(shí),this表示 “deep_thought所引用的對象”。this并不像其他的變量一樣從作用域鏈中讀取,而是在上下文的基礎上,在上下文中重置。

  • 函數呼叫

    假如沒(méi)有任何相關(guān)對象的奇幻東西,我們只是呼叫一個(gè)普通的、常見(jiàn)的函數,在這種情形下this表示的又是什么呢?

    <script type="text/javascript">    function test_this() {    return this;    }    var i_wonder_what_this_is = test_this();    </script>

    在這樣的場(chǎng)合,我們并不通過(guò)new來(lái)提供上下文,也不會(huì )以某種對象形式在背后偷偷提供上下文。在此, this默認下盡可能引用最全局的東西:對于網(wǎng)頁(yè)來(lái)說(shuō),這就是 window對象。

  • 事件處理函數

    比普通函數的呼叫更復雜的狀況,先假設我們使用函數去處理的是一個(gè)onclick事件。當事件觸發(fā)我們的函數運行,此處的this表示的是什么呢?不湊巧,這個(gè)問(wèn)題不會(huì )有簡(jiǎn)單的答案。

    如果我們寫(xiě)的是行內(inline)事件處理函數,this引用的是全局window對象:

    <script type="text/javascript">    function click_handler() {    alert(this); // 彈出 window 對象    }    </script>    ...    <button id='thebutton' onclick='click_handler()'>Click me!</button>

    但是,如果我們通過(guò)javascript來(lái)添加事件處理函數,this引用的是生成該事件的DOM元素。(注意:此處的事件處理非常簡(jiǎn)潔和易于閱讀,但其他的就別有洞天了。請使用真正的addEvent函數取而代之):

    <script type="text/javascript">    function click_handler() {    alert(this); // 彈出按鈕的DOM節點(diǎn)    }    function addhandler() {    document.getElementById('thebutton').onclick = click_handler;    }    window.onload = addhandler;    </script>    ...    <button id='thebutton'>Click me!</button>

復雜情況

讓我們來(lái)短暫地運行一下這個(gè)最后的例子。我們需要詢(xún)問(wèn)deep_thought一個(gè)問(wèn)題,如果不是直接運行click_handler而是通過(guò)點(diǎn)擊按鈕的話(huà),那會(huì )發(fā)生什么事情?解決此問(wèn)題的代碼貌似十分直接,我們可能會(huì )這樣做:

<script type="text/javascript">function BigComputer(answer) {this.the_answer = answer;this.ask_question = function () {alert(this.the_answer);}}function addhandler() {var deep_thought = new BigComputer(42),the_button = document.getElementById('thebutton');the_button.onclick = deep_thought.ask_question;}window.onload = addhandler;</script>

很完美吧?想象一下,我們點(diǎn)擊按鈕,deep_thought.ask_question被執行,我們也得到了“42”。但是為什么瀏覽器卻給我們一個(gè)undefined? 我們錯在何處?

其實(shí)問(wèn)題顯而易見(jiàn):我們給ask_question傳遞一個(gè)引用,它作為一個(gè)事件處理函數來(lái)執行,與作為對象方法來(lái)運行的上下文并不一樣。簡(jiǎn)而言之,ask_question中的 this關(guān)鍵字指向了產(chǎn)生事件的DOM元素,而不是在BigComputer的對象中。DOM元素并不存在一個(gè)the_answer屬性,所以我們得到的是 undefined而不是”42″. setTimeout也有類(lèi)似的行為,它在延遲函數執行的同時(shí)跑到了一個(gè)全局的上下文中去了。

這個(gè)問(wèn)題會(huì )在程序的所有角落時(shí)不時(shí)突然冒出,如果不細致地追蹤程序的每一個(gè)角落的話(huà),還是一個(gè)非常難以排錯的問(wèn)題,尤其在你的對象有跟DOM元素或者window對象同名屬性的時(shí)候。

使用.apply().call()掌控上下文

在點(diǎn)擊按鈕的時(shí)候,我們真正需要的是能夠咨詢(xún)deep_thought一個(gè)問(wèn)題,更進(jìn)一步說(shuō),我們真正需要的是,在應答事件和setTimeout的呼叫時(shí),能夠在自身的本原上下文中呼叫對象的方法。有兩個(gè)鮮為人知的javascript方法,applycall,在我們執行函數呼叫時(shí),可以曲線(xiàn)救國幫我們達到目的,允許我們手工覆蓋this的默認值。我們先來(lái)看call

<script type="text/javascript">var first_object = {num: 42};var second_object = {num: 24};function multiply(mult) {return this.num * mult;}multiply.call(first_object, 5); // 返回 42 * 5multiply.call(second_object, 5); // 返回 24 * 5</script>

在這個(gè)例子中,我們首先定義了兩個(gè)對象,first_objectsecond_object,它們分別有自己的num屬性。然后定義了一個(gè)multiply函數,它只接受一個(gè)參數,并返回該參數與this所指對象的num屬性的乘積。如果我們呼叫函數自身,返回的答案極大可能是undefined,因為全局window對象并沒(méi)有一個(gè)num屬性除非有明確的指定。我們需要一些途徑來(lái)告訴multiply里面的this關(guān)鍵字應該引用什么。而multiplycall方法正是我們所需要的。

call的第一個(gè)參數定義了在業(yè)已執行的函數內this的所指對象。其余的參數則傳入業(yè)已執行的函數內,如同函數的自身呼叫一般。所以,當執行multiply.call(first_object, 5)時(shí),multiply被呼叫,5傳入作為第一個(gè)參數,而this關(guān)鍵字被設置為first_object的引用。同樣,當執行multiply.call(second_object, 5)時(shí),5傳入作為第一個(gè)參數,而this關(guān)鍵字被設置為second_object的引用。

applycall一樣的方式工作,但可以讓你把參數包裹進(jìn)一個(gè)數組再傳遞給呼叫函數,在程序性生成函數呼叫時(shí)尤為有用。使用apply重現上一段代碼,其實(shí)區別并不大:

<script type="text/javascript">...multiply.apply(first_object, [5]); // 返回 42 * 5multiply.apply(second_object, [5]); // 返回 24 * 5</script>

applycall本身都非常有用,并值得貯藏于你的工具箱內,但對于事件處理函數所改變的上下文問(wèn)題,也只是送佛到西天的中途而已,剩下的還是得我們來(lái)解決。在搭建處理函數時(shí),我們自然而然地認為,只需簡(jiǎn)單地通過(guò)使用call來(lái)改變this的含義即可:

function addhandler() {var deep_thought = new BigComputer(42),the_button = document.getElementById('thebutton');the_button.onclick = deep_thought.ask_question.call(deep_thought);}

代碼之所以有問(wèn)題的理由很簡(jiǎn)單:call立即執行了函數(譯注:其實(shí)可以用一個(gè)匿名函數封裝,例如the_button.onclick = function(){deep_thought.ask_question.call(deep_thought);},但比起即將討論的bind來(lái),依然不夠優(yōu)雅)。我們給onclcik處理函數一個(gè)函數執行后的結果而非函數的引用。所以我們需要利用另一個(gè)javascript特色,以解決這個(gè)問(wèn)題。

.bind()之美

我并不是 Prototype javascript framework的忠實(shí)粉絲,但我對它的總體代碼質(zhì)量印象深刻。具體而言,它為Function對象增加一個(gè)簡(jiǎn)潔的補充,對我管理函數呼叫執行后的上下文產(chǎn)生了極大的正面影響:bindcall一樣執行相同的常見(jiàn)任務(wù),改變函數執行的上下文。不同之處在于bind返回的是函數引用可以備用,而不是call的立即執行而產(chǎn)生的最終結果。

如果需要簡(jiǎn)化一下bind函數以抓住概念的重點(diǎn),我們可以先把它插進(jìn)前面討論的乘積例子中去,看它究竟是如何工作的。這是一個(gè)相當優(yōu)雅的解決方案:

<script type="text/javascript">var first_object = {num: 42};var second_object = {num: 24};function multiply(mult) {return this.num * mult;}Function.prototype.bind = function(obj) {var method = this,temp = function() {return method.apply(obj, arguments);};return temp;}var first_multiply = multiply.bind(first_object);first_multiply(5); // 返回 42 * 5var second_multiply = multiply.bind(second_object);second_multiply(5); // 返回 24 * 5</script>

首先,我們定義了first_object, second_objectmultiply函數,一如既往。細心處理這些后,我們繼續為Function對象的prototype定義一個(gè)bind方法,這樣的話(huà),我們程序里的函數都有一個(gè)bind方法可用。當執行multiply.bind(first_object)時(shí),javascript為bind方法創(chuàng )建一個(gè)運行上下文,把this置為multiply函數的引用,并把第一個(gè)參數obj置為first_object的引用。目前為止,一切皆順。

這個(gè)解決方案的真正天才之處在于method的創(chuàng )建,置為this的引用所指(即multiply函數自身)。當下一行的匿名函數被創(chuàng )建,method通過(guò)它的作用域鏈訪(fǎng)問(wèn),obj亦然(不要在此使用this, 因為新創(chuàng )建的函數執行后,this會(huì )被新的、局部的上下文覆蓋)。這個(gè)this的別名讓apply執行multiply函數成為可能,而傳遞obj則確保上下文的正確。用計算機科學(xué)的話(huà)說(shuō),temp是一個(gè)閉包(closure),它可以保證,需要在first_object的上下文中執行multiply,bind呼叫的最終返回可以用在任何的上下文中。

這才是前面說(shuō)到的事件處理函數和setTimeout情形所真正需要的。以下代碼完全解決了這些問(wèn)題,綁定deep_thought.ask_question方法到deep_thought的上下文中,因此能在任何事件觸發(fā)時(shí)都能正確運行:

function addhandler() {var deep_thought = new BigComputer(42),the_button = document.getElementById('thebutton');the_button.onclick = deep_thought.ask_question.bind(deep_thought);}

漂亮。

本站僅提供存儲服務(wù),所有內容均由用戶(hù)發(fā)布,如發(fā)現有害或侵權內容,請點(diǎn)擊舉報。
打開(kāi)APP,閱讀全文并永久保存 查看更多類(lèi)似文章
猜你喜歡
類(lèi)似文章
Python最全函數大全,要學(xué)好一門(mén)編程語(yǔ)言地基一定要搭建好!很長(cháng)
(轉)Ext.onReady詳解
javascript語(yǔ)言精粹 筆記
【第655期】迷之this?
深入理解JavaScript系列(16):閉包(Closures)
JavaScript
更多類(lèi)似文章 >>
生活服務(wù)
分享 收藏 導長(cháng)圖 關(guān)注 下載文章
綁定賬號成功
后續可登錄賬號暢享VIP特權!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服

欧美性猛交XXXX免费看蜜桃,成人网18免费韩国,亚洲国产成人精品区综合,欧美日韩一区二区三区高清不卡,亚洲综合一区二区精品久久