JavaScript 类型判断:instanceof 与 constructor 原理深度解析

JavaScript 类型判断:instanceof 与 constructor 原理深度解析

本文档深入剖析 JavaScript 中 instanceofconstructor 两种类型判断方式的工作原理、底层机制、边界情况以及最佳实践。


一、前置知识:原型与原型链

在深入理解 instanceofconstructor 之前,需要先掌握 JavaScript 的原型机制。

1.1 什么是原型?

每个 JavaScript 对象都有一个与之关联的原型对象(prototype),通过原型,对象可以访问原型上的属性和方法。

javascript 复制代码
// 每个对象都有 __proto__ 属性指向其原型
let obj = {};
console.log(obj.__proto__);  // {} 或 null(取决于创建方式)

// 数组的原型
let arr = [1, 2, 3];
console.log(arr.__proto__);  // Array.prototype

1.2 原型链

当访问对象的某个属性时,如果对象自身没有该属性,JavaScript 会沿着 __proto__ 向上查找,直到找到为止或到达 null。这条由 __proto__ 串联起来的链条就是原型链

javascript 复制代码
┌─────────────┐     __proto__     ┌──────────────────┐     __proto__     ┌──────────────────┐     __proto__     ┌─────┐
│   [] 数组    │ ───────────────→ │ Array.prototype   │ ───────────────→ │ Object.prototype  │ ───────────────→ │ null │
│ (实例对象)   │                   │ push, pop, map... │                   │ toString, hasOwn..│                  │      │
└─────────────┘                   └──────────────────┘                   └──────────────────┘                  └─────┘

1.3 构造函数与原型的关系

javascript 复制代码
function Person(name) {
    this.name = name;
}

// 添加方法到原型
Person.prototype.sayHi = function() {
    console.log(`你好,我是${this.name}`);
};

const p = new Person("张三");

关系图:

javascript 复制代码
┌────────────────────┐
│   Person 构造函数    │
│                    │
│  ┌──────────────┐  │
│  │  prototype   │──┼──→ ┌─────────────────────────┐
│  └──────────────┘  │    │  Person.prototype       │
│         │          │    │  ┌───────────────────┐  │
│         ▼          │    │  │ constructor: Person│  │ ← 默认指向构造函数本身
│    new Person()    │    │  │ sayHi: function   │  │
│         │          │    │  └───────────────────┘  │
│         ▼          │    └─────────────────────────┘
│   ┌───────────┐    │              ▲
│   │    p      │    │              │
│   │ name:"张三"│    │              │
│   │__proto__: │────┼──────────────┘
│   └───────────┘    │
└────────────────────┘

二、instanceof 运算符

2.1 基本用法

instanceof 是一个二元运算符,用于检测构造函数的 prototype 属性是否存在于某个对象的原型链上。

javascript 复制代码
obj instanceof Constructor

返回值truefalse

javascript 复制代码
[] instanceof Array    // true
{} instanceof Object   // true
new Date() instanceof Date  // true
/regex/ instanceof RegExp   // true

2.2 核心原理:原型链查找

instanceof 的本质是检查构造函数的 prototype 是否位于对象的原型链上

javascript 复制代码
// 以下两行代码是等价的:
[] instanceof Array

// 等价于:
Array.prototype === [].__proto__  // true

更复杂的例子:

javascript 复制代码
class Animal {}
class Dog extends Animal {}

const dog = new Dog();

dog instanceof Dog     // true  ← Dog.prototype 在原型链上
dog instanceof Animal  // true  ← Animal.prototype 也在原型链上(继承)
dog instanceof Object  // true  ← Object.prototype 同样在原型链上

2.3 内部执行流程(手写实现)

我们可以用以下代码模拟 instanceof 的内部逻辑:

javascript 复制代码
/**
 * 手写 instanceof 实现
 * @param {Object} obj - 被检测的对象
 * @param {Function} Constructor - 构造函数
 * @returns {Boolean}
 */
function myInstanceof(obj, Constructor) {
    // 1. 获取构造函数的 prototype 属性
    let proto = Constructor.prototype;
    
    // 2. 获取对象的原型(__proto__)
    let p = obj.__proto__;
    
    // 3. 沿着原型链向上遍历查找
    while (p !== null) {
        if (p === proto) {
            return true;
        }
        p = p.__proto__;
    }
    
    return false;
}

// 测试
console.log(myInstanceof([], Array));     // true
console.log(myInstanceof({}, Object));    // true
console.log(myInstanceof(123, Number));   // false

