摘要:遮蔽效應作用域查找會在找到第一個匹配的標識符時停止,不會繼續往上層作用域查找,這就會產生遮蔽效應。會發現每一次輸出的都是為啥勒所有的回調函數回在循環結束后才會執行事件循環。
三劍客
編譯,顧名思義,就是源代碼執行前會經歷的過程,分三個步驟,
分詞/詞法分析,將我們寫的代碼字符串分解成多個詞法單元
解析/語法分析,將詞法單元集合生成抽象語法樹(AST)
代碼生成,抽象語法樹(AST)轉換成可執行代碼的過程
Tip1:js在語法分析和代碼生成階段有對運行性能進行優化,對冗余元素進行優化
Tip2:js的編譯過程不是發生在構建之前,而是代碼執行之前
理解作用域,首先知道三劍客,分別是
引擎:負責整個代碼編譯及執行的過程
編譯器: 負責詞法分析、語法分析、代碼生成
作用域:負責維護與收集所有聲明的標識符,保證當前執行代碼對這些標識符的訪問權限
舉例子,加深印象,對于var a = 2,三劍客如何協同工作,
編譯器進行分詞、語法分析,然后要代碼生成時,遇到 var a,問一下當前作用域集合“你有沒有這個名稱的變量呀?”,作用域如果說有,那么忽略聲明,繼續編譯,如果說沒有,那么就要要求作用域收集一下,并且給它個名字a,然后編譯器就生成了代碼,引擎準備來執行了,先問當前作用域集合,“你這里有a這個變量嗎?”,有引擎就拿來用,沒有就繼續找該變量,要么找到,就給它附個值2,沒有那就給你報個錯!
作用域嵌套LSH查詢,通俗解釋就是找到所聲明變量,并且對其賦值的行為
RSH查詢,通俗解釋就是查找聲明的變量
當一個塊或是函數嵌套在另外一個塊或函數時,就會產生作用域嵌套,于是在當前作用域找不到某個變量時,引擎會往外層嵌套作用域繼續查找,直達到最外層作用域(全局作用域)為止,也就是所謂的作用域鏈啦!
詞法作用域 相信有很多人都是搞不懂詞法作用域是什么?所謂的詞法作用域,就是定義在詞法階段(詞法分析)的作用域,由你寫代碼時將變量和塊作用域寫在哪里來決定的。
遮蔽效應作用域查找會在找到第一個匹配的標識符時停止,不會繼續往上層作用域查找,這就會產生遮蔽效應。
欺騙詞法作用域eval函數,修改詞法作用域
with關鍵字,創建詞法作用域
導致性能下降的原因,前面我們提過,在解析/語法分析、生成代碼階段,我們會對代碼進行優化,剔除冗余元素,但是當使用eval/with時,所有優化變得沒有意義,因為存在不可預見性,不知道修改和創建的詞法作用域是什么?所以會導致性能下降。
函數聲明、函數表達式、匿名函數表達式函數表達式:function為第一個詞,那么就是一個函數聲明,否則就是一個函數表達式
匿名函數表達式:沒有函數名,匿名函數在棧追蹤這種不會顯示有意義的函數名,使得調試困難
IIFE: 立即執行函數表達式((function() { ... }())、(function(){ ... })())
let為其聲明的變量隱式地去劫持了所在的塊級作用域,不會在塊級作用域中進行提升【變量提升】
Demo: with關鍵字為塊級作用域、{...}為塊級作用域,用完即銷毀
const常量,不可修改!
任何聲明在某個作用域(函數作用域和塊級作用域)的變量,都是屬于這個作用域。
每個作用域都會進行提升操作。
函數聲明會被提升,函數表達式不會提升,變量聲明提升的過程中,函數會優先!
閉包,有權訪問另外一個函數的變量標識符的函數,比較常見的一個閉包問題,就是for循環。
for(var i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i*1000) }
會發現每一次輸出的都是6,為啥勒?所有的回調函數回在循環結束后才會執行(事件循環)。所以每次都是輸出一個6來。
解決辦法:
1、IIFE,每個迭代儲存i的值
for(var i = 1; i <= 5; i++) { (function(i) { var j = i; setTimeout(function() { console.log(j); }, j*1000); })(i) }
2、IIFE,將i入參修改成j
for(var i = 1; i <= 5; i++) { (function(j) { setTimeout(function() { console.log(j); }, j*1000); })(i) }
3、創建閉包的塊作用域
for(var i = 1; i <= 5; i++) { let j = i; setTimeout(function() { console.log(j); }, j*1000); }
4、最優
for(let i = 1; i <= 5; i++) { setTimeout(function() { console.log(i); }, i*1000) }
另外一個閉包常用的場景,就是模塊暴露了,在這里提供一個現代模塊機制的實現方式,大家可以細細品嘗,
var MyMoudles = (function Manger() { var modules = {}; function define(name, deps, impl) { for (var i = 0; i < deps.length; i++) { deps[i] = modules[deps[i]]; } modules[name] = impl.apply(impl, deps); } function get(name) { return modules[name]; } })()
調用Demo:
MyMoudles.define("bar", [], function() { function hello(who) { return "Let me introduce: " + who; } return { hello: hello } }) MyMoudles.define("foo", ["bar"], function(bar) { var hungry = "hippo"; function awesome() { console.log(bar.hello(hungry).toUpperCase()); } return { awesome: awesome } }) var bar = MyMoudles.get("bar"); var foo = MyMoudles.get("foo"); console.log(bar.hello("hippo")); // Let me introduce: hippo foo.awesome();未來模塊機制
ES6提供了全新的模塊機制,基于函數的模塊(如上述現代模塊機制)并不是一個能被靜態識別的模式(編譯器無法識別),它們的API語義只有等到代碼運行時才會考慮進來,而ES6模塊就是一個能被靜態識別的模式,就是說API在編譯階段就會檢查API成員是否存在。
原文地址
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/106384.html
摘要:詞法熟悉語法的開發者,箭頭函數在涉及綁定時的行為和普通函數的行為完全不一致。被忽略的作為的綁定對象傳入,使用的是默認綁定規則。使用內置遍歷數組返回迭代器函數普通對象不含有,無法使用,可以進行改造,個人博客地址 this詞法 熟悉ES6語法的開發者,箭頭函數在涉及this綁定時的行為和普通函數的行為完全不一致。跟普通this綁定規則不一樣,它使用了當前的詞法作用域覆蓋了this本來的值。...
摘要:最近剛剛看完了你不知道的上卷,對有了更進一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對象原型。附錄詞法這一章并沒有說明機制,只是介紹了中的箭頭函數引入的行為詞法。第章混合對象類類理論類的機制類的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對 JavaScript 有了更進一步的了解。 《你不知道的 JavaScript》上卷由兩部...
摘要:的分句會創建一個塊作用域,其聲明的變量僅在中有效。而閉包的神奇作用是阻止此事發生。依然持有對該作用域的引用,而這個引用就叫做閉包。當然,無論使用何種方式對函數類型的值進行傳遞,當函數在別處被調用時都可以觀察到閉包。 date: 16.12.8 Thursday 第一章 作用域是什么 LHS:賦值操作的目標是誰? 比如: a = 2; RHS:誰是賦值操作的源頭? 比如: conso...
摘要:如果是聲明中的第一個詞,那么就是一個函數聲明,否則就是一個函數表達式。給函數表達式指定一個函數名可以有效的解決以上問題。始終給函數表達式命名是一個最佳實踐。也有開發者干脆關閉了靜態檢查工具對重復變量名的檢查。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Ja...
摘要:詞法作用域的查找規則是閉包的一部分。因此的確同閉包息息相關,即使本身并不會真的使用閉包。而上面的創建一個閉包,本質上這是將一個塊轉換成一個可以被關閉的作用域。結合塊級作用域與閉包模塊這個模式在中被稱為模塊。 你不知道的JS(上卷)筆記 你不知道的 JavaScript JavaScript 既是一門充滿吸引力、簡單易用的語言,又是一門具有許多復雜微妙技術的語言,即使是經驗豐富的 Jav...
閱讀 2260·2023-04-25 14:50
閱讀 1234·2021-10-13 09:50
閱讀 1866·2019-08-30 15:56
閱讀 1839·2019-08-29 15:29
閱讀 2886·2019-08-29 15:27
閱讀 3548·2019-08-29 15:14
閱讀 1192·2019-08-29 13:01
閱讀 3299·2019-08-26 14:06