91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

了解Javascript中變量和詞法環境

發布時間:2020-07-08 10:17:14 來源:億速云 閱讀:304 作者:Leah 欄目:web開發

這篇文章將為大家詳細講解有關了解Javascript中變量和詞法環境,文章內容質量較高,因此小編分享給大家做個參考,希望大家閱讀完這篇文章后對相關知識有一定的了解。

其實,我覺得Javascript核心中重要的東西并非是從舊版本擴展來的高大上的語法,例如解構賦值啊、展開語法和剩余參數(嘛……雖然的確是很666),但是用好這些,其實都建立在你對變量的認識上(常有人不知道什么是左值或右值的區別)正因如此,我覺得了解一個Javascript還是從最基本做起,就是了解一下何為變量吧。

本文其實也并非完全基礎,還是建立在對Javascript有一定了解之上的,至少對對象要有一定的認知。開始吧。

變量與數據

什么是變量?

越簡單的問題答案往往越是讓人感到意外,多數人的答案都與有關;事實上變量就是程序可操作的存儲區(術語內存空間),在Javascript程序運行時,存儲區(術語就是內存空間)可以保存我們所需的任何東西,代碼、數據……等等。然后可以將變量保存的數據大致上分割為兩類:原始類型(同基本類型)和引用類型;從變量中取出來的數據就是值,把一個值放到變量中時,該值就又變成了數據。

Javascript和其他語言相似,變量也需要被聲明才能實際存在,聲明后的變量稱之為實例化,為變量賦予一個值(默認為undefined)時,稱之為變量的初始化,只是實例化而未初始化的變量都處于uninitialized狀態。

例如:

let a = a ;         // (*)
console.log(a);
// ReferenceError: can't access lexical declaration `a' before initialization

很完美的報錯了(在(*)標志的位置),提示我們沒有初始化這個變量時就無法使用。這是不同于C++這類底層的變量的地方。其實這種現象在Javascript有一個極為高大上的名字:暫存死區,等過幾章節我就說明產生的原因。

(忘了說了,在變量聲明也需要一個名字,術語稱作標識符,我覺得不補充也不影響什么……)

不過Javascript另外特殊的地方在于,它對var聲明的變量是可以自動初始化的,Javascript會自動會為var聲明的變量賦予一個undefined值。
例如:

var a = a;console.log(a);    // undefined.

看吧,明明都差不多,結果卻全然不同。
但是實際上卻沒什么卵用,見下面的代碼:

var a = a;console.log(a+2);   // NaN

結果是NaN, 得到了一個我們完全不想要的結果。在如果無法順利數學計算時,Javascript便會給出一個非數字的結果,用NaN表示。但是比較有趣的是,如果你用typeof去驗證NaN類型:

typeof NaN ;      // number

卻告訴我們,這TMD是一個數值 number
Javascript莫名其妙的地方還有許多許多,不過我們還是不要繼續調戲javascript了,開始認真學習了。

類型與存儲

Javascript一共有 7 種原始類型 和 1 種 引用類型,如下:

  • 原始類型

    1、number

    2、string

    3、boolean

    4、symbol

    5、bigint

    6、undefined

    7、null

  • 引用類型:

    object

(這里面我就用小寫了,因為typeof返回的是小寫的)
我就是介紹一下這些必須要了解的東西,具體用法其他資料都有我就不贅述了。不過關于typeof還有要補充的一點是,它對于nullfunction結果:

function sayHello(){
     console.log('hello the world');
 }
 console.log(typeof sayHello);  // function
 console.log(typeof null);      // object

……對于一個函數,它真的返回的是一個“函數”,某種意義上用處很大,不過對null值返回一個object,這只能說有得就有缺吧。

我覺得對變量加深了解的辦法就是明白它的底層運作方式。其實也沒有什么了不起的,原始值是直接放在內存棧區, 引用類型值則是放在內存堆區(這是它的實際存儲區位置);(如果是常量,那么就會放在中,好像也是棧區的一部分)。正常情況下,變量取值都是直接都是從內存棧區中獲取的,但是引用類型的值是放在內存堆中,那么怎么辦?

引用類型值的訪問:

1、一個引用類型的變量,會在內存棧中保存一個指針

2、這個指針是用于引用內存堆中的存儲區的內存地址

3、在訪問一個類型值時

4、會通過指針找到內存堆中的存儲區,然后從中獲取值。

例如:

  var first  = {
      name:'hahei...'
  }
  var gggiii=111222;

映射圖如下:

了解Javascript中變量和詞法環境

注意:此處我用 ref. first表示  存儲區的引用 , 因為雖然保存的盡管是指針,但是在訪問這個值時,會進行二次解析(即通過這個指針找到存儲區), 而不是直接返回這個指針的具體數據。詳細可以參考 C++引用。

初識詞法環境

