javascript个人笔记 闭包/this/解构赋值/模板字符串/模块化
闭包
函数能够访问并记住其词法作用域(lexical scope)外的变量
用于封装私有变量,模块化
function outer() {let count = 0; // 外层函数的变量function inner() {count++; // 内层函数引用外层变量console.log(count);}return inner; // 返回内层函数
}const counter = outer();
counter(); // 输出 1
counter(); // 输出 2(count 被“记住”了)
outer的inner函数引用了外部的counter,outer函数执行完毕,count仍然会被保存
如果闭包中引用的大对象不再需要,需手动解除引用(如 null)(因为其有内存泄露风险
this
this 是一个 动态绑定 的上下文对象,它的值 取决于函数被调用的方式,而不是函数定义的位置(可以理解成每次调用函数,系统会自动帮助你传入一个this作为参数)
- 默认绑定(直接使用函数)
this 指向:全局对象(浏览器中为 window,Node.js 中为 global)。严格模式(‘use strict’)下为 undefined
function showThis() {console.log(this);
}showThis();
// 非严格模式:window(浏览器)
// 严格模式:undefined
- 隐式绑定(作为对象方法调用)
const obj = {name: "Alice",sayHi() {console.log(`Hi, ${this.name}!`); // this就是obj本身}
};obj.sayHi(); // 输出 "Hi, Alice!"
- this 指向:call/apply/bind 的第一个参数。
区别:
call:立即调用,参数逐个传递。
apply:立即调用,参数以数组传递。
bind:返回一个新函数,不立即调用。
apply的理解
❌ 错误理解:apply 的第一个参数(this 指向)会被当作数组处理。
✅ 正确理解:
第一个参数:永远是 this 的指向(可以是任意类型,和数组无关)。
第二个参数:是一个数组(或类数组),数组中的元素会被“展开”作为函数的参数
function greet() {console.log(`Hello, ${this.name}!`);
}const user = { name: "Bob" };greet.call(user); // 输出 "Hello, Bob!"
greet.apply(user); // 同上
const boundFunc = greet.bind(user);
boundFunc(); // 输出 "Hello, Bob!"
4.new 绑定(构造函数调用)
this 指向:新创建的实例对象。
场景:使用 new 调用构造函数。
function Person(name) {this.name = name; // this 指向新实例
}const alice = new Person("Alice");
console.log(alice.name); // 输出 "Alice"
- 箭头函数(无自己的 this)
- this 指向:继承外层作用域的 this(词法作用域)
const obj = {name: "Alice",sayHi: function() {setTimeout(() => {console.log(`Hi, ${this.name}!`); // this 继承自 sayHi(指向 obj)}, 100);}
};obj.sayHi(); // 输出 "Hi, Alice!"
this指向陷阱
//闭包
const obj = {name: "Alice",outer() {function inner() {console.log(this.name); // 直接调用}inner(); // 直接调用}
};obj.outer(); // 输出 undefined//回调函数
const obj = {name: "Alice",fetchData(callback) {setTimeout(callback, 100); // 🚨 问题出在这里, 等价于直接调用函数},logName() {console.log(this.name);}
};obj.fetchData(obj.logName); // 输出 undefined// 伪代码:模拟 setTimeout 的行为
function setTimeout(callback, delay) {// 等待 delay 毫秒...callback(); // 🚨 这里直接调用,没有 obj 上下文!
}
解构赋值(Destructuring)
从数组或对象中提取值,并赋值给变量的一种简洁语法
const arr = [1, 2, 3];
const [a, b, c] = arr; // a=1, b=2, c=3const user = { name: "Bob", age: 30 };
const { name, age } = user; // name="Bob", age=30const { role = "guest" } = user; // 如果 user.role 不存在,role="guest"
模板字符串
反引号(`)包裹字符串,支持多行文本和嵌入表达式(${expression})
const name = "Alice";
// 单行字符串
const greeting = `Hello, ${name}!`; // "Hello, Alice!"// 表达式计算
const sum = `1 + 2 = ${1 + 2}`; // "1 + 2 = 3"
模块化
将代码分割成多个文件,通过 import/export 管理依赖关系。
//假定这个文件叫math.js
export const PI = 3.14;
export function sum(a, b) { return a + b; }// 默认导出(每个模块仅一个)
export default class User { /* ... */ }
// 导入命名导出
import { PI, sum } from './math.js';// 导入默认导出
import User from './User.js';// 动态导入(按需加载)
const module = await import('./module.js');