你不知道的JS(下):深入JS(上)
目录
JavaScript 的运行机制
JavaScript 是一种单线程语言,这意味着它在任何时刻只会执行一个任务。为了提升效率,JavaScript 引入了事件循环和调用栈的概念。
1.1 调用栈
调用栈是一个后进先出(LIFO)的数据结构。JavaScript 执行时会将执行上下文放入调用栈中。
javascriptCopy Codefunction first() {
second();
console.log('First');
}
function second() {
console.log('Second');
}
first();
// 输出:
// Second
// First
在这个例子中,first 函数被调用,将 second 添加到调用栈中。然后 second 函数执行,输出 'Second',再返回到 first,输出 'First'。
1.2 事件循环
事件循环用于处理异步操作。在JavaScript中,当遇到异步操作时,不会阻塞主线程,而是将其放入一个任务队列,待调用栈为空时再执行。
javascriptCopy Codeconsole.log('Start');
setTimeout(() => {
console.log('Timeout');
}, 0);
console.log('End');
// 输出:
// Start
// End
// Timeout
在这个例子中,尽管 setTimeout 的延迟为 0 毫秒,它仍然会在主线程完成后执行。
作用域和闭包
2.1 作用域
作用域是变量的可访问范围。在 JavaScript 中有全局作用域和局部作用域。
javascriptCopy Codelet globalVar = 'I am a global variable';
function myFunction() {
let localVar = 'I am a local variable';
console.log(globalVar); // 可以访问全局变量
console.log(localVar); // 可以访问局部变量
}
myFunction();
// 输出:
// I am a global variable
// I am a local variable
2.2 闭包
闭包是指一个函数可以“记住”并访问它定义时的词法作用域,即使这个函数是在其词法作用域之外执行的。
javascriptCopy Codefunction outer() {
let count = 0;
return function inner() {
count++;
console.log(count);
};
}
const increment = outer();
increment(); // 输出:1
increment(); // 输出:2
在这个例子中,inner 函数形成了一个闭包,可以访问 outer 函数中的 count 变量。
原型与继承
3.1 原型
每个 JavaScript 对象都有一个原型属性,指向另一个对象。通过原型链,JavaScript 实现了继承。
javascriptCopy Codefunction Animal(name) {
this.name = name;
}
Animal.prototype.speak = function () {
console.log(`${this.name} makes a noise.`);
};
const dog = new Animal('Dog');
dog.speak(); // 输出:Dog makes a noise.
3.2 继承
可以通过原型链实现对象的继承。
javascriptCopy Codefunction Dog(name) {
Animal.call(this, name); // 调用父构造函数
}
Dog.prototype = Object.create(Animal.prototype);
Dog.prototype.constructor = Dog;
Dog.prototype.speak = function () {
console.log(`${this.name} barks.`);
};
const dog = new Dog('Rex');
dog.speak(); // 输出:Rex barks.
在这个例子中,Dog 继承了 Animal 的属性和方法。
异步编程
JavaScript 提供多种方式来处理异步编程,包括回调、Promise 和 async/await。
4.1 回调
回调是最基本的异步处理方式。
javascriptCopy Codefunction fetchData(callback) {
setTimeout(() => {
callback('Data received');
}, 1000);
}
fetchData((data) => {
console.log(data); // 输出:Data received
});
4.2 Promise
Promise 提供了一种更强大且易于管理的异步编程方式。
javascriptCopy Codefunction fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data received');
}, 1000);
});
}
fetchData().then((data) => {
console.log(data); // 输出:Data received
});
4.3 Async/Await
Async/Await 是基于 Promise 的语法糖,更加简洁易读。
javascriptCopy Codeasync function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve('Data received');
}, 1000);
});
}
(async () => {
const data = await fetchData();
console.log(data); // 输出:Data received
})();
模块化开发
模块化是将代码分割成独立模块的过程,方便管理和复用。
5.1 ES6 模块
ES6 引入了模块化的标准。
javascriptCopy Code// math.js
export function add(x, y) {
return x + y;
}
// main.js
import { add } from './math.js';
console.log(add(2, 3)); // 输出:5
5.2 CommonJS
Node.js 使用 CommonJS 模块化。
javascriptCopy Code// math.js
exports.add = function (x, y) {
return x + y;
};
// main.js
const math = require('./math');
console.log(math.add(2, 3)); // 输出:5
错误处理
错误处理是编写健壮代码的重要部分。
6.1 try...catch
使用 try...catch 捕获同步代码中的错误。
javascriptCopy Codetry {
throw new Error('Something went wrong');
} catch (error) {
console.error(error.message); // 输出:Something went wrong
}
6.2 Promise 错误处理
处理 Promise 中的错误。
javascriptCopy CodefetchData()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.error(error);
});
6.3 Async/Await 错误处理
在 async 函数中可以使用 try...catch 处理错误。
javascriptCopy Code(async () => {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
})();
性能优化
提高 JavaScript 性能的技巧包括减少 DOM 操作、使用节流和防抖等。
7.1 减少 DOM 操作
DOM 操作是昂贵的,应该尽量减少。
javascriptCopy Codeconst list = document.createElement('ul');
for (let i = 0; i < 1000; i++) {
const item = document.createElement('li');
item.textContent = `Item ${i}`;
list.appendChild(item);
}
document.body.appendChild(list);
7.2 节流和防抖
节流和防抖用于限制函数调用频率。
防抖
javascriptCopy Codefunction debounce(func, delay) {
let timeout;
return function (...args) {
clearTimeout(timeout);
timeout = setTimeout(() => func.apply(this, args), delay);
};
}
节流
javascriptCopy Codefunction throttle(func, limit) {
let lastFunc;
let lastRan;
return function (...args) {
if (!lastRan) {
func.apply(this, args);
lastRan = Date.now();
} else {
clearTimeout(lastFunc);
lastFunc = setTimeout(() => {
if (Date.now() - lastRan >= limit) {
func.apply(this, args);
lastRan = Date.now();
}
}, limit - (Date.now() - lastRan));
}
};
}
总结
JavaScript 是一种功能强大的编程语言,掌握其深入知识对于编写高效、可维护的代码至关重要。本文涵盖了 JavaScript 的运行机制、作用域与闭包、原型与继承、异步编程、模块化开发、错误处理及性能优化等内容。希望对你深入理解 JavaScript 有所帮助。