02-函數(shù)執(zhí)行-作用域鏈-面試題-內(nèi)存管理

函數(shù)執(zhí)行-作用域鏈-面試題-內(nèi)存管理

全局代碼執(zhí)行過程的回顧

var name = "why";
console.log(name);
console.log(num1);
var num1 = 20;
var num2 = 30;
var result = num1 + num2;
console.log(result);
/**
 * 1.代碼被解析,V8引擎內(nèi)部會幫助我們創(chuàng)建一個對象(globalObject -> go)
 * var globalObject = {
 *  String: "類",
 *  Date: "類",
 *  setTimeout: "函數(shù)",
 *  window: globalObject,
 *  name: undefined,
 *  num1: undefined,
 *  num2: undefined,
 *  result: undefined
 * };
 * 2.運行代碼
 *  >2.1.v8為了執(zhí)行代碼,v8引擎內(nèi)部會有一個執(zhí)行上下文棧(Execution Context ECStack)(函數(shù)調(diào)用棧)
 *  2.2.因為我們執(zhí)行的是全局代碼,為了全局代碼能夠正常的執(zhí)行,需要創(chuàng)建全局執(zhí)行上下文(Global Context ECStack)(全局代碼需要被執(zhí)行才會創(chuàng)建)
 *    >2.2.1.生成一個VO(Variable Object)
 *      VO = var globalObject = {
 *        String: "類",
 *        Date: "類",
 *        setTimeout: "函數(shù)",
 *        window: globalObject,
 *        name: undefined,
 *        num1: undefined,
 *        num2: undefined,
 *        result: undefined
 *      };
 *    >2.2.1.開始執(zhí)行代碼
 *    var globalObject = {
 *      String: "類",
 *      Date: "類",
 *      setTimeout: "函數(shù)",
 *      window: globalObject,
 *      name: "why",
 *      num1: 20,
 *      num2: 30,
 *      result: 50
 *    };
 *    如果console.log(result) =>   打印50
 *    如果在var name = "why"之后console.log(name) 打印why
 *    如果在var name1 = "20;之前console.log(name1) 打印undefined
 */
// why
// undefined
// 50

函數(shù)執(zhí)行

index.html

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
    <script src="./全局代碼執(zhí)行過程(函數(shù)).js"></script>
  </body>
</html>

全局代碼執(zhí)行過程(函數(shù)).js

var name = "why";
console.log(num1);
var num1 = 20;
var num2 = 30;
var result = num1 + num2;
console.log(result);
console.log(window);
/**
 * 1.代碼被解析,V8引擎內(nèi)部會幫助我們創(chuàng)建一個對象(globalObject -> go)
 * var globalObject = {
 *  String: "類",
 *  Date: "類",
 *  setTimeout: "函數(shù)",
 *  window: globalObject,
 *  name: undefined,
 *  num1: undefined,
 *  num2: undefined,
 *  result: undefined
 * };
 * 2.運行代碼
 *  >2.1.v8為了執(zhí)行代碼,v8引擎內(nèi)部會有一個執(zhí)行上下文棧(Execution Context ECStack)(函數(shù)調(diào)用棧)
 *  2.2.因為我們執(zhí)行的是全局代碼,為了全局代碼能夠正常的執(zhí)行,需要創(chuàng)建全局執(zhí)行上下文(Global Context ECStack)(全局代碼需要被執(zhí)行才會創(chuàng)建)
 *    >2.2.1.生成一個VO(Variable Object)
 *      VO = var globalObject = {
 *        String: "類",
 *        Date: "類",
 *        setTimeout: "函數(shù)",
 *        window: globalObject,
 *        name: undefined,
 *        num1: undefined,
 *        num2: undefined,
 *        result: undefined
 *      };
 *    >2.2.1.開始執(zhí)行代碼
 *    var globalObject = {
 *      String: "類",
 *      Date: "類",
 *      setTimeout: "函數(shù)",
 *      window: globalObject,
 *      name: "why",
 *      num1: 20,
 *      num2: 30,
 *      result: 50
 *    };
 *    如果console.log(result) =>   打印50
 *    如果在var name1 = "20;之前console.log(name1) 打印undefined
 *    window.num1 = 20
 *    window.num2 = 30
 *    window.result = 50
 */
// undefined
// 50
// window

var name = "why";
function foo() {
  console.log("foo");
}
foo();
var num1 = 20;
var num2 = 30;
var result = num1 + num2;
// foo

