每宣告一個函數就會產生一個作用域。而外面的作用域存取不了裡面的作用域(把裡面的變數和函數隱藏起來),而裡面的可以存取到外面的。對於隱藏變數和函數是一個非常有用的技術。
基於作用域隱藏的方法叫做最小授權或最小暴露原則。
這個原則是指在軟體設計中,應該最小限度的暴露必要內容,而將其內容都隱藏起來,例如某個模組或物件得API設計。 隱藏變數和函數可以解決同名識別碼之間的衝突,衝突會導致變數的意外覆蓋。
例如:
var a = 2; function foo(){ var a = 3; console.log(a); } foo(); console.log(a);
雖然這種技術可以解決一些問題,但是他並不理想,會導致一些額外的問題,首先必須聲明一個具名函數foo(),意味著foo這個名稱本身「污染」了所在的作用域,其次必須明確的透過函數名稱foo()呼叫這個函數才能運行其中的程式碼。
如果函數不需要函數名,並且能夠自動運行,這會更理想。幸好js提供了同時解決這兩個問題的方案-- (IIFE) Immediately Invoked Function Expression -- 立即執行函數
#var a = 2; (function foo(){ var a = 3; console.log(a); })() console.log(a);
首先立即執行函數不會當做函數宣告處理而是當做函數表達式處理。
區分函數宣告還是函數表達式:看function在宣告中是不是第一個字,如果第一個字就是函數宣告否則就是函數表達式。而立即執行函數" (function ",不是" function ",所以是函數表達式。
函數宣告和函數表達式之間最重要的差異是他們的名稱識別碼將會綁定在何處
函數宣告的函名稱數會綁定在目前作用域內。假如在全域作用域建立一個函數聲明,就可以在全域作用域存取這個函數名稱並執行。而函數表達式的函數名稱會綁定在自身的函數中,而不是目前說在作用域中。例如你全域建立一個函數表達式,如果你直接執行這個你所建立的函數表達式的函數名稱就會報錯,因為目前作用域下沒有這個標識符,而你在函數表達式裡面的作用域裡存取這個函數名就會回傳這個函數的引用。
作用域閉包,嗯,這兩個字閉包就有點讓人難以理解,(可以想像成一個包是關上的,裡面隱藏了一些神秘的東西)而對於閉包的定義是這樣說的:當函數可以記住並訪問所在的作用域時,就產生了閉包,即使函數是在當前作用域之外執行。
for instance(拽個英文,哈哈)。
function foo() { var a = 2; function bar() { console.log(a); } bar(); } foo();
上面的程式碼bar()可以存取外部作用域中的變數。根據上面的定義這是閉包嗎?從技術來講也許是,但我們理解的是作用域在當前作用域查找變數如果沒找到會繼續向上面查找,找到返回,找不到繼續找,直到全域作用域。-- 而這些正是閉包的一部份。函數bar()具有一個涵蓋foo()作用域的閉包。
function foo(){ var a = 2; function bar (){ console.log(a); } return bar; }var baz = foo(); baz();
在上面的程式碼更好的展示了閉包。
bar()函數在定義時作用域以外的地方執行(此時在全域作用域執行)。在foo()函數執行後,通常會期待foo()整個內部作用域都被銷毀,因為我們知道引擎有垃圾回收器用來釋放不在使用的記憶體空間,由於foo()已經執行完,看上去內容不會再被使用,所以很自然的會考慮對齊進行回收,回收後意味著裡面的函數和變數存取不到了。foo()執行完,baz變數存bar函數的引用。當執行baz也就是bar函數時。console.log(a)。不理解閉包的人可能認為會報錯,事實上,打印的是2 ;???what?
foo()函數作用域不是執行完銷毀了嗎?怎麼還能存取到a變數?-- 這就是閉包。
当foo()执行后,bar函数被返回全局作用域下,但是bar函数还保留着当时的词法作用域(当时写代码是的顺序就已经定义了作用域,这个作用域叫词法作用域--外面函数套着里面的函数的那种)甚至直到全局作用域。所以bar还留有foo()函数的引用。使得foo()函数没有被回收。
闭包可以说不出不在,只是你没有发现认出他。在定时器,事件监听器,ajax请求,跨窗口通信或者任何其他的异步(或者同步)任务中,只要使用了回调函数,实际上就是使用闭包。
for instance
function wait(message) { setTimeout(function timer() { console.log(message); }, 1000); } wait("hello");
在上面的代码中将一个内部函数(名为timer)传递给setTimerout(...).timer具有涵盖wait(...)的作用域的闭包。因此还保有对变量message的引用。wait()执行1000毫秒后,它的内部作用域不会消失,timer函数依然保有wait()作用域的闭包。
而闭包和立即执行函数息息相关。
循环和闭包
for(var i = 1; i <p>上面代码我们以为输出的会是1-5,可事实上输出的是5个6,这是为啥啊 -- 闭包啊。</p><p>延迟函数的回调会在循环结束时执行。事实上,当定时器运行时即使每个迭代的是setTimerout(...,0),所有的回调函数依然是循环结束后才会执行。我猜是跟js执行机制有关系吧。至于为什么都是6. 因为即使5个函数是在各个迭代中分别定义的,但是他们又被封闭在一个共享的全局作用域中因此实际上只有一个i.而怎么解决呢,立即执行函数来了!!!</p><pre class="brush:php;toolbar:false">for (var i = 1; i <p>打印出来1,2,3,4,5了欧,这回是你想要的数了。解释一下,5次循环创建了5个立即执行函数,这5个函数的作用域都不相同,立即函数接收的参数是当前循环的i.所以当timer执行时访问的就是自己立即执行函数对应的作用域。也就是说5个timer函数分别对应5个作用域,每个作用域保存的变量i都不同,解决啦!!!</p><p>你懂闭包了吗?</p><p><strong>js执行机制</strong></p><p><span class="bjh-p">JavaScript语言的一大特点就是单线程,也就是说,<span class="bjh-strong">同一个时间只能做一件事。那么,为什么JavaScript不能有多个线程呢?这样能提高效率啊。</span></span><span class="bjh-p">JavaScript的单线程,与它的用途有关。作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。这决定了它只能是单线程,否则会带来很复杂的同步问题。比如,假定JavaScript同时有两个线程,一个线程在某个DOM节点上添加内容,另一个线程删除了这个节点,这时浏览器应该以哪个线程为准</span><span class="bjh-p">所以,为了避免复杂性,从一诞生,JavaScript就是单线程,这已经成了这门语言的核心特征,将来也不会改变。</span></p><p><span class="bjh-p">单线程就意味着,所有任务需要排队,前一个任务结束,才会执行后一个任务。如果前一个任务耗时很长,后一个任务就不得不一直等着。JavaScript语言的设计者意识到这个问题,将所有任务分成两种,<span class="bjh-strong">一种是同步任务(synchronous),另一种是异步任务(asynchronous)。同步任务指的是,在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务;异步任务指的是,不进入主线程、而进入"任务队列"(task queue)的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。</span></span></p><p><span class="bjh-p">主线程从"任务队列"中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop(事件循环)。只要主线程空了,就会去读取"任务队列",这就是JavaScript的运行机制。</span></p><p><span class="bjh-h3">哪些语句会放入异步任务队列及放入时机</span><span class="bjh-p">一般来说,有以下四种会放入异步任务队列:</span><span class="bjh-ol"><span class="bjh-li"><span class="bjh-p">setTimeout 和 setlnterval ,<span class="bjh-li"><span class="bjh-p">DOM事件,<span class="bjh-li"><span class="bjh-p">ES6中的Promise,<span class="bjh-li"><span class="bjh-p">Ajax异步请求</span></span></span></span></span></span></span></span></span></p><p> 本文来自 <a href="https://www.php.cn/js-tutorial.html" target="_blank">js教程</a> 栏目,欢迎学习!</p>
以上是淺談JS函數及閉包的詳細內容。更多資訊請關注PHP中文網其他相關文章!

Python和JavaScript的主要區別在於類型系統和應用場景。 1.Python使用動態類型,適合科學計算和數據分析。 2.JavaScript採用弱類型,廣泛用於前端和全棧開發。兩者在異步編程和性能優化上各有優勢,選擇時應根據項目需求決定。

選擇Python還是JavaScript取決於項目類型:1)數據科學和自動化任務選擇Python;2)前端和全棧開發選擇JavaScript。 Python因其在數據處理和自動化方面的強大庫而備受青睞,而JavaScript則因其在網頁交互和全棧開發中的優勢而不可或缺。

