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