面试说出这些ES6新特性,让面试官对你耳目一新

68 阅读3分钟

引言

今天来分享的这几个ES6神技,保证让你在下一场面试中吊打竞争对手,让面试官眼睛一亮——这小子有点东西!

1. 解构赋值的精妙运用

基础用法大家都会,但你能回答出这些进阶问题吗?

// 面试常问题:交换变量值有哪些方法?
let a = 1, b = 2;

// 方法1:传统方式
let temp = a;
a = b;
b = temp;

// 方法2:ES6解构
[a, b] = [b, a];

// 方法3:算术运算(仅限于数字)
a = a + b;
b = a - b;
a = a - b;

// 方法4:位运算(仅限于整数)
a = a ^ b;
b = a ^ b;
a = a ^ b;

深层解构是展示技术深度的好机会:

// 复杂对象解构
const company = {
  name: "TechCorp",
  employees: [
    {
      id: 1,
      personal: {
        name: "John",
        address: {
          city: "New York",
          zipcode: "10001"
        }
      }
    }
  ]
};

// 一行代码获取嵌套数据
const { employees: [{ personal: { address: { city } } }] } = company;
console.log(city); // "New York"

// 函数参数解构与默认值结合
function createElement({ tag = 'div', content = '', className = '' } = {}) {
  return `<${tag} class="${className}">${content}</${tag}>`;
}

2. Promise及其背后的机制

不只是会用Promise,理解其原理才能让人眼前一亮:

// 手写简易Promise实现(面试加分项)
class MyPromise {
  constructor(executor) {
    this.state = 'pending';
    this.value = undefined;
    this.reason = undefined;
    this.onFulfilledCallbacks = [];
    this.onRejectedCallbacks = [];

    const resolve = (value) => {
      if (this.state === 'pending') {
        this.state = 'fulfilled';
        this.value = value;
        this.onFulfilledCallbacks.forEach(fn => fn());
      }
    };

    const reject = (reason) => {
      if (this.state === 'pending') {
        this.state = 'rejected';
        this.reason = reason;
        this.onRejectedCallbacks.forEach(fn => fn());
      }
    };

    try {
      executor(resolve, reject);
    } catch (err) {
      reject(err);
    }
  }

  then(onFulfilled, onRejected) {
    if (this.state === 'fulfilled') {
      onFulfilled(this.value);
    } else if (this.state === 'rejected') {
      onRejected(this.reason);
    } else {
      this.onFulfilledCallbacks.push(() => onFulfilled(this.value));
      this.onRejectedCallbacks.push(() => onRejected(this.reason));
    }
  }
}

Promise组合方法的实战应用:

// 同时处理多个异步操作,但需要所有结果(无论成功失败)
function allSettled(promises) {
  return Promise.all(promises.map(p => 
    p.then(value => ({ status: 'fulfilled', value }))
     .catch(reason => ({ status: 'rejected', reason }))
  ));
}

// 竞速应用:设置超时时间
function withTimeout(promise, timeout) {
  return Promise.race([
    promise,
    new Promise((_, reject) => 
      setTimeout(() => reject(new Error('Timeout')), timeout)
    )
  ]);
}

3. Proxy和Reflect的元编程能力

这是ES6中最强大但最少被深入理解的特性之一:

// 实现自动依赖跟踪(Vue3响应式原理)
function reactive(target) {
  const handler = {
    get(obj, key, receiver) {
      track(obj, key); // 依赖收集
      return Reflect.get(obj, key, receiver);
    },
    set(obj, key, value, receiver) {
      Reflect.set(obj, key, value, receiver);
      trigger(obj, key); // 触发更新
      return true;
    }
  };
  return new Proxy(target, handler);
}

// 实现高级校验器
function createValidator(obj, validations) {
  return new Proxy(obj, {
    set(target, key, value) {
      if (validations[key] && !validations[key](value)) {
        throw new Error(`Invalid value for ${key}`);
      }
      return Reflect.set(target, key, value);
    }
  });
}

const person = createValidator({}, {
  age: value => value >= 0 && value < 150,
  email: value => /@/.test(value)
});

person.age = 25; // 成功
person.age = 200; // 抛出错误

4. 迭代器和生成器的底层原理

不只是for...of循环,理解迭代协议:

// 实现可迭代对象
class Range {
  constructor(start, end, step = 1) {
    this.start = start;
    this.end = end;
    this.step = step;
  }
  
  [Symbol.iterator]() {
    let current = this.start;
    return {
      next: () => {
        if (current <= this.end) {
          const value = current;
          current += this.step;
          return { value, done: false };
        }
        return { done: true };
      }
    };
  }
}

// 生成器控制异步流程
async function* asyncGenerator() {
  const urls = ['/api1', '/api2', '/api3'];
  
  for (const url of urls) {
    try {
      const response = await fetch(url);
      yield await response.json();
    } catch (error) {
      yield { error: error.message };
    }
  }
}

// 使用for await...of处理
(async () => {
  for await (const data of asyncGenerator()) {
    console.log(data);
  }
})();

5. 模块系统的深入理解

ES6模块与CommonJS的区别是常见面试题:

// ES6模块是静态的,支持tree-shaking
export const apiKey = '12345'; // 可以被tree-shaking
export default function() { console.log('default'); }

// 动态导入的应用
async function loadModule(condition) {
  if (condition) {
    const module = await import('./moduleA.js');
    return module.default;
  } else {
    const module = await import('./moduleB.js');
    return module.default;
  }
}

// 循环引用的处理
// ES6模块处理循环引用比CommonJS更合理
// a.js
import { b } from './b.js';
export const a = 'a';

// b.js
import { a } from './a.js';
export const b = 'b';

// 不会报错,但值为undefined,需要设计时避免

6. 符号(Symbol)的实际应用场景

不只是唯一值,还有这些实用场景:

// 定义对象元数据
const USER_LEVEL = Symbol('userLevel');
const user = {
  name: 'John',
  [USER_LEVEL]: 'admin' // 不会出现在JSON.stringify、Object.keys中
};

// 实现自定义类型检测
class MyArray extends Array {
  static [Symbol.hasInstance](instance) {
    return Array.isArray(instance) && instance.hasOwnProperty('isMyArray');
  }
}

// 替代枚举值
const LOG_LEVEL = {
  DEBUG: Symbol('debug'),
  INFO: Symbol('info'),
  WARN: Symbol('warn'),
  ERROR: Symbol('error')
};

面试实战技巧

  1. 不仅说出是什么,还要解释为什么:当被问到箭头函数时,不要只说"没有自己的this",而要解释设计初衷是为了解决函数嵌套中的this问题
  2. 结合使用场景:提到Proxy时,可以关联到Vue3的响应式原理或表单验证的实际应用
  3. 指出注意事项:比如箭头函数不能用作构造函数,没有arguments对象,这些细节能展现你的全面性
  4. 性能考量:提到扩展运算符时,可以讨论其在大型数组上的性能问题替代方案