更严谨的实现(考虑 null 和非对象类型)

javascript 复制代码
function myInstanceof(obj, Constructor) {
    // 处理非对象类型和 null
    if (obj === null || typeof obj !== 'object') {
        return false;
    }
    
    let proto = Constructor.prototype;
    let p = Object.getPrototypeOf(obj);  // 使用标准 API
    
    while (p !== null) {
        if (p === proto) {
            return true;
        }
        p = Object.getPrototypeOf(p);
    }
    
    return false;
}

2.4 图解原型链查找过程

[1, 2, 3] instanceof Array 为例:

javascript 复制代码
步骤 1: 获取 Array.prototype
        ┌─────────────────────────┐
        │  Array.prototype        │
        │  ┌───────────────────┐  │
        │  │ push, pop, map... │  │
        │  └───────────────────┘  │
        └─────────────────────────┘
                    ▲
                    │ 比较
                    │
步骤 2: 从 [1,2,3] 开始沿原型链查找
                    
        ┌─────────────┐     __proto__     ┌──────────────────┐     __proto__     ┌──────────────────┐     __proto__     ┌─────┐
        │  [1, 2, 3]  │ ───────────────→ │ Array.prototype   │ ───────────────→ │ Object.prototype  │ ───────────────→ │ null │
        │  (起点)     │                   │  ✅ 匹配成功!     │                   │                   │                  │      │
        └─────────────┘                   └──────────────────┘                   └──────────────────┘                  └─────┘
            
结果: [1, 2, 3] instanceof Array → true

2.5 特殊情况分析

2.5.1 基本类型的处理
javascript 复制代码
// ❌ 原始值类型无法直接使用 instanceof
"hello" instanceof String    // false
123 instanceof Number        // false
true instanceof Boolean      // false

// ✅ 但可以使用包装对象
new String("hello") instanceof String    // true
new Number(123) instanceof Number        // true
new Boolean(true) instanceof Boolean     // true

原因 :原始值不是对象,没有原型链。而 StringNumberBoolean 是构造函数,其实例是包装对象。

2.5.2 跨 iframe / window 失效问题
javascript 复制代码
// 假设有一个 iframe
const iframe = document.getElementById('myIframe');
const iframeWindow = iframe.contentWindow;

const arr = [];

// ❌ 不同 window 下的构造函数是不同的引用
arr instanceof iframeWindow.Array   // false!

// 原因:
// iframeWindow.Array !== window.Array
// 虽然它们的名字相同,但是两个不同的函数引用

解决方案 :使用 Object.prototype.toString.call()

javascript 复制代码
// ✅ 推荐方式
Object.prototype.toString.call(arr) === '[object Array]'  // true
2.5.3 自定义构造函数
javascript 复制代码
function Car(brand) {
    this.brand = brand;
}

Car.prototype.drive = function() {
    console.log(`${this.brand} 正在行驶`);
};

const myCar = new Car("Tesla");

myCar instanceof Car    // true
myCar instanceof Object // true
myCar instanceof Array  // false

2.6 instanceof 的缺陷

缺陷 说明 示例
不能检测基本类型 原始值没有原型链 "hello" instanceof Stringfalse
跨 iframe 失效 不同 window 下构造函数引用不同 [] instanceof iframe.Arrayfalse
只检测原型链 无法检测对象的实际"类型"意图 难以区分普通对象和特定用途对象

三、constructor 属性

3.1 constructor 的来源

每个构造函数在创建时,JavaScript 引擎会自动在其 prototype 上设置一个 constructor 属性,指向构造函数本身。

javascript 复制代码
function Person(name) {
    this.name = name;
}

// 自动生成的默认行为
Person.prototype.constructor === Person  // true

图解

yaml 复制代码
┌────────────────────┐         ┌─────────────────────────┐
│   Person           │         │  Person.prototype       │
│   (构造函数)        │◄────────┤                         │
│                    │  引用    │  constructor: Person    │ ← 自动设置
│  prototype: ───────┼───────► │  (其他属性/方法...)      │
└────────────────────┘         └─────────────────────────┘

内置类型的 constructor

javascript 复制代码
[].constructor === Array                // true
{}.constructor === Object               // true
"hello".constructor === String          // true
(123).constructor === Number            // true
true.constructor === Boolean            // true
new Date().constructor === Date         // true

3.2 利用 constructor 判断类型

javascript 复制代码
function getTypeByConstructor(value) {
    if (value === null) return "null";
    if (typeof value !== "object") return typeof value;
    return value.constructor.name;
}

