国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專(zhuān)欄INFORMATION COLUMN

你不知道的JavaScript·第一部分

Tonny / 3471人閱讀

摘要:空格一般沒(méi)意義會(huì)被忽略解析語(yǔ)法分析這個(gè)過(guò)程會(huì)將詞法單元轉(zhuǎn)換成抽象語(yǔ)法樹(shù)。小結(jié)本章節(jié)我們深入理解了的作用域,提升,閉包等概念,希望你能有所收獲,下一部分整理下解析對(duì)象原型等一些概念。

第一章: 作用域是什么 1、 編譯原理

JavaScript 被列為 ‘動(dòng)態(tài)’ 或 ‘解釋執(zhí)行’ 語(yǔ)言,于其他傳統(tǒng)語(yǔ)言(如 java)不同的是,JavaScript是邊編譯邊執(zhí)行的。
一段源碼在執(zhí)行前會(huì)經(jīng)歷三個(gè)步驟: 分詞/詞法分析 -> 解析/語(yǔ)法分析 -> 代碼生成

分詞/詞法分析

這個(gè)過(guò)程將字符串分解成詞法單元,如 var a = 2; 會(huì)被分解成詞法單元 var、 a、 = 、2、;。空格一般沒(méi)意義會(huì)被忽略

解析/語(yǔ)法分析

這個(gè)過(guò)程會(huì)將詞法單元轉(zhuǎn)換成 抽象語(yǔ)法樹(shù)(Abstract Syntax Tree,AST)。
如 var a = 2; 對(duì)應(yīng)的 抽象語(yǔ)法樹(shù) 如下, 可通過(guò) 在線(xiàn)可視化AST 網(wǎng)址在線(xiàn)分析

{
  "type": "Program",
  "start": 0,
  "end": 10,
  "body": [
    {
      "type": "VariableDeclaration",
      "start": 0,
      "end": 10,
      "declarations": [
        {
          "type": "VariableDeclarator",
          "start": 4,
          "end": 9,
          "id": {
            "type": "Identifier",
            "start": 4,
            "end": 5,
            "name": "a"
          },
          "init": {
            "type": "Literal",
            "start": 8,
            "end": 9,
            "value": 2,
            "raw": "2"
          }
        }
      ],
      "kind": "var"
    }
  ],
  "sourceType": "module"
}

代碼生成

將 AST 轉(zhuǎn)換成可執(zhí)行的代碼,存放于內(nèi)存中,并分配內(nèi)存和轉(zhuǎn)化為一些機(jī)器指令

2、理解作用域

其實(shí)結(jié)合上面提到的編譯原理,作用域就好理解了。作用域就是當(dāng)前執(zhí)行代碼對(duì)這些標(biāo)識(shí)符的訪(fǎng)問(wèn)權(quán)限。
編譯器會(huì)在當(dāng)前作用域中聲明一些變量,運(yùn)行時(shí)引擎會(huì)去作用域中查找這些變量(其實(shí)就是一個(gè)尋址的過(guò)程),如果找到這些變量就可以操作變量,找不到就往上一層作用域找(作用域鏈的概念),或者返回 null

第三章: 函數(shù)作用域和塊作用域 1、函數(shù)中的作用域

每聲明一個(gè)函數(shù)都會(huì)形成一個(gè)作用域,那作用域有什么用呢,它能讓該作用域內(nèi)的變量和函數(shù)不被外界訪(fǎng)問(wèn)到,也可以反過(guò)來(lái)說(shuō)是不讓該作用域內(nèi)的變量或函數(shù)污染全局。

對(duì)比:

var a = 123
function bar() {
  //...
}

function foo() {
  var a = 123
  function bar() {
    //...
  }
}

變量 a 和函數(shù) bar 用一個(gè)函數(shù) foo 包裹起來(lái),函數(shù) foo 會(huì)形成一個(gè)作用域,變量 a 和函數(shù) bar 外界將無(wú)法訪(fǎng)問(wèn),同時(shí)變量或函數(shù)也不會(huì)污染全局。

2、函數(shù)作用域

進(jìn)一步思考,上面例子的變量 a 和函數(shù) bar 有了作用域,但函數(shù) foo 不也是暴露在全局,也對(duì)全局造成污染了啊。是的,JavaScript對(duì)這種情況提出了解決方案: 立即執(zhí)行函數(shù) (IIFE)

(function foo() {
  var a = 123
  function bar() {
    //...
  }
})()

第一個(gè)()將函數(shù)變成表達(dá)式,第二個(gè)()執(zhí)行了這個(gè)函數(shù),最終函數(shù) foo 也形成了自己的作用域,不會(huì)污染到全局,同時(shí)也不被全局訪(fǎng)問(wèn)的到。