var name = "why";
foo();
function foo() {
  console.log("foo");
}
var num1 = 20;
var num2 = 30;
var result = num1 + num2;
// foo

var name = "why";
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  console.log("foo");
}
/**
 * 編譯
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: undefined,
 *    foo: foo的地址值 => {   地址值  內(nèi)存中開辟一塊空間,保存foo函數(shù)(父級作用域,執(zhí)行的代碼塊)
 *      num: undefined
 *      m: undefined
 *      n: undefined
 *    }
 *  }
 * 執(zhí)行
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: "why",
 *    foo: foo的地址值 => {
 *      num: 123
 *      m: 10
 *      n: 20
 *    }
 *  }
 */
// undefined
// foo

var name = "why";
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  var name = "foo";
  console.log(name);
}
/**
 * 編譯
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: undefined,
 *    foo: foo的地址值 => {   地址值  內(nèi)存中開辟一塊空間,保存foo函數(shù)(父級作用域,執(zhí)行的代碼塊)
 *      num: undefined
 *      m: undefined
 *      n: undefined,
 *      name: undefined
 *    }
 *  }
 * 執(zhí)行
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: "why",
 *    foo: foo的地址值 => {
 *      num: 123
 *      m: 10
 *      n: 20,
 *      name: "foo"
 *    }
 *  }
 */
// undefined
// foo

作用域鏈

  • 當(dāng)我們查找一個變量時,真實的查找路徑是沿著作用域鏈來查找的
var name = "why";
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  console.log(name);
}
/**
 * 編譯
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: undefined,
 *    foo: foo的地址值 => {   地址值  內(nèi)存中開辟一塊空間,保存foo函數(shù)(父級作用域,執(zhí)行的代碼塊)
 *      num: undefined
 *      m: undefined
 *      n: undefined
 *    }
 *  }
 * 執(zhí)行
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: "why",
 *    foo: foo的地址值 => {
 *      num: 123
 *      m: 10
 *      n: 20
 *    }
 *  }
 */
// undefined
// why
var name = "why";
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  function bar() {
    console.log(name);
  }
  bar();
}
/**
 * 編譯
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: undefined,
 *    foo: foo的地址值 => {   地址值  內(nèi)存中開辟一塊空間,保存foo函數(shù)(父級作用域,執(zhí)行的代碼塊)
 *      num: undefined
 *      m: undefined
 *      n: undefined,
 *      bar: bar的地址 => {  地址值  內(nèi)存中開辟一塊空間,保存bar函數(shù)(父級作用域,執(zhí)行的代碼塊}
 *    }
 *  }
 * 執(zhí)行
 *  var GlobalObject = {
 *    String: "類",
 *    window: GlobalObject,
 *    name: "why",
 *    foo: foo的地址值 => {
 *      num: 123
 *      m: 10
 *      n: 20
 *      bar: bar的地址值 => {}
 *    }
 *  }
 */
// undefined
// why
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  function bar() {
    console.log(name);
  }
  bar();
}
// name is not defined
var age = 100;
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  function bar() {
    console.log(age);
  }
  bar();
}
// undefined
// 100
foo(123);
function foo(num) {
  console.log(m);
  var m = 10;
  var n = 20;
  function bar() {
    console.log(age);
  }
  bar();
}
// age is not defined
var message = "Hello Global";
function foo() {
  console.log(message);
}
function bar() {
  var message = "Hello Bar";
  foo();
}
bar();
// Hello Global
var message = "Hello Global";
function foo() {
  console.log(message);
}
function bar() {
  var message = "Hello Bar";
  foo();
}
bar();
/**
 * 編譯
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    message: undefined,
 *    foo: foo的地址值,
 *    bar: bar的地址值 => {
 *      message: undefined,
 *      foo: 和之前foo的地址值相同,為同一個
 *    }
 *  }
 * 執(zhí)行
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    mesage: "Hello Global"
 *    foo: foo的地址值,
 *    bar: bar的地址值 => {
 *      message: "Hello Bar",
 *      foo: 和之前foo的地址值相同,為同一個
 *    }
 *  }
 */
// Hello Global
變量環(huán)境和記錄.png

作用域面試題

var n = 100;
function foo() {
  n = 200;
}
foo();
console.log(n);
/**
 * 編譯
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: undefined,
 *    foo: foo的地址值
 *  }
 * 執(zhí)行
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: 100,
 *    foo: foo的地址值 => {
 *      n: 200
 *    }
 *  }
 */