getTypeByConstructor([])        // "Array"
getTypeByConstructor({})        // "Object"
getTypeByConstructor("hello")   // "String"
getTypeByConstructor(123)       // "number"
getTypeByConstructor(new Date())// "Date"

3.3 constructor 被覆盖的问题

问题一:直接替换 prototype

javascript 复制代码
function Animal(name) {
    this.name = name;
}

const dog = new Animal("旺财");

// ❌ 直接替换 prototype,constructor 丢失
Animal.prototype = {
    bark() {
        console.log("汪汪!");
    }
};

const dog2 = new Animal("大黄");
dog2.constructor === Animal  // false!变成了 undefined

图解问题

yaml 复制代码
替换前:
┌─────────────────┐         ┌─────────────────────────┐
│     Animal      │◄────────┤  Animal.prototype       │
│                 │         │  constructor: Animal ✓  │
└─────────────────┘         └─────────────────────────┘

替换后:
┌─────────────────┐         ┌─────────────────────────┐
│     Animal      │         │  新的 prototype          │
│                 │         │  bark: function         │
│  prototype: ────┼───────► │  constructor: undefined │ ← 丢失了!
└─────────────────┘         └─────────────────────────┘

问题二:Object.create() 创建的对象

javascript 复制代码
const customProto = {
    customMethod() {}
};

const obj = Object.create(customProto);
obj.constructor === Object  // false!因为 Object.prototype 不在原型链上

问题三:修改实例的 proto

javascript 复制代码
const arr = [1, 2, 3];

// 修改原型
arr.__proto__ = { foo: () => {} };

arr.constructor === Array  // false!

3.4 正确维护 constructor 的方式

方式一:手动指定 constructor
javascript 复制代码
function Animal(name) {
    this.name = name;
}

// ✅ 手动保持 constructor 指向
Animal.prototype = {
    constructor: Animal,  // 显式指定
    speak() {
        console.log(`${this.name} 发出声音`);
    }
};
方式二:使用 Object.setPrototypeOf()
javascript 复制代码
function Animal(name) {
    this.name = name;
}

Animal.prototype.speak = function() {
    console.log(`${this.name} 发出声音`);
};

const dog = new Animal("旺财");

// ✅ 安全地修改原型
Object.setPrototypeOf(dog, Array.prototype);
dog.constructor === Array  // true
方式三:使用 class 语法(推荐)
javascript 复制代码
class Animal {
    constructor(name) {
        this.name = name;
    }
    
    speak() {
        console.log(`${this.name} 发出声音`);
    }
}

// class 会自动维护 constructor
const dog = new Animal("旺财");
dog.constructor === Animal  // true

四、两者对比与总结

4.1 核心区别

特性 instanceof constructor
判断依据 构造函数的 prototype 是否在原型链上 原型上的 constructor 属性指向哪个函数
查找方向 从对象向原型链上方查找 直接从 __proto__ 读取
能否检测基本类型 ❌ 不能 ❌ 不能(需先包装)
跨 iframe 支持 ❌ 失效 ⚠️ 取决于 prototype 是否改变
继承检测 ✅ 支持多层继承 ⚠️ 只返回最近的构造函数
安全性 较安全,不易被篡改 易被覆盖导致误判
性能 略慢(需遍历原型链) 略快(直接读取属性)

4.2 使用场景建议

javascript 复制代码
// ✅ 推荐使用 instanceof 的场景
// 1. 检测数组
if (arr instanceof Array) { ... }

// 2. 检测日期
if (date instanceof Date) { ... }

// 3. 检测正则表达式
if (pattern instanceof RegExp) { ... }

// 4. 检测自定义类的实例
if (obj instanceof MyCustomClass) { ... }


// ✅ 推荐使用 constructor 的场景
// 1. 需要知道具体类型名称
const typeName = obj.constructor.name;

// 2. 快速判断且确定 prototype 未被修改
if (obj.constructor === Object) { ... }


// ✅ 最推荐的通用方案
Object.prototype.toString.call(obj)

五、更可靠的类型判断方案

5.1 typeof 运算符

typeof 是最简单的类型判断方式,但有明显局限。

javascript 复制代码
typeof 123        // "number"
typeof "hello"    // "string"
typeof true       // "boolean"
typeof undefined  // "undefined"
typeof Symbol()   // "symbol"
typeof 123n       // "bigint"
typeof {}         // "object"
typeof []         // "object"  ← 局限:无法区分数组
typeof null       // "object"  ← 历史遗留 bug
typeof function(){} // "function"

