初识JS,浅析JavaScript 代码的执行机制
2023-12-03 16:01:06
JavaScript 代码执行机制概述
JavaScript 是一种解释型语言,这意味着它逐行执行代码,而不是像编译型语言那样将整个程序编译成机器代码再执行。JavaScript 代码的执行机制主要分为以下几个阶段:
- 词法分析和解析 :在这个阶段,JavaScript 引擎会将源代码转换成抽象语法树 (AST),AST 是代码的结构化表示,便于后续的执行。
- 变量提升 :在解释执行之前,JavaScript 会将所有声明的变量提升到当前作用域的顶部。这意味着,变量可以先使用,再声明。
- 代码执行 :JavaScript 引擎逐行解释执行代码,并将执行结果存储在内存中。
- 垃圾回收 :当变量不再被使用时,JavaScript 引擎会自动释放该变量所占用的内存空间。
JavaScript 代码执行机制的几个核心概念
变量提升
变量提升是指 JavaScript 会将所有声明的变量提升到当前作用域的顶部。这意味着,变量可以在声明之前使用,但是此时的变量值是 undefined。
console.log(myName); // undefined
var myName = 'John Doe';
函数提升
函数提升是指 JavaScript 会将所有声明的函数提升到当前作用域的顶部。这意味着,函数可以在声明之前调用,但是此时函数内部的变量和参数都是 undefined。
foo(); // TypeError: foo is not a function
function foo() {
console.log('Hello, world!');
}
作用域
作用域是指代码中变量和函数的可见范围。在 JavaScript 中,有全局作用域和局部作用域之分。全局作用域是指整个程序都可以访问的变量和函数,而局部作用域是指函数内部的变量和函数。
var globalVariable = 'Hello, world!';
function foo() {
var localVariable = 'Goodbye, world!';
}
console.log(globalVariable); // Hello, world!
console.log(localVariable); // ReferenceError: localVariable is not defined
闭包
闭包是指函数及其内部作用域的组合。这意味着,函数内部的变量和函数即使在函数执行完成后仍然存在。
function createCounter() {
var count = 0;
return function() {
return ++count;
};
}
var counter = createCounter();
console.log(counter()); // 1
console.log(counter()); // 2
console.log(counter()); // 3
执行上下文
执行上下文是指 JavaScript 代码执行的环境。它包括当前执行的代码、变量和函数。当一个函数被调用时,一个新的执行上下文就会被创建。
function foo() {
console.log(this); // [object Window]
}
foo();
var obj = {
foo: function() {
console.log(this); // [object Object]
}
};
obj.foo();
调用栈
调用栈是指 JavaScript 引擎用来跟踪函数调用顺序的数据结构。当一个函数被调用时,该函数的信息会被压入调用栈。当函数执行完成后,该函数的信息会被弹出调用栈。
function foo() {
bar();
}
function bar() {
baz();
}
function baz() {
console.log('Hello, world!');
}
foo();
当这段代码执行时,调用栈如下:
foo()
bar()
baz()
当 baz() 函数执行完成后,baz() 函数的信息会被弹出调用栈。当 bar() 函数执行完成后,bar() 函数的信息也会被弹出调用栈。最后,当 foo() 函数执行完成后,foo() 函数的信息也会被弹出调用栈。
堆
堆是指 JavaScript 引擎用来存储对象和数组的数据结构。当一个对象或数组被创建时,该对象或数组的信息会被存储在堆中。
var obj = {
name: 'John Doe',
age: 30
};
var arr = [1, 2, 3];
当这段代码执行时,obj 对象和 arr 数组的信息都会被存储在堆中。
原型链
原型链是指 JavaScript 对象继承的链条。当一个对象被创建时,该对象会继承其原型的所有属性和方法。对象的原型是该对象所属类的实例。
function Person(name, age) {
this.name = name;
this.age = age;
}
Person.prototype.greet = function() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};
var john = new Person('John Doe', 30);
john.greet(); // Hello, my name is John Doe and I am 30 years old.
当这段代码执行时,john 对象会继承 Person 类的所有属性和方法。因此,john 对象可以调用 Person 类的 greet() 方法。
this
this 是指当前执行代码的对象。this 的值可以是全局对象、函数对象、对象实例等。
console.log(this); // [object Window]
function foo() {
console.log(this); // [object Window]
}
foo();
var obj = {
foo: function() {
console.log(this); // [object Object]
}
};
obj.foo();
当这段代码执行时,this 的值会在不同的上下文中发生变化。在全局上下文中,this 的值为全局对象。在函数上下文中,this 的值为函数对象。在对象上下文中,this 的值为对象实例。
事件循环
事件循环是指 JavaScript 引擎用来处理事件的机制。当事件发生时,例如鼠标点击、键盘按下、定时器超时等,事件循环会将该事件放入事件队列中。事件循环会不断地从事件队列中取出事件并执行。
// 鼠标点击事件
document.addEventListener('click', function() {
console.log('The mouse was clicked!');
});
// 定时器事件
setTimeout(function() {
console.log('1 second has passed!');
}, 1000);
// 键盘按下事件
document.addEventListener('keydown', function() {
console.log('A key was pressed!');
});
当这段代码执行时,事件循环会将鼠标点击事件、定时器事件和键盘按下事件放入事件队列中。然后,事件循环会不断地从事件队列中取出事件并执行。
异步编程
异步编程是指代码在不等待结果的情况下继续执行。在 JavaScript 中,异步编程可以通过回调函数、Promise 和 async/await 来实现。
// 回调函数
function foo(callback) {
setTimeout(function() {
callback('Hello, world!');
}, 1000);
}
foo(function(result) {
console.log(result); // Hello, world!
});
// Promise
function foo() {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello, world!');
}, 1000);
});
}
foo().then(function(result) {
console.log(result); // Hello, world!
});
// async/await
async function foo() {
const result = await new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('Hello, world!');
}, 1000);
});
console.log(result); // Hello, world!
}
foo();
当这段代码执行时,foo() 函数会立即执行,但不会等待 setTimeout() 函数执行完成。当 setTimeout() 函数执行完成后,callback() 函数或 Promise.resolve() 函数会被调用。然后,回调函数或 Promise 的 then() 函数会被执行。最后,console.log() 函数会被执行,输出结果 Hello, world!。