3、塊作用域

es6之前JavaScript是沒(méi)有塊作用域這個(gè)概念的,這與一般的語(yǔ)言(如Java ,C)很大不同,看下面這個(gè)例子:

for (var i = 0; i < 10; i++) {
  console.log("i=", i);
}
console.log("輸出", i); // 輸出 10

for 循環(huán)定義了變量 i,通常我們只想這個(gè)變量 i 在循環(huán)內(nèi)使用,但忽略了 i 其實(shí)是作用在外部作用域(函數(shù)或全局)的。所以循環(huán)過(guò)后也能正常打印出 i ,因?yàn)闆](méi)有塊的概念。

甚至連 try/catch 也沒(méi)形成塊作用域:

try {
  for (var i = 0; i < 10; i++) {
    console.log("i=", i);
  }
} catch (error) {}
console.log("輸出", i); // 輸出 10
解決方法1

形成塊作用域的方法當(dāng)然是使用 es6 的 let 和 const 了, let 為其聲明的變量隱式的劫持了所在的塊作用域。

for (let i = 0; i < 10; i++) {
  console.log("i=", i);
}
console.log("輸出", i); // ReferenceError: i is not defined

將上面例子的 var 換成 let 最后輸出就報(bào)錯(cuò)了 ReferenceError: i is not defined ,說(shuō)明被 let 聲明的 i 只作用在了 for 這個(gè)塊中。

除了 let 會(huì)讓 for、if、try/catch 等形成塊,JavaScript 的 {} 也能形成塊

{
  let name = "曾田生"
}

console.log(name); //ReferenceError: name is not defined
解決方法2

早在沒(méi) es6 的 let 聲明之前,常用的做法是利用 函數(shù)也能形成作用域 這么個(gè)概念來(lái)解決一些問(wèn)題的。

看個(gè)例子

function foo() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = function () {
      return i
    }
  }
  console.log(i)// i 作用在整個(gè)函數(shù),for 執(zhí)行完此時(shí) i 已經(jīng)等于 10 了
  return result
}
var result = foo()
console.log(result[0]()); // 輸出 10 期望 0
console.log(result[1]()); // 輸出 10 期望 1
console.log(result[2]()); // 輸出 10 期望 2

這個(gè)例子出現(xiàn)的問(wèn)題是執(zhí)行數(shù)組函數(shù)最終都輸出了 10, 因?yàn)?i 作用在整個(gè)函數(shù),for 執(zhí)行完此時(shí) i 已經(jīng)等于 10 了, 所以當(dāng)后續(xù)執(zhí)行函數(shù) result[x]() 內(nèi)部返回的 i 已經(jīng)是 10 了。

利用函數(shù)的作用域來(lái)解決

function foo() {
  var result = []
  for (var i = 0; i < 10; i++) {
    result[i] = function (num) {
      return function () { // 函數(shù)形成一個(gè)作用域,內(nèi)部變量被私有化了
        return num
      }
    }(i)
  }
  return result
}
var result = foo()
console.log(result[0]()); // 0
console.log(result[1]()); // 1
console.log(result[2]()); // 2

上面的例子也是挺典型的,一般面試題比較考基礎(chǔ)的話(huà)就會(huì)被問(wèn)道,上面例子不僅考察到了塊作用域的概念,函數(shù)作用域的概念,還考察到了閉包的概念(閉包后續(xù)講但不影響這個(gè)例子的理解),多琢磨一下就理解了。

第四章: 提升

提升指的是變量提升和函數(shù)提升,為什么JavaScript會(huì)有提升這個(gè)概念呢,其實(shí)也很好理解,因?yàn)镴avaScript代碼是先 編譯執(zhí)行 的,所以在編譯階段就會(huì)先對(duì)變量和函數(shù)做聲明,在執(zhí)行階段就出現(xiàn)了所謂的變量提升和函數(shù)提升了。

1、變量提升
console.log(a); // undefined
var a = 1;

上面代碼 console.log(a); // undefined 就是因?yàn)榫幾g階段先對(duì)變量做了聲明,先聲明了個(gè)變量 a, 并默認(rèn)賦值 undefined

var a;
console.log(a); // undefined
a = 1;
2、函數(shù)提升

函數(shù)同樣也存在提升,這就是為什么函數(shù)能先調(diào)用后聲明了

foo();
function foo() {
  console.log("---foo----");
}

注意:函數(shù)表達(dá)式不會(huì)被提升

foo();
var foo = function() {
  console.log("---foo----");
}
// TypeError: foo is not a function

注意:函數(shù)會(huì)首先被提升,然后才是變量