局限性

  • 无法区分 null 和其他对象类型
  • 无法区分数组、日期、正则等引用类型
  • 所有对象都返回 "object"

5.2 Object.prototype.toString.call() (推荐)

这是最可靠的类型判断方法,能准确识别所有内置类型。

javascript 复制代码
Object.prototype.toString.call(value)

返回值格式[object Type]

javascript 复制代码
// 基本类型
Object.prototype.toString.call(null)       // "[object Null]"
Object.prototype.toString.call(undefined)  // "[object Undefined]"
Object.prototype.toString.call(true)       // "[object Boolean]"
Object.prototype.toString.call(false)      // "[object Boolean]"
Object.prototype.toString.call(123)        // "[object Number]"
Object.prototype.toString.call(123n)       // "[object BigInt]"
Object.prototype.toString.call("hello")    // "[object String]"
Object.prototype.toString.call(Symbol())   // "[object Symbol]"

// 引用类型
Object.prototype.toString.call({})         // "[object Object]"
Object.prototype.toString.call([])         // "[object Array]"
Object.prototype.toString.call(new Date()) // "[object Date]"
Object.prototype.toString.call(/regex/)    // "[object RegExp]"
Object.prototype.toString.call(new Error())// "[object Error]"
Object.prototype.toString.call(new Map())  // "[object Map]"
Object.prototype.toString.call(new Set())  // "[object Set]"
Object.prototype.toString.call(new WeakMap()) // "[object WeakMap]"
Object.prototype.toString.call(new WeakSet()) // "[object WeakSet]"
Object.prototype.toString.call(new Promise(() => {})) // "[object Promise]"

// 其他
Object.prototype.toString.call(function(){})  // "[object Function]"
Object.prototype.toString.call(class {})      // "[object Class]"
Object.prototype.toString.call(document)      // "[object HTMLDocument]"
Object.prototype.toString.call(window)        // "[object Window]"

原理

toString() 方法内部通过 [[Class]] 内部属性来确定类型标签。这个标签在对象创建时就由 JavaScript 引擎设定,无法通过普通手段修改。

javascript 复制代码
// [[Class]] 是内部属性,无法直接访问
// 但可以通过 toString 间接获取
Object.prototype.toString.call({})  // "[object Object]"
                                     //      ↑↑↑↑↑↑
                                     //    这就是 [[Class]] 的值

5.3 Array.isArray()

专门用于判断数组的方法,比 instanceof 更可靠。

javascript 复制代码
Array.isArray([])           // true
Array.isArray({})           // false
Array.isArray("hello")      // false
Array.isArray(arguments)    // false(类数组不是真数组)

为什么比 instanceof 更好?

javascript 复制代码
// 跨 iframe 场景
const iframe = document.getElementById('myFrame');
const iframeWindow = iframe.contentWindow;

const arr = [];

// ❌ instanceof 失效
arr instanceof iframeWindow.Array   // false

// ✅ isArray 仍然有效
Array.isArray(arr)  // true

5.4 封装通用类型判断函数

javascript 复制代码
/**
 * 获取值的精确类型
 * @param {*} value - 要判断的值
 * @returns {string} 类型名称(小写)
 */
function getType(value) {
    // 处理 null
    if (value === null) {
        return "null";
    }
    
    // 处理非对象类型
    const type = typeof value;
    if (type !== "object") {
        return type;
    }
    
    // 处理对象类型
    return Object.prototype.toString.call(value)
        .slice(8, -1)  // 去掉 "[object " 和 "]"
        .toLowerCase();
}

// 测试
console.log(getType(null));        // "null"
console.log(getType(undefined));   // "undefined"
console.log(getType(123));         // "number"
console.log(getType("hello"));     // "string"
console.log(getType(true));        // "boolean"
console.log(getType([]));          // "array"
console.log(getType({}));          // "object"
console.log(getType(new Date()));  // "date"
console.log(getType(/regex/));     // "regexp"
console.log(getType(new Map()));   // "map"
console.log(getType(new Set()));   // "set"
console.log(getType(new Promise(() => {}))); // "promise"
console.log(getType(new Error())); // "error"
console.log(getType(function(){}));// "function"

增强版:支持自定义类型判断

javascript 复制代码
/**
 * 类型判断工具
 */
