Skip to content

定义函数的方法有哪些?

查看详情
  • 函数声明
//ES5
function getSum () {}
function () {}//匿名函数
//ES6
() => {}
  • 函数表达式
javascript
//ES5
var getSum = function () {};
//ES6
let getSum = () => {};
  • 构造函数

ES5 的作用域和作用域链是什么?

查看详情
  • 作用域就是一个独立的地盘,让变量不会外泄,暴露出去。在 ES5 中只有全局域和函数域
  • 当查找变量的时候会先从当前上下文的变量对象中查找,如果没有找到就会从父级(词法层面的父级)执行上下文的变量对象查找,一直找到全局上下文的变量对象。这样由多个执行上下文的变量对象构成的一层层的关系就叫做作用域链

谈谈 JS 作用域的理解

查看详情
  • 在 ES6 之前,JS 中的作用域有两种,全局作用域和函数作用域。函数作用域中定义的变量只能在函数内部使用,外界无法访问。通过声明函数来创建函数作用域
  • 在 ES6 中新增了 let 和 const 命令,它们能够创建一个块级作用域,让变量只能在当前代码块内可见。

说出下列代码的执行结果

javascript
var num1 = 55;
var num2 = 66;

function fn(num, num1) {
  // 相当于先定义num, num1两个变量
  num = 100;
  num1 = 100;
  num2 = 100;
  console.log(num);
  console.log(num1);
  console.log(num2);
}
fn(num1, num2);
console.log(num1);
console.log(num2);
console.log(num);
查看详情
100
100
100
55
100
num is not defined

this 是什么?如何正确的判断 this?箭头函数的 this 是什么?

查看详情
  • 当前执行代码的环境对象
  • this 的绑定规则有四种:默认绑定,隐式绑定,显式绑定,new 绑定
    • new 绑定:函数是否在 new 中调用,如果是,那么 this 绑定的是新建创的对象(前提是构造函数中没有返回对象或者 function,否则 this 指向返回的对象或者 function)
    • 显式绑定:函数是否通过 call,apply 调用,或者使用了 bind,如果是那么 this 绑定的就是指定的对象。如果把 null 或者 undefined 作为 this 的绑定对象传入 call、apply 或者 bind,这些值的调用会被忽略,实际使用的是默认绑定
    • 隐式绑定:函数是否在某个上下文对象中调用,如果是 this 绑定的就是那个上下文对象。一般是 obj.foo()
    • 默认绑定:如果以上都不是那么使用默认绑定,严格模式下绑定到 undefined,否则绑定到全局对象
  • 箭头函数没有自己的 this,它的 this 继承于上一层代码块的 this

使用箭头函数应该注意什么?

查看详情
  • 箭头函数没有自己的 this,它的 this 继承于上一层代码块的 this,所以有时该慎用箭头函数
    • 对象的方法
    • 类属性语法和箭头函数的组合
javascript
const test = {
  name: 'test object',
  createAnonFunction: function () {
    return function () {
      console.log(this.name);
      console.log(arguments);
    };
  },
  createArrowFunction: function () {
    return () => {
      console.log(this.name);
      console.log(arguments);
    };
  },
};
const anon = test.createAnonFunction('hello', 'world');
const arrow = test.createArrowFunction('hello', 'world');
anon();
// undefined
// []
arrow();
// test object
// ['hello', 'world']

// 如果将此类作为原型进行子类化使用,既不利于测试同时还可能导致其他问题(React官方不推荐组件的继承写法,所以这样使用不会有大的问题)
class Counter {
  counter = 0;

  handleClick = () => {
    this.counter++;
  };
}
  • 不能使用 arguments 对象
  • 不能作为构造函数使用
  • 不能使用 yield 命令,因此箭头函数不能作为 Generator 函数

使用箭头函数的好处是什么?

查看详情
  • 箭头函数的语法更简洁
  • 箭头函数更易于阅读,可以明确知道当前 this 指向

ES6 中的普通函数和箭头函数有什么区别