var foo = 1;
foo();
function foo() {
  console.log("---foo----");
}
// TypeError: foo is not a function

分析一下,因?yàn)樯厦胬泳幾g后是這樣的

var foo = undefined; // 變量名賦值 undefined
function foo() {     // 函數(shù)先提升
  console.log("---foo----");
}
foo = 1;             // 但接下去是變量被重新賦值了 1,是個(gè)Number類(lèi)型
foo();               // Number類(lèi)型當(dāng)然不能用函數(shù)方式調(diào)用,就報(bào)錯(cuò)了
// TypeError: foo is not a function
第五章: 作用域閉包

閉包問(wèn)題一直會(huì)在JavaScript被提起,是JavaScript一個(gè)比較奇葩的概念

1、閉包的產(chǎn)生
閉包的概念: 當(dāng)函數(shù)可以記住并訪(fǎng)問(wèn)所在的詞法作用域時(shí),就產(chǎn)生了閉包

概念貌似挺簡(jiǎn)單的,簡(jiǎn)單分析下,首先閉包是 產(chǎn)生的,是在代碼執(zhí)行中產(chǎn)生的,有的一些網(wǎng)絡(luò)博文直接將閉包定義為 某一個(gè)特殊函數(shù) 是錯(cuò)的。

閉包是怎么產(chǎn)生的呢,一個(gè)函數(shù)能訪(fǎng)問(wèn)到所在函數(shù)作用域就產(chǎn)生了閉包,注意到作用域的概念,咱們最上面的章節(jié)有提到,看下面例子:

function foo() {
  var a = 0;
  function bar() {
    a++;
    console.log(a);
  }
  return bar;
}

var bat = foo()
bat() // 1
bat() // 2
bat() // 3

結(jié)合例子分析一下: 函數(shù) foo 內(nèi)部返回了函數(shù) bar ,外部聲明個(gè)變量 bat 拿到 foo 返回的函數(shù) bar ,執(zhí)行 bat() 發(fā)現(xiàn)能正常輸出 1 ,注意前面章節(jié)提到的作用域,變量 a 是在函數(shù) foo 內(nèi)部的一個(gè)私有變量,不能被外界訪(fǎng)問(wèn)的,但外部函數(shù) bat 卻能訪(fǎng)問(wèn)的到私有變量 a,這說(shuō)明了 外部函數(shù) bat 持有函數(shù) foo 的作用域 ,也就產(chǎn)生了閉包。

閉包的形成有什么用呢,JavaScript 讓閉包的存在明顯有它的作用,其中一個(gè)作用是為了模塊化,當(dāng)然你也可以利用外部函數(shù)持有另一個(gè)函數(shù)作用域的閉包特性去做更多的事情,但這邊就暫且討論模塊化這個(gè)作用。

函數(shù)有什么作用呢,私有化變量或方法呀,那函數(shù)內(nèi)的變量和方法被私有化了函數(shù)怎么和外部做 交流 呢, 暴露出一些變量或方法呀

function foo() {
  var _a = 0;
  var b = 0;
  function _add() {
    b = _a + 10    
  }
  function bar() {
    _add()
  }
  function getB() {
    return b
  }
  return {
    bar: bar,
    getB: getB
  }
}

var bat = foo()
bat.bar()
bat.getB() // 10

上面例子函數(shù) foo 可以理解為一個(gè)模塊,內(nèi)部聲明了一些私有變量和方法,也對(duì)外界暴露了一些方法,只是在執(zhí)行的過(guò)程中順帶產(chǎn)生了一個(gè)閉包

2、模塊機(jī)制

上面提到了閉包的產(chǎn)生和作用,貌似在使用 es6語(yǔ)法 開(kāi)發(fā)的過(guò)程中很少用到了閉包,但實(shí)際上我們一直在用閉包的概念的。

foo.js
var _a = 0;
var b = 0;
function _add() {
  b = _a + 10
}
function bar() {
  _add()
}
function getB() {
  return b
}
export default {
  bar: bar,
  getB: getB
}
bat.js
import bat from "foo"

bat.bar()
bat.getB() // 10

上面例子是 es6 模塊的寫(xiě)法,是不是驚奇的發(fā)現(xiàn)變量 bat 可以記住并訪(fǎng)問(wèn)模塊 foo 的作用域,這符合了閉包的概念。

小結(jié):

本章節(jié)我們深入理解了JavaScript的 作用域提升閉包等概念,希望你能有所收獲,下一部分整理下 this解析對(duì)象原型 等一些概念。

如果有興趣也可以去我的 github-blog 提 issues ,github也整理了幾篇文章會(huì)定期更新,歡迎 star

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

