天天看點

你不知道的javascript[上]學習總結(第一部分1-3章)

第一部分 作用域和閉包(1-3章)

代碼在執行前,會經過三個步驟

分詞-詞法分析

  • 将由字元組成的【代碼字串】分解為【有意義的代碼塊】,被稱為【詞法單元】
  • 比如,var a = 2; 通常會被分解為幾個詞法單元:var、a、=、2。被稱為【詞法單元流數組】

解析-文法分析

  • 将詞法單元流數組轉換為一套代表了程式文法的【抽象文法樹AST】,數組中的每一項被轉化為了AST樹中的節點

代碼生成

  • 将AST轉化為一組【機器指令】,用來建立一個叫 a 的變量(記憶體配置設定),并将值 2 存儲在 a 中

相比較,js引擎更加複雜,會在三個階段中進行【運作性能優化】,包括【備援元素優化】

在js中,多數編譯發生在【代碼執行前幾微秒】

作用域是根據名稱查找變量的規則

  • 引擎,負責整個 js 程式的編譯和執行過程
  • 編譯器,負責文法分析和代碼生成
  • 作用域,是一套規則,收集維護由所有聲明的辨別符組成的查詢,并确定目前執行的代碼是否有權限通路

變量的指派

  • 首先,編譯器會詢問目前作用域是否存在該變量,如果沒有就聲明一個
  • 然後,在運作時引擎會在作用域中查詢該變量,如果有就指派
  • 仍以 a=2 為例,引擎會為變量 a 進行【LHS查詢(左查)】
  • LHS查詢會試圖找到變量 a 的容器本身,并對其指派。另一種【LHR查詢(右查)】則隻是簡單的查找變量
  • 【變量指派】和【調用函數時傳參】,這兩種操作都會導緻【LHS查詢】

小測試,找出LHS查詢和LHR查詢

function foo(a){
    var b = a;
    return a + b;
}
var c = foo(2);
//LHR查詢
foo(2
= a
a..
..b
//LHS查詢
c = 
b = 
a = 2 (傳參,隐式變量配置設定)
           

ReferenceError 和 TypeError

  • 如果【RHS查詢】在作用域中找不到需要的變量,引擎就會抛出 ReferenceError ,代作作用域判别失敗
  • 試圖引用 null 或是 undefined 屬性,會引發 TypeError,代表作用域判别成功,但是操作是非法的

eval 和 with

  • eval 會動态插入一個變量聲明,這會對詞法作用域的環境進行修改
  • with 被當作重複引用一個對象中的多個屬性時的快捷方式,不必重複引用對象本身。這種方式相當于建立了新的詞法作用域
  • 這兩種方式,當引擎在進行編譯時,不能進行相關的性能優化,【不要使用】
//eval
eval("var c = 666");
console.log(c);
//width
var obj = {
  a:1,
  b:2,
  c:3
}
with(obj){
  a = 111;
  b = 222;
  c = 333;
}
console.log(obj);//{ "a": 111, "b": 222, "c": 333 }
           

匿名函數自執行表達式 | Immediately invoked function expression

  • 有兩種寫法,都是一樣的,如下
  • 如果要在其内部,擷取函數對象,隻有一種方法,如下
  • 不要用【匿名函數自執行表達式】,要使用【具名函數自執行表達式】,如下
(function(){console.log(1)})();//1
(function(){console.log(2)}());//2
// arguments.callee在函數内部調用函數的方法
(function(){
  console.log(arguments.callee);//
})();
//使用可描述的名稱,能讓代碼不言自明
(function printName(){console.log("name")})();
(function printColor(){console.log("color")}());
           

try catch 屬于塊級作用域

使用塊級作用域提升性能

  • 如下,由于 setTimeout 引用了 color 變量,如果沒有大括号,代碼塊一中的變量會一直保留給 setTimeout,不會被垃圾回收機制處理
  • 而實際上,setTimeout 中隻引用了 color,代碼塊一完全可以在執行完後釋放,是以可以手動加上塊級作用域
function doSomething(data){
  console.log(data);
}
// 代碼塊一
{
  const data = [1,2,3];
  doSomething(data);
}
const color = "green";
setTimeout(function(){
  //如果不需要data,則可以将代碼塊一,放在大括号中,這樣垃圾會收機制會釋放出這一部分記憶體
  //console.log(data);
  console.log(color);
},2000)
           

變量提升

小測試,輸出啥

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

-不是undefined,有變量提升

小測試,再試一下

console.log(a);//undefined
var a = 2;
           
  • 不是2,也不會報ReferenceError,而是undefined
  • 因為,【變量聲明存在提升,但變量指派不會】