函数执行-作用域链-面试题-内存管理
全局代码执行过程的回顾
var name = "why";
console.log(name);
console.log(num1);
var num1 = 20;
var num2 = 30;
var result = num1 + num2;
console.log(result);
/**
* 1.代码被解析,V8引擎内部会帮助我们创建一个对象(globalObject -> go)
* var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* window: globalObject,
* name: undefined,
* num1: undefined,
* num2: undefined,
* result: undefined
* };
* 2.运行代码
* >2.1.v8为了执行代码,v8引擎内部会有一个执行上下文栈(Execution Context ECStack)(函数调用栈)
* 2.2.因为我们执行的是全局代码,为了全局代码能够正常的执行,需要创建全局执行上下文(Global Context ECStack)(全局代码需要被执行才会创建)
* >2.2.1.生成一个VO(Variable Object)
* VO = var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* window: globalObject,
* name: undefined,
* num1: undefined,
* num2: undefined,
* result: undefined
* };
* >2.2.1.开始执行代码
* var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* 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
函数执行
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="./全局代码执行过程(函数).js"></script>
</body>
</html>
全局代码执行过程(函数).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引擎内部会帮助我们创建一个对象(globalObject -> go)
* var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* window: globalObject,
* name: undefined,
* num1: undefined,
* num2: undefined,
* result: undefined
* };
* 2.运行代码
* >2.1.v8为了执行代码,v8引擎内部会有一个执行上下文栈(Execution Context ECStack)(函数调用栈)
* 2.2.因为我们执行的是全局代码,为了全局代码能够正常的执行,需要创建全局执行上下文(Global Context ECStack)(全局代码需要被执行才会创建)
* >2.2.1.生成一个VO(Variable Object)
* VO = var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* window: globalObject,
* name: undefined,
* num1: undefined,
* num2: undefined,
* result: undefined
* };
* >2.2.1.开始执行代码
* var globalObject = {
* String: "类",
* Date: "类",
* setTimeout: "函数",
* 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的地址值 => { 地址值 内存中开辟一块空间,保存foo函数(父级作用域,执行的代码块)
* num: undefined
* m: undefined
* n: undefined
* }
* }
* 执行
* 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的地址值 => { 地址值 内存中开辟一块空间,保存foo函数(父级作用域,执行的代码块)
* num: undefined
* m: undefined
* n: undefined,
* name: undefined
* }
* }
* 执行
* var GlobalObject = {
* String: "类",
* window: GlobalObject,
* name: "why",
* foo: foo的地址值 => {
* num: 123
* m: 10
* n: 20,
* name: "foo"
* }
* }
*/
// undefined
// foo
作用域链
- 当我们查找一个变量时,真实的查找路径是沿着作用域链来查找的
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的地址值 => { 地址值 内存中开辟一块空间,保存foo函数(父级作用域,执行的代码块)
* num: undefined
* m: undefined
* n: undefined
* }
* }
* 执行
* 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的地址值 => { 地址值 内存中开辟一块空间,保存foo函数(父级作用域,执行的代码块)
* num: undefined
* m: undefined
* n: undefined,
* bar: bar的地址 => { 地址值 内存中开辟一块空间,保存bar函数(父级作用域,执行的代码块}
* }
* }
* 执行
* 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的地址值相同,为同一个
* }
* }
* 执行
* var GlobalObject = {
* window: GlobalObject,
* mesage: "Hello Global"
* foo: foo的地址值,
* bar: bar的地址值 => {
* message: "Hello Bar",
* foo: 和之前foo的地址值相同,为同一个
* }
* }
*/
// Hello Global

变量环境和记录.png
作用域面试题
var n = 100;
function foo() {
n = 200;
}
foo();
console.log(n);
/**
* 编译
* var GlobalObject = {
* window: GlobalObject,
* n: undefined,
* foo: foo的地址值
* }
* 执行
* 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
* }
* }
* 执行
* 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的地址值 => {}
* }
* }
* 执行
* 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
* }
* }
* 执行
* 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); 转化为
* var a = 10
* b = 10
*/
}
foo();
console.log(b);
console.log(a);
// 19
// a is not defined
内存管理
内存管理
- 不管什么样的编程语言,在代码的执行过程中都是需要给它分配内存的
- 某些编程语言需要我们自己手动的管理内存
- 某些编程语言会可以自动帮助我们管理内存
JavaScript的内存结构
- 栈结构
- 堆结构
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 }
* 垃圾回收期
* 引用计数法
* 指向obj
* 指向一次 +1
* 少一次指向 -1
* 当为0时, 就GC被回收
* 弊端
* 引用计数存在一个很大的弊端 : 循环引用
* 示例
* var obj1 = { friend: obj2 };
* var obj2 = { friend: obj1 };
* 标记清除
* 看附带图片
*/
垃圾回收器
- 英文
- Garbage Collection,简称GC
- 对于那么不再使用的对象,我们都称之为是垃圾,他需要被回收,已释放更多的内存空间
- 而我们的语言运行环境,比如Java的运行环境JVM,JavaScript的运行环境JS引擎都会内存垃圾回收器
GC算法

垃圾回收机制-引用计数.png

垃圾回收机制-标记清除.png