面试题

2025/2/21 ES6面试题

# 箭头函数和普通函数的区别

# 1. 定义方式

# 2. 参数处理

一个参数可省略 (),没参数默认为 ()

# 3. 函数体

返回一个简单的表达式可以省略 {}

# 4. this 指向

箭头函数没有自己的 this 对象, 而是从其作用域链的上一层继承 this。 箭头函数中 this 的指向在它被定义的时候就已经确定了。

构造函数内部的 this 指向当前对象的实例。而箭头函数的 this 的指向是在定义时确定的,不是在调用时确定

# 5. 没有 call, apply, bind

箭头函数的 this 指向不能通过 callapplybind 等方法改变。

# 6. 不可当做构造函数

不可以对箭头函数使用 new 命令。

箭头函数不能作为构造函数的原因主要有以下几点:

  • this 的绑定方式不同:箭头函数中的 this 是词法作用域,它会捕获定义时的 this 值。而普通函数中的 this 是动态的,取决于函数调用的方式。构造函数需要依赖 this 来初始化新对象,因此必须使用普通函数。

  • 没有 prototype 属性:箭头函数没有自己的 prototype 属性,而构造函数需要通过 prototype 来为实例添加属性和方法。由于箭头函数缺少这一特性,它无法正确地创建和初始化新对象。

  • new 关键字不适用:尝试用 new 操作符调用箭头函数会导致错误,因为箭头函数不是设计用来与 new 一起使用的。使用 new 调用普通函数会创建一个新的空对象,并将 this 绑定到这个新对象上,但箭头函数不会这样做。

let fun = () => {console.log("是一个箭头函数")}
new fun(); // TypeError: fun is not a constructor

new 一个构造函数的步骤

假设我们有一个构造函数 Person

function Person(name, age) {
  this.name = name;
  this.age = age;
}

Person.prototype.greet = function() {
  console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
};

const person1 = new Person('Alice', 30);


  1. 会创建一个新的对象;

    const obj = {};
    
  2. 设置原型链,也就是将新对象的 __proto__ 属性指向 prototype 属性, 这使得新对象可以继承构造函数原型上的属性和方法。

    obj.__proto__ = Person.prototype;
    
  3. 绑定 this 将构造函数内部的 this 绑定到这个新创建的对象

      let result = Person.call(obj, 'Alice', 30);
    
  4. 执行构造函数

    // 构造函数内部的代码执行,将 name 和 age 属性添加到 obj 上
    obj.name = 'Alice';
    obj.age = 30;
    
  5. 如果函数没有返回对象则返回 this

    if(typeof result == 'object'){
      return result;
    }else{
      return obj
    }
    

代码实现

function myNew(constructor, ...args) {
  if(typeof constructor !== 'function'){
    throw new TypeError('Constructor is not a function');
  }
  // 1. 创建一个空对象
  const obj = {};

  // 2. 将对象的 __proto__ 属性指向构造函数的 prototype 属性
  // obj.__proto__ = constructor.prototype;
  Object.setPrototypeOf(obj, constructor.prototype);

  // 3. 将构造函数内部的 this 绑定到新对象,并执行构造函数
  const result = constructor.call(obj, args);

  // 4. 如果构造函数返回一个对象,则返回该对象;否则返回新创建的对象
  return (result !== null && typeof result === 'object') ? result : obj;
}

# 7. 箭头函数没有 arguments

# Symbol

ES6 中的 Symbol 是一种新的基本数据类型 , 表示独一无二的值。 Symbol 的值是唯一且不可变的,可以用作对象属性的键,以防止属性名冲突。

# 用作对象属性名

使用 Symbol 定义的对象属性不会出现在普通的遍历中,如 for...infor...of 循环或 Object.keys()Object.getOwnPropertyNames() 中。它们可以通过 Object.getOwnPropertySymbols() 或者 Reflect.ownKeys() 获取。

# 内置 Symbol

  1. Symbol.iterator:为每个对象定义了默认的迭代器。该迭代器可以被 for...of 循环使用。
  2. Symbol.match:指定了匹配的是正则表达式而不是字符串, 还用于标识对象是否具有正则表达式的行为。
  3. Symbol.species:是个函数值属性,其被构造函数用以创建派生对象。
  4. Symbol.toPrimitive:用于将对象转换为基本值(如数字、字符串或布尔值)。

Symbol 可以用于自定义对象的迭代行为,如 Symbol.iterator,可以在任意对象上实现遍历数据能力。

let obj = {
  [Symbol.iterator]: function* () {
    yield 1;
    yield 2;
    yield 3;
  }
};

for (let value of obj) {
  console.log(value); // 分别输出 1, 2, 3
}

Symbol.match是一个特殊的符号(symbol),它定义了当一个对象被用作 String.prototype.match 的参数时的行为。简单来说,它决定了这个对象是否可以用于匹配字符串。

class ConditionalMatcher {
  constructor(private target: string) {
  }

  [Symbol.match](string: string) {
    console.log(`Matching string: ${ string }`);
    if (string.includes(this.target)) {
      return ['matched']; // 匹配成功
    } else {
      return null; // 匹配失败
    }
  }
}

const matcher = new ConditionalMatcher('hello');
const result1 = 'hello world'.match(matcher);
console.log(result1); // 输出: ["matched"]

const result2 = 'goodbye world'.match(matcher);
console.log(result2); // 输出: null

// 一个没有提供 Symbol.toPrimitive 属性的对象,参与运算时的输出结果。
const obj1 = {};
console.log(+obj1); // NaN
console.log(`${obj1}`); // "[object Object]"
console.log(obj1 + ""); // "[object Object]"

