前端面试必备:手写题深度解析与实战技巧(上篇)

一、类型检测的终极武器:typeof运算符详解

在JavaScript类型系统中,typeof是开发者最常用的基础运算符之一,其设计初衷是通过返回字符串标识变量的数据类型。但实际使用中,其特殊行为与历史遗留问题常成为面试官的考察重点。

1.1 基础类型检测实践

对于原始类型(Primitive Types),typeof能准确返回预期结果:

  1. // 数值类型
  2. typeof 42; // "number"
  3. typeof NaN; // "number" (特殊值仍属数值类型)
  4. typeof Infinity; // "number"
  5. // 字符串类型
  6. typeof 'hello'; // "string"
  7. typeof ``; // "string" (模板字符串)
  8. // 布尔类型
  9. typeof true; // "boolean"
  10. typeof false; // "boolean"
  11. // 特殊原始值
  12. typeof undefined; // "undefined"
  13. typeof Symbol('id'); // "symbol" (ES6新增)
  14. typeof 123n; // "bigint" (ES11新增)

1.2 引用类型检测陷阱

当检测对象类型时,typeof的表现开始出现异常:

  1. // 对象类型
  2. typeof {}; // "object"
  3. typeof []; // "object" (数组被误判)
  4. typeof /regex/; // "object" (正则表达式)
  5. typeof new Date(); // "object" (日期对象)
  6. // 函数类型(唯一例外)
  7. typeof function(){}; // "function"

关键注意事项:

  1. null检测悖论
    由于历史遗留问题,typeof null返回"object"。正确检测方式应使用严格相等:

    1. const val = null;
    2. console.log(val === null); // true
  2. 数组类型鉴别
    需使用Array.isArray()方法替代typeof

    1. Array.isArray([]); // true
    2. Array.isArray({}); // false
  3. 未声明变量安全检测
    对未定义的变量使用typeof不会抛出错误:

    1. typeof undefinedVar; // "undefined"
    2. // 对比直接访问会报错:
    3. console.log(undefinedVar); // ReferenceError

1.3 类型检测进阶方案

对于复杂场景,推荐组合使用多种检测方式:

  1. // 检测数组(兼容旧环境)
  2. function isArray(arr) {
  3. return Object.prototype.toString.call(arr) === '[object Array]';
  4. }
  5. // 类型检测工具函数
  6. function getType(val) {
  7. return Object.prototype.toString.call(val).slice(8, -1).toLowerCase();
  8. }
  9. getType([]); // "array"
  10. getType(/regex/); // "regexp"

二、继承机制的核心:原型链深度剖析

原型链(Prototype Chain)是JavaScript实现继承的核心机制,理解其工作原理对掌握面向对象编程至关重要。

2.1 原型链基础结构

每个JavaScript对象都包含一个隐藏属性[[Prototype]](可通过__proto__访问),指向其构造函数的prototype对象:

  1. function Person(name) {
  2. this.name = name;
  3. }
  4. const p = new Person('Alice');
  5. console.log(p.__proto__ === Person.prototype); // true

2.2 属性查找机制

当访问对象属性时,引擎会沿着原型链逐级向上查找:

  1. Person.prototype.species = 'Homo sapiens';
  2. console.log(p.species); // "Homo sapiens" (沿原型链查找)

原型链可视化:

  1. p.__proto__ Person.prototype
  2. Person.prototype.__proto__ Object.prototype
  3. Object.prototype.__proto__ null (原型链终点)

2.3 原型链关键特性

  1. 构造函数属性
    每个函数都有prototype属性,指向实例的原型对象:

    1. function Foo() {}
    2. console.log(Foo.prototype.constructor === Foo); // true
  2. 原型方法共享
    在原型上定义的方法可被所有实例共享:

    1. Person.prototype.greet = function() {
    2. console.log(`Hello, ${this.name}`);
    3. };
    4. p.greet(); // "Hello, Alice"
  3. 原型链修改影响
    动态修改原型会影响所有已有实例:

    1. function Animal() {}
    2. const cat = new Animal();
    3. Animal.prototype.sound = 'Meow';
    4. console.log(cat.sound); // "Meow" (即使定义在实例创建后)

2.4 原型链面试题解析

经典问题:如何判断一个对象是否属于某个构造函数的实例?

解决方案

  1. 使用instanceof运算符:

    1. console.log(p instanceof Person); // true
  2. 手动实现原型链检测:

    1. function customInstanceof(obj, constructor) {
    2. let proto = obj.__proto__;
    3. while (proto) {
    4. if (proto === constructor.prototype) return true;
    5. proto = proto.__proto__;
    6. }
    7. return false;
    8. }

进阶问题:如何实现继承?

ES5方案

  1. function Child() {}
  2. Child.prototype = new Parent(); // 原型链继承
  3. Child.prototype.constructor = Child; // 修复构造函数指向

ES6方案

  1. class Child extends Parent {
  2. constructor() {
  3. super(); // 必须调用父类构造函数
  4. }
  5. }

三、实战技巧总结

  1. 类型检测优先级
    typeof===Object.prototype.toString → 自定义检测函数

  2. 原型链优化建议

    • 避免在原型上添加过多属性,影响性能
    • 使用Object.create(null)创建无原型对象
    • 谨慎使用__proto__(已废弃,推荐Object.setPrototypeOf
  3. 面试应对策略

    • 准备类型检测的多种实现方案
    • 能手写原型链相关工具函数
    • 理解new操作符的内部实现机制

本文系统解析了前端面试中关于类型检测和原型链的核心考点,通过代码示例与原理剖析,帮助开发者建立完整的知识体系。掌握这些内容不仅能提升面试通过率,更能为实际开发中的类型安全与对象模型设计打下坚实基础。下篇将继续探讨闭包、作用域链等高级特性,敬请期待。