轉(zhuǎn)載請(qǐng)注明本文地址:http://specialneedsforspecialkids.com/yun/95714.html

相關(guān)文章

  • 鐘快速了解《你不知道 JavaScript》(上卷)

    摘要:最近剛剛看完了你不知道的上卷,對(duì)有了更進(jìn)一步的了解。你不知道的上卷由兩部分組成,第一部分是作用域和閉包,第二部分是和對(duì)象原型。附錄詞法這一章并沒(méi)有說(shuō)明機(jī)制,只是介紹了中的箭頭函數(shù)引入的行為詞法。第章混合對(duì)象類(lèi)類(lèi)理論類(lèi)的機(jī)制類(lèi)的繼承混入。 最近剛剛看完了《你不知道的 JavaScript》上卷,對(duì) JavaScript 有了更進(jìn)一步的了解。 《你不知道的 JavaScript》上卷由兩部...

    趙春朋 評(píng)論0 收藏0
  • 你不知道JavaScript》 (上) 閱讀摘要

    摘要:但是如果非全局的變量如果被遮蔽了,無(wú)論如何都無(wú)法被訪(fǎng)問(wèn)到。但是如果引擎在代碼中找到,就會(huì)完全不做任何優(yōu)化。結(jié)構(gòu)的分句中具有塊級(jí)作用域。第四章提升編譯器函數(shù)聲明會(huì)被提升,而函數(shù)表達(dá)式不會(huì)被提升。 本書(shū)屬于基礎(chǔ)類(lèi)書(shū)籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱; 上中下三本的讀書(shū)筆記: 《你不知道的JavaScript》 (上) 讀書(shū)筆記...

    FingerLiu 評(píng)論0 收藏0
  • 你不知道JavaScript》 (中) 閱讀摘要

    摘要:這時(shí)候控制臺(tái)看到的是對(duì)象的快照,然而點(diǎn)開(kāi)看詳情的話(huà)是這段代碼在運(yùn)行的時(shí)候,瀏覽器可能會(huì)認(rèn)為需要把控制臺(tái)延遲到后臺(tái),這種情況下,等到瀏覽器控制臺(tái)輸出對(duì)象內(nèi)容時(shí),可能已經(jīng)運(yùn)行,因此會(huì)在點(diǎn)開(kāi)的時(shí)候顯示,這是的異步化造成的。 本書(shū)屬于基礎(chǔ)類(lèi)書(shū)籍,會(huì)有比較多的基礎(chǔ)知識(shí),所以這里僅記錄平常不怎么容易注意到的知識(shí)點(diǎn),不會(huì)全記,供大家和自己翻閱; 上中下三本的讀書(shū)筆記: 《你不知道的JavaScri...

    stackvoid 評(píng)論0 收藏0
  • 精讀《你不知道javascript(中卷)》

    摘要:強(qiáng)制類(lèi)型轉(zhuǎn)換本章介紹了的數(shù)據(jù)類(lèi)型之間的轉(zhuǎn)換即強(qiáng)制類(lèi)型轉(zhuǎn)換包括顯式和隱式。強(qiáng)制類(lèi)型轉(zhuǎn)換常常為人詬病但實(shí)際上很多時(shí)候它們是非常有用的。隱式強(qiáng)制類(lèi)型轉(zhuǎn)換則沒(méi)有那么明顯是其他操作的副作用。在處理強(qiáng)制類(lèi)型轉(zhuǎn)換的時(shí)候要十分小心尤其是隱式強(qiáng)制類(lèi)型轉(zhuǎn)換。 前言 《你不知道的 javascript》是一個(gè)前端學(xué)習(xí)必讀的系列,讓不求甚解的JavaScript開(kāi)發(fā)者迎難而上,深入語(yǔ)言?xún)?nèi)部,弄清楚JavaSc...

    李世贊 評(píng)論0 收藏0
  • 你不知道提升 - 先有雞還是先有蛋?

    摘要:一先有雞還有先有蛋直覺(jué)上會(huì)認(rèn)為代碼在執(zhí)行時(shí)是由上到下一行一行執(zhí)行的。不幸的是兩種猜測(cè)都是不對(duì)的。換句話(huà)說(shuō),我們的問(wèn)題先有雞還是先有蛋的結(jié)論是先有蛋聲明后有雞賦值。 一、先有雞還有先有蛋? 直覺(jué)上會(huì)認(rèn)為javascript代碼在執(zhí)行時(shí)是由上到下一行一行執(zhí)行的。但實(shí)際上這并不完全正確,有一種特殊情況會(huì)導(dǎo)致這個(gè)假設(shè)是錯(cuò)誤的。 a = 2; var a; console.log(a); 大家...

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

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

0條評(píng)論

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