变量声明: var, let 与 const
作用域与变量提升
// var 的变量提升
console.log(foo); // undefined
var foo = 'Hello';
// let 的暂时性死区
// console.log(bar); // Uncaught ReferenceError: Cannot access 'bar' before initialization
let bar = 'World';
const 的不变性
const 的“不变”是指针(引用)的不变,而不是其指向内容的不变。
箭头函数 (ES6)
const subtract = (a, b) => a - b;
特点:语法简洁,且其 this 值由所在区域外层决定,而不是由调用方式决定。
this 指向
四大绑定规则
-
默认绑定: 独立函数调用,非严格模式下指向全局对象 (
window),严格模式下为undefined。 -
隐式绑定: 作为对象方法调用,
this指向该对象。 -
显式绑定: 通过
.call(),.apply(),.bind()强制指定this。 -
new 绑定: 通过
new调用构造函数,this指向新创建的实例。
原型与原型链
这是JavaScript实现继承和属性共享的核心机制。
-
prototype: 每个函数都拥有的属性,指向一个对象,用于存放实例需要共享的方法和属性。 -
__proto__: 每个对象都拥有的属性,指向其构造函数的prototype。 -
原型链: 当访问一个对象的属性时,引擎会先在对象自身查找,若未找到,则沿着
__proto__链向上查找,直至链的顶端null。
作用域与闭包
作用域
定义了变量和函数的可访问范围。
- 全局作用域: 在代码任何地方都可访问。
- 函数作用域: 变量在声明它们的函数内部及子函数内部可访问。
- 块级作用域 (ES6) : 由
let和const声明的变量,只在{}代码块内可访问。
闭包
指一个函数能够访问并操作其词法作用域(定义时的作用域)中的变量,即使该函数在其词法作用域之外被执行。
function createCounter() {
let count = 0; // 私有变量,外部无法直接访问
return {
increment: function() {
count++;
},
getValue: function() {
return count;
}
};
}
const counter = createCounter();
counter.increment();
counter.increment();
console.log(counter.getValue()); // 2
// console.log(counter.count); // undefined, 无法直接访问
args
高阶函数
一个函数如果接收函数作为参数,或将函数作为返回值,那么它就是高阶函数。
- 常见内置高阶函数:
Array.prototype.map,filter,reduce。 - 自定义高阶函数 (函数柯里化 Currying 示例) :
// 一个简单的加法函数
function add(x, y) {
return x + y;
}
// 柯里化转换器
function curry(fn) {
return function curried(...args) {
if (args.length >= fn.length) {
return fn.apply(this, args);
} else {
return function(...args2) {
return curried.apply(this, args.concat(args2));
}
}
};
}
const curriedAdd = curry(add);
const addFive = curriedAdd(5); // 返回一个新函数,等待接收第二个参数
console.log(addFive(3)); // 8
console.log(curriedAdd(5)(3)); // 8
# call、apply、bind 作用和区别
call、apply、bind 都是函数 Function 原型上的方法,三者的功能都是用来改变函数中的 this 指向
call
const Person1 = {
fullName: function (country, city) {
return this.firstName + this.lastName + " " + country + " " + city
}
}
const Person2 = {
firstName: "张",
lastName: "三",
}
Person1.fullName.call(Person2, '中国', '河南') // 张三 中国 河南
apply
const person = {
fullName: function (country, city) {
return this.firstName + this.lastName + " " + country + " " + city
}
}
const newPerson = {
firstName: "壮",
lastName: "志国",
}
person.fullName.apply(newPerson, ['中国', '河南']) // 壮志国 中国 河南
bind
常用在react中的dom调用函数
const person = {
fullName: function (country, city) {
return this.firstName + this.lastName + " " + country + " " + city
}
}
const newPerson = {
firstName: "壮",
lastName: "志国",
}
// 打印出fullName函数
person.fullName.bind(newPerson, '中国', '河南')() // 壮志国 中国 河南
防抖 (Debounce)
防抖的核心思想是:在事件被触发n秒后再执行回调,如果在这n秒内事件又被触发,则重新计时。这适用于只需响应用户最终操作状态的场景,如输入框搜索联想。
/**
* 防抖函数
* @param {Function} func - 需要执行的回调函数
* @param {number} delay - 延迟时间 (ms)
* @returns {Function} - 经过防抖处理的新函数
*/
function debounce(func, delay) {
let timerId; // 通过闭包维持 timerId
return function (...args) {
// 保存函数调用时的 this 上下文和参数
const context = this;
// 如果存在定时器,则清除它,实现重新计时
clearTimeout(timerId);
// 设置新的定时器
timerId = setTimeout(() => {
// 使用 apply 将保存的上下文和参数传递给原函数
func.apply(context, args);
}, delay);
};
}
节流 (Throttle)
节流的核心思想是:在规定时间内,事件处理函数最多执行一次。这适用于需要以固定频率响应的场景,如scroll滚动加载、resize窗口调整。
//throttle.js
/**
* @param {*} fn 要执行的函数
* @param {*} interval 时间间隔
* @returns
*/
function throttle(fn, interval) {
let lastTime = 0
const _throttle = function (...args) {
const nowTime = new Date().getTime()
const intervalTime = nowTime - lastTime
if (intervalTime >= interval) {
fn.apply(this, args)
lastTime = nowTime
}
}
return _throttle
}