目录

new与直接创建的区别

一、new 与直接创建的区别

1. 内存分配机制

二、内存模型详解

1. new 的内存分配过程

2. 直接创建对象的内存模型

三、变量在内存中的位置

1. 栈内存 vs 堆内存

2. new 创建的对象内存布局

四、性能与内存优化

1. 方法共享(原型 vs 实例)

2. 闭包与内存泄漏

五、关键区别总结

六、代码示例对比

1. 直接创建对象

2. new 创建对象

七、总结

new底层机制

一、new 的执行流程(底层四步)

1. 创建空对象并绑定原型

2. 绑定 this 并执行构造函数

3. 处理构造函数返回值

4. 完成对象创建

二、底层机制模拟(手写 new 函数)

三、关键底层特性

1. 构造函数内部的 return 陷阱

2. 性能优化

3. 严格模式下的 this 保护

四、new 的应用场景与陷阱

1. 适用场景

2. 常见陷阱

五、总结


new与直接创建的区别


一、new 与直接创建的区别

1. 内存分配机制

  • 直接创建(字面量)

    const obj = { name: "Alice" };
    • 内存模型

      • 对象直接分配在堆内存中。

      • 其隐式原型(__proto__)自动指向 Object.prototype

    • 特点:无构造函数参与,无法通过 instanceof 追溯类型。

  • 使用 new

    function Person(name) { this.name = name; }
    const obj = new Person("Bob");
    • 内存模型

      • 创建一个空对象,并将其 __proto__ 链接到 Person.prototype

      • 构造函数逻辑(Person)在该对象的上下文中执行。

    • 特点:对象类型明确(obj instanceof Person 为 true),可继承原型方法。


二、内存模型详解

1. new 的内存分配过程

当执行 new Person("Bob") 时,内存中发生以下步骤:

  1. 创建空对象

    const obj = Object.create(Person.prototype); // 原型链绑定
    • 堆内存中分配新对象,obj.__proto__ → Person.prototype

  2. 绑定 this 并执行构造函数

    Person.call(obj, "Bob"); // 将 this 指向 obj
    • 构造函数内部对 this 的操作(如 this.name = "Bob")会写入 obj 的内存空间。

  3. 返回对象

    • 若构造函数未显式返回对象,则返回 obj

    • 若构造函数返回 对象(包括数组、函数等),则替代 obj

    • 若返回 非对象值(如 numberstring),则忽略返回值,仍返回 obj

2. 直接创建对象的内存模型

const obj = { name: "Alice" };
  • 堆内存结构

    • 对象直接分配在堆中,属性值(如 name)存储在对象内部。

    • obj.__proto__ → Object.prototype


三、变量在内存中的位置

1. 栈内存 vs 堆内存

  • 栈内存

    • 存储 基本类型值numberstringboolean 等)和 引用地址

    • 例如:

      const age = 30; // 基本类型,值存在栈中
      const ref = obj; // 引用地址存在栈中,指向堆中的对象
  • 堆内存

    • 存储 引用类型值(对象、数组、函数等)。

    • 例如:

      const obj = { name: "Alice" }; // 对象本身在堆中

2. new 创建的对象内存布局

假设有以下构造函数:

function Person(name) {
  this.name = name;          // 实例属性(存储在对象自身)
}
Person.prototype.greet = function() { // 原型方法(存储在原型)
  console.log(this.name);
};

const p = new Person("Bob");
  • 内存结构

    p (栈中的引用地址) 
      │
      └─→ 堆中的 Person 实例对象
            ├─ name: "Bob"              // 实例属性
            └─ __proto__: → Person.prototype
                                ├─ greet: function() // 原型方法
                                └─ __proto__: → Object.prototype

四、性能与内存优化

1. 方法共享(原型 vs 实例)

  • 实例方法(每个对象独立):

    function Person(name) {
      this.name = name;
      this.greet = function() { ... }; // 每个实例独占一个方法
    }
    • 内存开销:方法重复存储,占用更多堆内存。

  • 原型方法(共享):

    Person.prototype.greet = function() { ... }; // 所有实例共享
    • 内存优化:方法仅存一份,通过原型链访问。

2. 闭包与内存泄漏

若构造函数中使用了闭包:

function Person(name) {
  this.getName = function() { return name; }; // 闭包保留 name
}
  • 内存影响:每个实例的 getName 方法独立,且闭包中的 name 无法被 GC 回收,直到实例销毁。


五、关键区别总结

特性 new 创建的对象 直接创建的对象
原型链 __proto__ → 构造函数原型 __proto__ → Object.prototype
类型标识 instanceof 可检测类型 无法追溯自定义类型
方法存储 方法可共享于原型 方法需直接定义在对象中
内存占用 实例属性独立,原型方法共享 所有属性和方法独立
构造函数逻辑 可执行初始化代码 无初始化逻辑