const TypeUtils = {
    /**
     * 获取精确类型
     */
    get(value) {
        if (value === null) return "null";
        if (typeof value !== "object") return typeof value;
        return Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
    },
    
    /**
     * 是否为数组
     */
    isArray(value) {
        return Array.isArray(value);
    },
    
    /**
     * 是否为普通对象(排除数组、日期等)
     */
    isPlainObject(value) {
        if (typeof value !== "object" || value === null) return false;
        const proto = Object.getPrototypeOf(value);
        return proto === Object.prototype || proto === null;
    },
    
    /**
     * 是否为空对象/数组
     */
    isEmpty(value) {
        if (value === null || value === undefined) return true;
        if (typeof value === "string") return value.trim() === "";
        if (Array.isArray(value)) return value.length === 0;
        if (typeof value === "object") return Object.keys(value).length === 0;
        return false;
    },
    
    /**
     * 类型断言
     */
    assert(value, expectedType) {
        const actualType = this.get(value);
        if (actualType !== expectedType.toLowerCase()) {
            throw new TypeError(
                `Expected "${expectedType}" but got "${actualType}"`
            );
        }
        return true;
    }
};

// 使用示例
TypeUtils.get([1, 2, 3]);     // "array"
TypeUtils.isArray([1, 2, 3]); // true
TypeUtils.isPlainObject({});  // true
TypeUtils.isPlainObject([]);  // false
TypeUtils.isEmpty([]);        // true
TypeUtils.assert("hello", "string"); // true
TypeUtils.assert(123, "string");     // throws TypeError

六、实战应用与最佳实践

6.1 参数类型校验

javascript 复制代码
/**
 * 安全的函数参数校验
 */
function processData(options) {
    // 校验 options 是对象
    if (typeof options !== "object" || options === null) {
        throw new TypeError("options must be an object");
    }
    
    // 校验回调函数
    if (typeof options.callback !== "function") {
        throw new TypeError("options.callback must be a function");
    }
    
    // 校验数组
    if (!Array.isArray(options.items)) {
        throw new TypeError("options.items must be an array");
    }
    
    // 处理数据...
}

6.2 深拷贝时的类型处理

javascript 复制代码
/**
 * 深拷贝函数
 */
function deepClone(obj) {
    // 处理基本类型和函数
    if (obj === null || typeof obj !== "object") {
        return obj;
    }
    
    // 处理日期
    if (obj instanceof Date) {
        return new Date(obj.getTime());
    }
    
    // 处理正则
    if (obj instanceof RegExp) {
        const copy = new RegExp(obj.source, obj.flags);
        copy.lastIndex = obj.lastIndex;
        return copy;
    }
    
    // 处理数组
    if (Array.isArray(obj)) {
        return obj.map(item => deepClone(item));
    }
    
    // 处理普通对象
    const clonedObj = {};
    for (const key in obj) {
        if (obj.hasOwnProperty(key)) {
            clonedObj[key] = deepClone(obj[key]);
        }
    }
    
    return clonedObj;
}

6.3 表单数据验证

javascript 复制代码
class Validator {
    constructor(data) {
        this.data = data;
        this.errors = {};
    }
    
    require(fields) {
        fields.forEach(field => {
            const value = this.data[field];
            if (value === null || value === undefined || value === "") {
                this.errors[field] = `${field} is required`;
            }
        });
        return this;
    }
    
    isType(field, type) {
        const value = this.data[field];
        const actualType = Object.prototype.toString.call(value).slice(8, -1).toLowerCase();
        if (actualType !== type.toLowerCase()) {
            this.errors[field] = `${field} must be ${type}`;
        }
        return this;
    }
    
    validate() {
        return Object.keys(this.errors).length === 0 
            ? { valid: true } 
            : { valid: false, errors: this.errors };
    }
}

// 使用示例
const validator = new Validator({
    name: "张三",
    age: 25,
    email: "zhangsan@example.com"
});

const result = validator
    .require(["name", "email"])
    .isType("age", "number")
    .validate();

console.log(result);  // { valid: true }

6.4 最佳实践总结

javascript 复制代码
// ✅ 最佳实践清单

// 1. 判断数组:优先使用 Array.isArray()
if (Array.isArray(arr)) { ... }

// 2. 判断 null:必须放在前面
if (value === null) { ... }

// 3. 判断基本类型:使用 typeof
if (typeof value === "string") { ... }

// 4. 判断引用类型:使用 toString.call()
if (Object.prototype.toString.call(value) === "[object Date]") { ... }

// 5. 判断普通对象:检查原型
function isPlainObject(obj) {
    return typeof obj === "object" && 
           obj !== null && 
           Object.getPrototypeOf(obj) === Object.prototype;
}