// 接下面声明一个对象,手动赋予了 Symbol.toPrimitive 属性,再来查看输出结果。
const obj2 = {
  [Symbol.toPrimitive](hint) {
    if (hint === "number") {
      return 10;
    }
    if (hint === "string") {
      return "hello";
    }
    return true;
  },
};
console.log(+obj2); // 10  — hint 参数值是 "number"
console.log(`${obj2}`); // "hello"   — hint 参数值是 "string"
console.log(obj2 + ""); // "true"    — hint 参数值是 "default"

+obj2 使用的是 number 作为 hint,因为一元加号运算符明确要求将对象转换为数值。 ${obj2} 使用的是 string 作为 hint,因为模板字符串插值明确要求将对象转换为字符串。 obj2 + "" 使用的是 default 作为 hint,默认情况下会先尝试 number,如果失败则尝试 string

# ES Module 和 Commonjs 的区别

相同点:两者都是 JavaScript 的模块化规范,都可以用来导入导出模块。

不同点:

  • ES Module (ESM)ES6 引入的标准化模块系统,支持动态导入,在编译时加载,可以异步加载模块。
  • CommonJS (CJS)出现在 ES6 之前,不支持动态导入,在运行时加载,采取的是同步加载模块的方式。

# 1. 导入导出

ESM 中,模块的导入和导出是通过 importexport 关键字来实现的。导出的是绑定的引用,模块外部能够实时观察到模块内部的变化。 在 CJS 中,模块的导入和导出是通过 requiremodule.exports/exports 来实现的。导出的是值的拷贝,当导入模块执行完毕,模块内部的变化不会影响这个值。

# 2. 加载机制

ES Modules在编译时加载, 采用异步加载模块方式,支持动态导入(按需加载导入模块),会更适合在浏览器环境中使用。

CommonJS 在运行时加载, 采用同步加载模块方式, 所以不支持动态导入; 同步加载是等模块加载完毕后才会执行代码。 这种加载方式通常在服务端使用, 因为服务端文件都在本地,不会引起明显的延迟问题, 但不适合客户端 (如浏览器) , 因为会导致浏览器在等待模块下载和解析期间暂停执行。

# 3. 运行环境

ES Modules 是 ES6 引入的官方标准化模块系统, 支持异步加载, 被现代浏览器广泛支持,Node.js 现在也支持 ES Modules

CommonJS 主要用于 Node.js 环境。

# 4. 变量作用域

ES Modules 的顶层 thisundefined,因为 ESM 模块在严格模式下执行,并且每个模块都有自己的顶层作用域,模块内部的变量默认不会被全局共享。

CommonJS 每个文件都是其模块的顶层作用域,因为 CJS 不会使用严格模式,它们的导入导出基于对象的引用,所以可以共享模块内部的变量。

# 5. 使用场景

  1. ES Modules 更适合现代 JavaScript 开发,因为 ESMJavaScript 官方的模块系统,现代浏览器原生支持,支持静态分析、异步加载、严格模式等特性,有利于前端代码拆分,以懒加载方式优化加载性能。
  2. ES Modules 更适合需要利用静态分析来进行 Tree Shaking(树摇优化)优化的项目:Tree Shaking 是一种只打包必要模块代码的方法, 依赖于 ESM 的静态结构可以移除未被使用的代码。因为 ESM 的导入在顶层,且不是动态生成的,所以 Tree Shaking 可以在编译时进行静态分析从而确定哪些模块和函数被实际使用,哪些没有。,从而移除未使用的代码。
  3. CommonJS 更适合 Node.js 服务端开发,模块加载是同步的,方便变量共享。
  4. 混合场景:当需要在同一个项目中混合使用两种模块系统时,可以通过设置 Webpack或其他模块打包工具来处理。

# 扩展运算符使用场景

扩展运算符()允许一个可迭代的表达式如数组或者字符串被展开为一系列的参数。

常见的使用场景:

  1. 数组操作:合并数组、复制数组、将数组作为参数传递给函数等。
  2. 函数参数:将不定数量的参数收集为一个数组,或者将数组解构为函数的参数。
  3. 对象操作:合并对象、创建新的对象副本。
  4. 字符串操作:将字符串转换为字符数组,方便遍历和操作每个字符。

# ES6 的 Proxy 可以实现什么功能?

可以用来创建虚拟化的对象,通过自定义基本操作(如属性查找、赋值、枚举、函数调用等)的行为来实现各种高级功能。主要功能包括:

  1. 拦截和定义对象的基本操作,比如属性访问、赋值、删除、函数调用等。
  2. 实现自定义的行为,比如数据验证、属性保护、自动填充默认值等。
  3. 实现观察者模式,可以轻松实现对象的监听和变化追踪。
  4. 创建虚拟属性和方法,使得代码更灵活和动态。
  5. 代理外部接口,可以将 API 调用封装为本地对象的属性访问操作。

# 解构使用场景

  1. 数组
  2. 对象
  3. 函数参数
  4. 交换变量
  5. 解构时变量重命名

# rest 参数

rest 参数是 ES6 中新增的一项语法, 用于表示不确定数量的参数,允许你将不定数量的参数收集为一个数组。

将传入的多个参数包装成一个参数,在参数列表中,rest 参数必须是最后一个参数,并且只能有一个。

  1. 对象,数组,函数参数将剩余部分用 rest 来接收
  2. 可以使代码更清晰
Last Updated: 2026/06/09/ 06:29:26