六、代码示例对比

1. 直接创建对象
const obj1 = { name: "Alice" };
const obj2 = { name: "Bob" };

console.log(obj1.greet === obj2.greet); // false(方法不共享)
2. new 创建对象
function Person(name) { this.name = name; }
Person.prototype.greet = function() { console.log(this.name); };

const p1 = new Person("Alice");
const p2 = new Person("Bob");

console.log(p1.greet === p2.greet); // true(方法共享)

七、总结

  • new 的核心价值:实现面向对象的实例化、原型继承和方法共享。

  • 内存效率:通过原型链共享方法,减少内存占用。

  • 变量存储

    • 基本类型存在栈中,引用地址指向堆中的对象。

    • 实例属性在堆中独立存储,原型方法在原型对象中共享。

  • 应用场景

    • 需要类型标识和方法共享 → 使用 new

    • 简单数据结构 → 直接创建对象。


  

new底层机制


一、new 的执行流程(底层四步)

当执行 const obj = new Constructor(arg) 时,底层发生以下步骤:

1. 创建空对象并绑定原型
const obj = Object.create(Constructor.prototype);
  • 内存操作:在堆中分配新对象,其隐式原型(__proto__)指向构造函数的 prototype

  • 原型链效果:新对象可访问 Constructor.prototype 上的属性和方法。

2. 绑定 this 并执行构造函数
const result = Constructor.apply(obj, args);
  • 上下文切换:构造函数内部的 this 被强制绑定到新对象 obj

  • 属性初始化:构造函数中通过 this.xxx = ... 定义的属性会被写入 obj 的内存空间。

3. 处理构造函数返回值
if (typeof result === 'object' && result !== null) {
  return result; // 构造函数返回对象,替代默认对象
} else {
  return obj;    // 否则返回新创建的对象
}
  • 规则

    • 若构造函数返回 对象(包括数组、函数等),则替代 obj

    • 若返回 非对象值(如 numberstring),则忽略返回值,仍返回 obj

4. 完成对象创建
  • 最终结果obj(或被替代的对象)成为 new 表达式的结果。


二、底层机制模拟(手写 new 函数)

以下代码模拟 new 的底层行为:

function myNew(Constructor, ...args) {
  // 1. 创建空对象,并绑定原型链
  const obj = Object.create(Constructor.prototype);
  
  // 2. 执行构造函数,绑定 this
  const result = Constructor.apply(obj, args);
  
  // 3. 处理返回值
  return result instanceof Object ? result : obj;
}

// 使用示例
function Person(name) { this.name = name; }
const p = myNew(Person, "Alice");
console.log(p.name); // "Alice"

三、关键底层特性

1. 构造函数内部的 return 陷阱
  • 返回对象:替代默认对象

    function Person() { return { name: "Alice" }; }
    const p = new Person(); // p 是 { name: "Alice" }
  • 返回非对象:忽略返回值。

    function Person() { return 42; }
    const p = new Person(); // p 是 Person 实例
2. 性能优化
  • 方法共享:将方法定义在原型上(Person.prototype.method),而非构造函数内部,避免每个实例重复创建方法。

  • 内存泄漏:避免在构造函数中创建闭包,防止意外保留无用引用。

3. 严格模式下的 this 保护
"use strict";
function Person() {
  console.log(this); // 未使用 new 时,this 为 undefined
}
Person(); // 报错:Cannot set property 'name' of undefined

四、new 的应用场景与陷阱

1. 适用场景
  • 自定义类型:需要明确类型标识(如 instanceof 检测)。

  • 共享方法:通过原型链实现方法复用。

  • 框架开发:如 React 组件类(class Component 基于 new)。

2. 常见陷阱
  • 忘记使用 new

    function Person(name) { this.name = name; }
    const p = Person("Alice"); // this 指向全局(或 undefined)

    解决方案:构造函数内强制 new 调用:

    function Person(name) {
      if (!(this instanceof Person)) {
        return new Person(name);
      }
      this.name = name;
    }

五、总结

  • new 的核心作用:基于构造函数创建实例,绑定原型链,初始化对象属性。

  • 底层四步:创建空对象 → 绑定原型 → 执行构造函数 → 处理返回值。

  • 内存模型:实例属性独立存储,原型方法共享于原型对象。

  • 最佳实践:方法定义在原型,避免构造函数返回非对象值,使用 ES6 class 简化代码。


Logo

GitCode 天启AI是一款由 GitCode 团队打造的智能助手,基于先进的LLM(大语言模型)与多智能体 Agent 技术构建,致力于为用户提供高效、智能、多模态的创作与开发支持。它不仅支持自然语言对话,还具备处理文件、生成 PPT、撰写分析报告、开发 Web 应用等多项能力,真正做到“一句话,让 Al帮你完成复杂任务”。

更多推荐