// 6. 避免使用 constructor 判断(容易被破坏)
// ❌ 不推荐
if (obj.constructor === Object) { ... }

// 7. 跨 iframe 场景:使用 toString.call()
// ❌ 可能失效
if (arr instanceof iframeWindow.Array) { ... }
// ✅ 始终有效
if (Object.prototype.toString.call(arr) === "[object Array]") { ... }

七、常见问题 FAQ

Q1: 为什么 [] instanceof Object 返回 true

A : 因为所有对象都继承自 ObjectObject.prototype 位于所有对象的原型链上。

javascript 复制代码
[].__proto__.__proto__ === Object.prototype  // true

Q2: 如何判断一个变量是普通对象而不是数组或其他对象?

A : 检查其原型是否直接等于 Object.prototype

javascript 复制代码
function isPlainObject(obj) {
    return typeof obj === "object" && 
           obj !== null && 
           Object.getPrototypeOf(obj) === Object.prototype;
}

isPlainObject({})      // true
isPlainObject([])      // false
isPlainObject(new Date()) // false

Q3: typeof null 为什么返回 "object"

A : 这是 JavaScript 的历史遗留 bug。在 JS 的最初实现中,值以 32 位存储,其中 3 位表示类型。null 的类型标记被错误地设置为 0(object 类型),这个设计一直沿用至今。

javascript 复制代码
// 可以用以下方式正确判断 null
typeof null === "object"  // true(bug)
null === null             // true(正确判断方式)

Q4: 如何判断一个对象是否是某个类的实例(包括子类)?

A : 使用 instanceof

javascript 复制代码
class Animal {}
class Dog extends Animal {}

const dog = new Dog();
dog instanceof Dog     // true
dog instanceof Animal  // true(包含子类)

Q5: instanceofconstructor 哪个性能更好?

A : constructor 略快,因为它直接读取属性,不需要遍历原型链。但在现代浏览器中差异极小,建议优先考虑可靠性而非性能。

javascript 复制代码
// constructor 更快(直接读取)
obj.constructor === Constructor

// instanceof 稍慢(遍历原型链)
obj instanceof Constructor

Q6: 如何处理 Symbol 类型的判断?

A : 使用 typeof

javascript 复制代码
const sym = Symbol("description");
typeof sym === "symbol"  // true

// 或使用 toString
Object.prototype.toString.call(sym)  // "[object Symbol]"

附录:类型判断速查表

判断目标 推荐方法 示例
数组 Array.isArray() Array.isArray(arr)
普通对象 原型检查 Object.getPrototypeOf(obj) === Object.prototype
日期 toString.call() Object.prototype.toString.call(d) === "[object Date]"
正则 toString.call() Object.prototype.toString.call(r) === "[object RegExp]"
字符串 typeof typeof s === "string"
数字 typeof typeof n === "number"
布尔值 typeof typeof b === "boolean"
undefined typeof typeof u === "undefined"
null 严格相等 v === null
函数 typeof typeof f === "function"
Map/Set toString.call() Object.prototype.toString.call(m) === "[object Map]"
Promise toString.call() Object.prototype.toString.call(p) === "[object Promise]"
任意类型 typeof + toString 组合使用

相关推荐
gezg1 小时前
DeepSeek Harness 插件:Excel 拖进输入框,AI 自己去读文件
前端·ai编程
Asize1 小时前
HTTP 明明无状态,登录态怎么就保住了——React + Zustand + JWT 鉴权全流程拆解
前端·javascript
两只羊ovo1 小时前
MCP:AI 界的 USB-C,把模型和世界「插」起来
前端
Darling噜啦啦1 小时前
JWT 登录鉴权全链路:从 Zustand 状态管理到 Axios 拦截器,彻底搞懂前端鉴权工程
前端
可涵不会debug1 小时前
LangChain 示例选择器(Example selectors)完整基础概念解读
服务器·前端·数据库
Csvn1 小时前
😱 React `<StrictMode>`:为什么 useEffect 被调用了两次?别慌,这是特性不是 bug
前端
Asize1 小时前
2 道大厂面试题:TS 工具类型我懂了,CSS 3 列布局把我问住了
前端·css·typescript
胡萝卜术2 小时前
从"氛围编程"到规范驱动:两次创造如何让 AI 协作从碰运气变成工程流水线
前端·面试·github
Imchendiana2 小时前
《狂人日记NO.11》— 给 AI 装一本"项目说明书":我把"自己"蒸馏成了一个编码知识库Skill
前端·ai编程