想必各位都已經對什么是作用域了若指掌,但是我還是必須重新提一下作用域標識符的可訪問范圍,在Javascript中的任何操作,幾乎都有作用域的參與。Javascript中使用詞法環境決定作用域,在下面我會簡單介紹一下。(請注意,這里我沒有用變量這個術語,因為解析標識符范圍時,應該還沒有真正生成代碼,感興趣的可以去了解一下AST語法樹

看,以下代碼:

 var val=111;
 function hahaha(){
     console.log(val);
 }
 function hihihi(){
    hahaha();
 }
 hihihi();  /// 111

的確是正確輸出了,111

但是我更喜歡把 val放在一個函數中,如:

   function hahaha(){
       console.log(val);      /// (**)
   }
   function hihihi(){
      var val=111;            /// (*)
      hahaha();
   }
   hihihi();

結果就是Uncaught ReferenceError: val is not defined, 根本沒找到val這個標識符,這是為什么?

因為執行過程是這樣的:

  1. hihihi函數執行  , 然后為 val賦值……
  2. hahaha函數執行
  3. hahaha找不到val標識符,便去外部詞法環境
  4. hahaha外部詞法環境就是** hahaha函數聲明時代碼的外部**,即全局代碼(下稱全局詞法環境)
  5. 全局詞法環境沒找到val,終了。
    (請注意3-5步, 找val找的是函數聲明代碼的外部,而不是函數調用時的位置。)

現在應該提一下概念了,詞法環境(Lexical Environment)就是根據代碼結構時決定的作用域,也可以稱作詞法作用域(Lexical Scoping)它是靜態作用域。可以這么說,在源代碼寫好時,所有標識符的作用域就已經被決定。當然也有動態作用域,你可以去試試bash腳本,它就是動態的。嘿嘿。詳細也可以參考靜態作用域詞法作用域

此處只要發現了個中區別就極好掌握,所以我就略了。

詞法環境的抽象

在Javascript常用三種詞法環境: 一、塊級作用域 二、全局作用域 三、函數作用域。

有時,我們會將一個詞法環境(即作用域,下面我會正式使用詞法環境替代作用域這個術語)抽象成偽代碼,如下:

	LexicalEnvironment = {
		OuterEnv: < ... > ,
		This :   < ... > ,
		EnvironmentRecord:{
			// ... identifiername:variable
		}
	}

很簡單:

  • OuterEnv:當前詞法環境的外部詞法環境
  • This: 當前詞法環境的 this的值,但它是運行時決定的。
  • EnvironmentRecord(環境記錄): 標識符-變量的映射,注意,這里的標識符只是單純的字符串,變量指的是存儲區的數據。而且標識符必須是當前詞法環境,而不是當前代碼的。

例如:

  function first(){
      var a  =100;
      let d = 220;
      {     // Block, 
          var b = a+100;
          let c = b*10;
          console.log(a,b,c,d);
      }
  }
  first();  // 100 200 2000 220

一定不要忽略first函數中的塊級作用域,這很重要。

然后寫成抽象就是:
函數內部的塊級作用域

	BlockEnv = {
		OuterEnv: < FuncFirstEnv > ,
		This :   < window > ,
		EnvironmentRecord:{
			c:< 2000 >              // 這里沒有b
		}
	}

函數作用域

	FuncEnv = {
		OuterEnv: < GlobalEnv > ,
		This :   < window > ,
		EnvRec:{
			a:< 100 >,
			d:< 220 >,
			b:< 200 >
		}
	}

OKay,先到這里吧。

一些問題:

1、為什么用詞法環境代替作用域
–詞法環境涵蓋了作用域,但反之則不能。
–但注意,詞法作用域和詞法作用域鏈與作用域以及作用域鏈都可通用。

2、環境記錄是什么?
–當前環境下的標識符-變量的映射
–但是標識符只是“合法標識符”的字符串形式。
–變量是是指存儲區的內容,但是確切說法是存儲區

最后

我把我的筆記,重新整理后發到博客上后發現——我筆記干凈了好多,艸。

這種只深入核心的內容很有用,而且在寫代碼時也變得靈活很多了。我覺得這就是最有用的地方
最后:
個人理解,常有失誤;細細查看不知何處,望君做到心中有數。

關于了解Javascript中變量和詞法環境就分享到這里了,希望以上內容可以對大家有一定的幫助,可以學到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

竹溪县| 肥西县| 绵竹市| 清苑县| 张家港市| 安平县| 岳池县| 七台河市| 玛沁县| 松阳县| 南丹县| 临猗县| 新化县| 临西县| 漳浦县| 平果县| 平谷区| 龙岩市| 始兴县| 广元市| 扎囊县| 革吉县| 通道| 普洱| 永靖县| 渝北区| 禹城市| 蓬莱市| 永定县| 肃北| 孝感市| 成武县| 石狮市| 井陉县| 文安县| 榕江县| 莱芜市| 介休市| 高要市| 辽源市| 元谋县|