JS基础

38 阅读4分钟

变量声明: varlet 与 const

image.png

作用域与变量提升

// 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 指向

四大绑定规则

  1. 默认绑定: 独立函数调用,非严格模式下指向全局对象 (window),严格模式下为 undefined

  2. 隐式绑定: 作为对象方法调用,this 指向该对象。

  3. 显式绑定: 通过 .call(), .apply(), .bind() 强制指定 this

  4. new 绑定: 通过 new 调用构造函数,this 指向新创建的实例。

原型与原型链

这是JavaScript实现继承和属性共享的核心机制。

  • prototype: 每个函数都拥有的属性,指向一个对象,用于存放实例需要共享的方法和属性。

  • __proto__ : 每个对象都拥有的属性,指向其构造函数的 prototype

  • 原型链: 当访问一个对象的属性时,引擎会先在对象自身查找,若未找到,则沿着 __proto__ 链向上查找,直至链的顶端 null

image.png

image.png

作用域与闭包

作用域

定义了变量和函数的可访问范围。

  • 全局作用域: 在代码任何地方都可访问。
  • 函数作用域: 变量在声明它们的函数内部及子函数内部可访问。
  • 块级作用域 (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

image.png

高阶函数

一个函数如果接收函数作为参数,或将函数作为返回值,那么它就是高阶函数。

  • 常见内置高阶函数Array.prototype.mapfilterreduce
  • 自定义高阶函数 (函数柯里化 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
}