// 200
function foo() {
  console.log(n);
  var n = 200;
  console.log(n);
}
var n = 100;
foo();
/**
 * 編譯
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: undefined,
 *    foo: foo的地址值 => {
 *      n: undefined
 *    }
 *  }
 * 執(zhí)行
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: 100,
 *    foo: foo的地址值 => {
 *      n: 200
 *    }
 *  }
 */
// undefined
// 200
var n = 100;
function foo1() {
  console.log(n);
}
function foo2() {
  var n = 200;
  console.log(n);
  foo1();
}
foo2();
console.log(n);
/**
 * 編譯
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: undefined,
 *    foo1: foo1的地址值 => {}
 *    foo2: foo2的地址值 => {
 *      n: undefined,
 *      foo1: foo1的地址值 => {}
 *    }
 *  }
 * 執(zhí)行
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: 100,
 *    foo1: foo1的地址值 => {
 *       n: 100,
 *       foo1: foo1的地址值 => {}
 *    }
 *    foo2: foo2的地址值 => {
 *      n: 200
 *    }
 *  }
 */
// 200
// 100
// 100
var a = 100;
function foo() {
  console.log(a);
  return;
  var a = 100;
}
foo();
/**
 * 編譯
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: undefined,
 *    foo: foo的地址值 => {
 *      n: undefined
 *    }
 *  }
 * 執(zhí)行
 *   var GlobalObject = {
 *    window: GlobalObject,
 *    n: 100,
 *    foo: foo的地址值 => {
 *      n: undefined
 *    }
 *  }
 */
// undefined
function foo() {
  var m = 100;
}
foo();
console.log(m);
// m is not defined
function foo() {
  m = 100;
}
foo();
console.log(m);
// 100
function foo() {
  var a = (b = 100);
}
foo();
console.log(a);
console.log(b);
// a is not defined
function foo() {
  var a = (b = 100);
}
foo();
console.log(b);
console.log(a);
// 100
// a is not defined
function foo() {
  var a = (b = 10);
  /**
   * var a = (b = 10); 轉(zhuǎn)化為
   *  var a = 10
   *  b = 10
   */
}
foo();
console.log(b);
console.log(a);
// 19
// a is not defined

內(nèi)存管理

內(nèi)存管理

  • 不管什么樣的編程語言,在代碼的執(zhí)行過程中都是需要給它分配內(nèi)存的
    • 某些編程語言需要我們自己手動的管理內(nèi)存
    • 某些編程語言會可以自動幫助我們管理內(nèi)存

JavaScript的內(nèi)存結(jié)構(gòu)

  • 棧結(jié)構(gòu)
  • 堆結(jié)構(gòu)
var name = "why";
var age = 18;
var obj = { name: "kobe", age: 40 };
var names = ["abc", "cba"];
/**
 * 棧
 *  var name = "why"
 *  var age = 18;
 *  var obj => 堆  返回一個地址值 0xobj
 *  var names => 堆  返回一個地址值 0xnames
 * 堆
 *  0xobj { name: "kobe", age: 40 }
 *  0xnanes ["abc", "cba"]
 */
const obj = { name: "why" };
var info = { name: "kobe", friend: obj };
var p = { name: "james", friend: obj };
/**
 * 棧
 *  var obj => 堆 0xobj
 *  var info => 堆 0xinfo
 *  var p => 0x - p
 * 堆
 *  0xobj { name: "why" }
 *  0xinfo { name: "kobe", friend: 0xobj }
 *  0xp { name: "james", friend: 0xobj }
 * 垃圾回收期
 *  引用計數(shù)法
 *    指向obj
 *      指向一次 +1
 *      少一次指向  -1
 *      當(dāng)為0時, 就GC被回收
 *    弊端
 *      引用計數(shù)存在一個很大的弊端 : 循環(huán)引用
 *      示例
 *        var obj1 = { friend: obj2 };
 *        var obj2 = { friend: obj1 };
 *    標(biāo)記清除
 *      看附帶圖片
 */

垃圾回收器

  • 英文
    • Garbage Collection,簡稱GC
  • 對于那么不再使用的對象,我們都稱之為是垃圾,他需要被回收,已釋放更多的內(nèi)存空間
  • 而我們的語言運行環(huán)境,比如Java的運行環(huán)境JVM,JavaScript的運行環(huán)境JS引擎都會內(nèi)存垃圾回收器

GC算法

垃圾回收機制-引用計數(shù).png
垃圾回收機制-標(biāo)記清除.png
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容