查看详情
特性普通函数箭头函数
语法使用 function 关键字使用箭头 => 语法
this 绑定调用时确定定义时继承自外层作用域
call、apply、bind可以改变 this 指向不能改变 this 指向
arguments对象 可以访问没有自己的 arguments 对象,使用 ...args 替代
用作构造函数可以不能
作为对象的方法this 指向调用对象this 继承自外层作用域

词法词法作用域和 this 的区别

查看详情
  • 词法作用域: 也称为静态作用域(Static Scope),是指变量的作用域在代码的书写阶段就已经确定,而不是在运行时确定。在词法作用域中,变量的作用域由它们在源代码中的位置决定。JavaScript 使用词法作用域,这意味着一个函数在定义的时候就确定了它的作用域链,而不是在调用的时候确定。
  • this 是在调用时被绑定的,this 指向什么,完全取决于函数的调用位置

什么是闭包?闭包的作用是什么?缺点是什么?

查看详情
  • 闭包(Closure)是指在 JavaScript 中,当一个函数可以记住并访问它的词法作用域时,即使这个函数是在其词法作用域之外执行的。
  • 闭包的作用
    • 封装私有变量
    • 模仿块级作用域(ES5 中没有块级作用域)
    • 保持状态
  • 缺点:
    • 内存泄漏:闭包长时间持有对大对象的引用,可能会导致内存泄漏
    • 调试困难
    • 性能问题:过度使用闭包可能会导致性能问题,特别是在创建大量闭包时,每个闭包都会保存一份外部作用域的引用,这可能会增加内存消耗和垃圾回收的压力。
javascript
function makeAdder(x) {
  return function (y) {
    return x + y;
  };
}

var add5 = makeAdder(5);
var add10 = makeAdder(10);

console.log(add5(2)); // 7
console.log(add10(2)); // 12

call,apply 和 bind 有什么区别?

查看详情
  • call,apply 和 bind 的作用都是将函数的 this 绑定到指定的对象
  • call 和 apply 的功能相同,只是传参的方式不一样
    • fn.call(obj, arg1, arg2, ...)
    • fn.apply(obj, [argsArray])
  • call 和 apply 改变了函数的 this 后便执行该函数,而 bind 则是返回改变 this 之后的新函数,并不会执行该函数

什么是 IIFE?

查看详情
  • IIFE 是一个立即调用的函数表达式,它在创建后立即执行
  • 常用此模式来避免污染全局命名空间,因为 IIFE 中使用的所有变量在其作用域外都是不可见的。

节流和防抖

查看详情
  • 防抖:触发高频事件后的 n 秒内函数只会执行一次,如果在 n 秒内高频事件再次被触发,则重新计算时间。

应用场景:

  • 每次 resize/scroll 触发统计事件
  • 文本输入验证
javascript
function debounce(fn) {
  let timeout = null;
  return function () {
    clearTimeout(timeout);
    timeout = setTimeout(() => {
      fn.apply(this, arguments);
    }, 500);
  };
}

function fetchData() {
  console.log('防抖成功');
}

const input = document.getElementById('input');
input.addEventListener('input', debounce(fetchData()));
  • 节流:高频事件触发,n 秒只能执行一次

使用场景:

  • 计算鼠标的的移动距离
  • 搜索联想
  • 监听鼠标滚动事件判断是否到页面底部自动加载更多
javascript
function throttle(fn) {
  let canRun = true;
  return function () {
    if (!canRun) return;
    canRun = false;
    setTimeout(() => {
      fn.apply(this, arguments);
      canRun = true;
    });
  };
}

function fetchData() {
  console.log('节流成功');
}

window.addEventListener('resize', throttle(fetchData));

什么是函数柯里化?实现 sum(1)(2)(3)返回 1,2,3 之和

查看详情
  • 函数柯里化是把接受多个参数的函数变化成一个单一参数的(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术
javascript
function sum(a) {
  return function (b) {
    return function (c) {
      return a + b + c;
    };
  };
}
console.log(sum(1)(2)(3)); // 6

什么是高阶函数?常见的高阶函数有哪些?

查看详情
  • 高阶函数(Higher-Order Function)是指至少满足以下一个条件的函数:
    • 接受一个或多个函数作为参数。
    • 返回一个函数。
  • 常见的高阶函数
    • map
    • filter
    • find