青训营上课笔记
三.JavaScript
JavaScript是一种高级的、直译式的编程语言,常用于前端开发,在后端也有广泛应用。
1.数据类型
a.JavaScript有七种基本数据类型:undefined、null、boolean、number、string、symbol、object。其中,null和object在typeof操作符中返回"object"。
b.JavaScript的基本数据类型是按值传递的,而对象则是按引用传递的。
c.JavaScript还有一种特殊的包装类型:Number、String、Boolean。这些包装类型实际上是对应的基本数据类型的对象包装。
// 示例代码
let foo = 5;
let bar = foo; // 将foo的值复制到bar,此时bar的值为5
foo = 10;
console.log(bar); // 输出:5,表明bar的值没有被改变
let obj1 = {name: 'John'};
let obj2 = obj1; // 将obj1的引用赋值给obj2,此时obj2指向的是obj1指向的对象
obj1.name = 'Jane';
console.log(obj2.name); // 输出:Jane,表明obj2指向的对象的属性被改变了
2.作用域和闭包
a.JavaScript使用词法作用域,即函数在声明时就确定了其作用域,与函数调用的位置无关。作用域规定了标识符的可见范围。
b.JavaScript支持函数嵌套,并且内部函数可以访问外部函数的变量。这种机制称为闭包。
c.闭包可以用来创建私有变量和访问外部函数的数据。
// 示例代码
function outer() {
let count = 0; // count是外部函数outer的局部变量
function inner() {
count++; // 内部函数inner可以访问外部函数outer的变量count
console.log(count);
}
return inner;
}
let closure = outer(); // 将返回的内部函数inner赋值给closure
closure(); // 输出:1
closure(); // 输出:2
console.log(count); // 报错,count是outer内部的局部变量,无法在外部访问
3.原型和原型链
a.JavaScript中的对象有一个原型(prototype)属性,可以指向另一个对象。如果某个对象的属性或方法在自身找不到,就会去原型对象中查找。
b.原型链是由多个对象的原型构成的链表结构,用于查找对象的属性和方法。
// 示例代码
let person = { name: 'John' };
let student = Object.create(person); // 创建一个新对象,并将person对象设置为其原型
student.id = 123;
console.log(student.name); // 输出:John,student对象的原型是person对象,所以可以访问name属性
console.log(student.id); // 输出:123
console.log(student.toString()); // 输出:[object Object],student对象的原型是Object.prototype,所以可以调用toString方法
4.异步编程
a.JavaScript中的异步编程通过回调函数、Promise、async/await等方式来实现。
b.回调函数是一种传递给其他函数的函数,用于在异步操作完成后执行。但多层嵌套的回调函数容易产生回调地狱,使代码难以理解和维护。
c.Promise是一个用于处理异步操作的对象,可以更好地组织异步代码。Promise有三种状态:pending、fulfilled(resolved)和rejected。可以链式调用then方法来处理异步操作的结果。
d.async/await是一种更为简洁、直观的异步编程方式,基于Promise实现。使用async声明函数,函数内部使用await关键字来等待异步操作完成。
// 示例代码
// 回调函数示例
function asynchronousOperation(callback) {
setTimeout(() => {
callback("Data received");
}, 1000);
}
function processData(data) {
console.log("Processing data: " + data);
}
asynchronousOperation(processData);
// Promise示例
function asynchronousOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
asynchronousOperation().then((data) => {
console.log("Processing data: " + data);
});
// async/await示例
async function asynchronousOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("Data received");
}, 1000);
});
}
(async function() {
const data = await asynchronousOperation();
console.log("Processing data: " + data);
})();
5.垃圾回收
a.JavaScript使用垃圾回收机制自动管理内存。当不再使用一个对象时,垃圾回收器会自动释放对象占用的内存空间。
b.JavaScript中的垃圾回收器采用的是基于标记和清除的算法,通过标记不再使用的对象,然后清除它们。
c.对象的引用计数也是一种垃圾回收机制,每个对象都有一个引用计数,当计数为0时,对象将被回收。
// 示例代码
function createObject() {
let obj = new Object();
return obj;
}
let obj1 = createObject(); // 创建一个新对象,obj1引用它
let obj2 = obj1; // obj2也引用同一个对象
obj1 = null; // obj1不再引用对象
obj2 = null; // obj2也不再引用对象,此时对象的引用计数为0,垃圾回收器可以回收对象
// 在其他地方仍然引用这个对象
console.log(obj2); // 输出:null,对象已经被回收
6.函数式编程
a.JavaScript支持函数式编程范式,函数是一等公民,可以作为变量、参数、返回值等进行操作。
b.函数式编程强调使用纯函数,即函数的输出仅由输入决定,没有副作用。这样可以减少代码的复杂性和错误概率。
c.在函数式编程中,常用的操作包括map、filter、reduce等,它们能够对数组进行转换和运算,产生新的数组或结果。
// 示例代码
// map示例:将数组中的每个元素进行平方运算
const numbers = [1, 2, 3, 4, 5];
const squaredNumbers = numbers.map((num) => num * num);
console.log(squaredNumbers); // 输出:[1, 4, 9, 16, 25]
// filter示例:过滤数组中的偶数
const evenNumbers = numbers.filter((num) => num % 2 === 0);
console.log(evenNumbers); // 输出:[2, 4]
// reduce示例:求和数组中的所有元素
const sum = numbers.reduce((acc, cur) => acc + cur, 0);
console.log(sum); // 输出:15
7.模块化
a.JavaScript的模块化能够将代码分割为多个独立的模块,提高代码的可维护性和可重用性。
b.ES6引入了原生的模块化支持,使用import和export关键字来导入和导出模块。
c.模块化还可以使用第三方库,如CommonJS、AMD等。
//示例代码
在math.js文件中定义一个模块:
// math.js
export function add(a, b) {
return a + b;
}
export function subtract(a, b) {
return a - b;
}
// 在index.js文件中导入并使用模块:
// index.js
import { add, subtract } from './math.js';
console.log(add(5, 2)); // 输出:7
console.log(subtract(5, 2)); // 输出:3
8.错误处理
a.JavaScript中的错误处理可以通过try/catch语句来实现。try代码块用于包裹可能抛出错误的代码,catch代码块用于捕获并处理错误。
b.错误对象包含了错误的信息,如错误的类型、错误的消息等。
c.在异步操作中,可以使用Promise的catch方法或async/await的try/catch语句来捕获错误。
//示例代码:
try {
// 可能抛出错误的代码
const result = someFunction(); // 假设someFunction函数不存在
console.log(result); // 不会执行,因为在上一行抛出了错误
} catch (error) {
// 错误处理代码
console.log("An error occurred: " + error); // 输出:An error occurred: ReferenceError: someFunction is not defined
}
// Promise错误处理示例
function asynchronousOperation() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject(new Error("Something went wrong"));
}, 1000);
});
}
asynchronousOperation()
.then((data) => {
console.log(data);
})
.catch((error) => {
console.log("An error occurred: " + error); // 输出:An error occurred: Error: Something went wrong
});
// async/await错误处理示例
async function main() {
try {
const result = await asynchronousOperation(); // 假设asynchronousOperation函数抛出了错误
console.log(result);
} catch (error) {
console.log("An error occurred: " + error); // 输出:An error occurred: Error: Something went wrong
}
}
main();
9.性能优化
a.在JavaScript中,可以通过一些技巧和最佳实践来提高代码的性能。
b.避免不必要的全局变量,减少作用域链的查找。
c.使用恰当的数据结构和算法,避免低效操作,如循环中的大量拼接字符串可以用数组或join方法代替。
d.频繁操作DOM会影响性能,可以优化为批量操作或使用文档片段。
e.在循环中尽量避免创建和销毁对象,可以重用对象或使用对象池。
// 示例代码:
// 避免频繁操作DOM的示例
const element = document.getElementById('myElement');
let content = '';
for (let i = 0; i < 1000; i++) {
content += 'New content ';
}
element.innerHTML = content; // 频繁操作DOM,性能较低
// 优化为批量操作DOM的示例
const fragment = document.createDocumentFragment();
for (let i = 0; i < 1000; i++) {
const p = document.createElement('p');
p.textContent = 'New content';
fragment.appendChild(p);
}
element.appendChild(fragment); // 批量操作DOM,性能更高
// 重用对象的示例
function calculateSum(a, b) {
// 重用数组对象,避免重复创建和销毁数组
const result = [];
for (let i = 0; i < a.length; i++) {
result[i] = a[i] + b[i];
}
return result;
}
const array1 = [1, 2, 3];
const array2 = [4, 5, 6];
console.log(calculateSum(array1, array2)); // 输出:[5, 7, 9]
10.结合HTML与CSS
当结合HTML和CSS应用JavaScript时,可以实现各种交互效果和动态功能。
a.创建一个按钮,点击按钮时改变元素的样式
当点击按钮时,元素的背景色会切换为黄色。
HTML:
<button id="myButton">Click me</button>
<div id="myElement">Hello, world!</div>
CSS:
#myElement {
font-size: 18px;
color: blue;
}
#myElement.highlight {
background-color: yellow;
}
JavaScript:
const button = document.getElementById('myButton');
const element = document.getElementById('myElement');
button.addEventListener('click', () => {
element.classList.toggle('highlight');
});
b.使用JavaScript加载远程数据并动态更新页面内容
这段代码使用函数从远程API加载数据,并在加载完成后将数据以JSON字符串的形式显示在页面上。
HTML:
<div id="dataContainer"></div>
CSS:
#dataContainer {
font-size: 18px;
}
JavaScript:
const dataContainer = document.getElementById('dataContainer');
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
dataContainer.textContent = JSON.stringify(data);
})
.catch(error => {
console.error(error);
dataContainer.textContent = 'Error occurred while loading data.';
});
c.创建一个图片轮播器
这段代码创建了一个简单的图片轮播器。每3秒钟自动切换到下一张图片,通过更改图片的opacity属性来实现淡入淡出效果。
HTML:
<div id="slider">
<img src="image1.jpg" alt="Image 1">
<img src="image2.jpg" alt="Image 2">
<img src="image3.jpg" alt="Image 3">
</div>
CSS:
#slider {
position: relative;
width: 500px;
height: 300px;
overflow: hidden;
}
#slider img {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
transition: opacity 0.5s ease-in-out;
}
.active {
opacity: 1;
}
JavaScript:
const slider = document.getElementById('slider');
const images = slider.getElementsByTagName('img');
let index = 0;
function changeSlide() {
images[index].classList.remove('active');
index = (index + 1) % images.length;
images[index].classList.add('active');
}
setInterval(changeSlide, 3000);
4.创建一个表单验证程序
这段代码创建了一个简单的表单验证程序。当点击提交按钮时,会检查输入框中的内容是否为空,如果有空字段,则显示错误消息;如果所有字段都填写了,则显示成功提交的消息。
HTML:
<form id="myForm">
<input type="text" id="nameInput" placeholder="Enter your name">
<input type="email" id="emailInput" placeholder="Enter your email">
<button type="submit">Submit</button>
</form>
<p id="message"></p>
CSS:
form input {
display: block;
margin-bottom: 10px;
}
#message {
font-weight: bold;
}
const form = document.getElementById('myForm');
const nameInput = document.getElementById('nameInput');
const emailInput = document.getElementById('emailInput');
const message = document.getElementById('message');
form.addEventListener('submit', (event) => {
event.preventDefault(); // 阻止表单的默认提交行为
const name = nameInput.value;
const email = emailInput.value;
if (name === '' || email === '') {
message.textContent = 'Please fill in all fields.';
message.style.color = 'red';
} else {
message.textContent = 'Form submitted successfully.';
message.style.color = 'green';
}
});