Python和JavaScript各有優勢,選擇取決於項目需求和個人偏好。 1.Python易學,語法簡潔,適用於數據科學和後端開發,但執行速度較慢。 2.JavaScript在前端開發中無處不在,異步編程能力強,Node.js使其適用於全棧開發,但語法可能複雜且易出錯。

javascriptisnotbuiltoncorc; sanInterpretedlanguagethatrunsonenginesoftenwritteninc.1)JavascriptwasdesignedAsignedAsalightWeight,drackendedlanguageforwebbrowsers.2)Enginesevolvedfromsimpleterterpretpretpretpretpreterterpretpretpretpretpretpretpretpretpretcompilerers,典型地,替代品。

JavaScript可用於前端和後端開發。前端通過DOM操作增強用戶體驗,後端通過Node.js處理服務器任務。 1.前端示例:改變網頁文本內容。 2.後端示例:創建Node.js服務器。

選擇Python還是JavaScript應基於職業發展、學習曲線和生態系統:1)職業發展:Python適合數據科學和後端開發,JavaScript適合前端和全棧開發。 2)學習曲線:Python語法簡潔,適合初學者;JavaScript語法靈活。 3)生態系統:Python有豐富的科學計算庫,JavaScript有強大的前端框架。

JavaScript框架的強大之處在於簡化開發、提升用戶體驗和應用性能。選擇框架時應考慮:1.項目規模和復雜度,2.團隊經驗,3.生態系統和社區支持。

引言我知道你可能會覺得奇怪,JavaScript、C 和瀏覽器之間到底有什麼關係?它們之間看似毫無關聯,但實際上,它們在現代網絡開發中扮演著非常重要的角色。今天我們就來深入探討一下這三者之間的緊密聯繫。通過這篇文章,你將了解到JavaScript如何在瀏覽器中運行,C 在瀏覽器引擎中的作用,以及它們如何共同推動網頁的渲染和交互。 JavaScript與瀏覽器的關係我們都知道,JavaScript是前端開發的核心語言,它直接在瀏覽器中運行,讓網頁變得生動有趣。你是否曾經想過,為什麼JavaScr


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SAP NetWeaver Server Adapter for Eclipse
將Eclipse與SAP NetWeaver應用伺服器整合。

記事本++7.3.1
好用且免費的程式碼編輯器

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

MinGW - Minimalist GNU for Windows
這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

ZendStudio 13.5.1 Mac
強大的PHP整合開發環境