佛山市网站建设_网站建设公司_HTML_seo优化
2025/12/30 11:36:41 网站建设 项目流程

Object.create 和 new 区别

Object.create 和 new 区别

  • 导出时间: 2025/12/30 11:16:02
  • 对话 ID: 6940cce7-e43c-8322-ae03-6b22e93902cc
  • 消息数: 8

用户 · 2025/12/16 11:07:18

// 1. 定义祖先 (GrandParent)
const grandParent = {
lastName: "Wang",
sayHi: function() { console.log("Hi from GrandParent!"); }
};

// 2. 定义父亲 (Parent),并让它的原型指向祖先
const parent = Object.create(grandParent);
parent.firstName = "Dayong";

// 3. 定义你 (Child),并让你的原型指向父亲
const child = Object.create(parent);
child.age = 18;

// --- 测试查找过程 ---

// Case A: 查找自身有的属性
console.log(child.age); // 18
// 解释:child 自己有 age,直接返回。

// Case B: 查找原型链上的属性 (父亲的)
console.log(child.firstName); // "Dayong"
// 解释:child 自己没有,顺着 proto 找到 parent,parent 有。

// Case C: 查找原型链深处的属性 (祖先的)
console.log(child.lastName); // "Wang"
// 解释:child 没有 -> parent 没有 -> grandParent 有。

// Case D: 方法继承
child.sayHi(); // "Hi from GrandParent!"
// 解释:一直找到祖先的方法并执行。

// Case E: 找不到的情况
console.log(child.money); // undefined
// 解释:找遍了全家(直到 Object.prototype 的上一级 null),都没找到。

这段js代码的 Object.create函数是什么? 和new有什么关系吗?


助手 · 2025/12/16 11:07:20

很好的一段示例代码 👍,你已经把原型链查找过程演示得非常清楚了。下面我们系统地回答你两个问题:


一、Object.create() 是什么?

1️⃣ 本质定义

Object.create(proto, [propertiesObject])

👉 作用:创建一个新对象,并把这个新对象的 [[Prototype]](也就是 __proto__)指向你传入的 proto 对象。

用一句话说:

Object.create 是“直接指定原型”的造对象方式


2️⃣ 用你的代码来理解

const parent = Object.create(grandParent);

等价于:

const parent = {};
parent.__proto__ = grandParent; // 本质效果

⚠️ 注意:
__proto__ 是访问器,不是推荐写法,但它很好地帮助理解机制


3️⃣ Object.create 不会做的事情

Object.create 只做一件事

👉 建立原型关系

不会

  • 调用构造函数
  • 初始化属性
  • 自动创建实例属性

所以你才需要手动写:

parent.firstName = "Dayong";
child.age = 18;

4️⃣ 经典用途

const child = Object.create(parent);

非常适合:

  • 只关心“继承关系”
  • 做原型委托(Delegation)
  • 不需要构造函数那一套复杂流程

二、Object.create()new 有什么关系?

这是核心问题 👇
它们都和“原型”有关,但层级完全不同。


三、new 到底做了什么?

function Person(name) {this.name = name;
}const p = new Person("Tom");

new Person() 背后等价于👇(伪代码):

const obj = {};
obj.__proto__ = Person.prototype;   // 建立原型链
Person.call(obj, "Tom");            // 执行构造函数
return obj;

📌 new = Object.create + 调用构造函数


四、Object.create vs new 对照表

对比点 Object.create new
是否创建对象
是否指定原型 ✅(直接指定) ✅(指向构造函数的 prototype)
是否调用函数 ✅(调用构造函数)
是否自动初始化属性
是否依赖构造函数
适合的编程风格 原型委托 构造函数 / 类

五、你的例子,用 new 会怎么写?

如果用 new,结构会变成这样:

function GrandParent() {}
GrandParent.prototype.lastName = "Wang";
GrandParent.prototype.sayHi = function () {console.log("Hi from GrandParent!");
};function Parent() {this.firstName = "Dayong";
}
Parent.prototype = Object.create(GrandParent.prototype);function Child() {this.age = 18;
}
Child.prototype = Object.create(Parent.prototype);const child = new Child();

💡 对比一下你现在的写法,会发现:

  • Object.create 更直接
  • new 更“面向类”

六、一句话总结(面试级)

Object.create 是手动指定原型链的低级 API;new 是基于构造函数的高级封装,本质上内部也依赖原型机制。

或者更狠一点:

new 做的第一步,本质上就是 Object.create(Constructor.prototype)


如果你愿意,我可以下一步帮你讲:

  • 🔥 为什么 ES6 class 只是 new + prototype 的语法糖
  • 🔥 Object.create(null) 有什么神奇用途
  • 🔥 为什么说 JS 是“基于原型而不是类”的语言

你想继续哪一个?


用户 · 2025/12/16 11:11:40

为什么 ES6 class 只是 new + prototype 的语法糖


助手 · 2025/12/16 11:11:42

这是一个非常关键、非常本质的问题 👍
理解了它,你就真正理解了 JavaScript 的“类”

我会按结论 → 证据 → 底层机制 → 易错点这个顺序来讲。


一、先给结论(记住这句话)

ES6 的 class 并没有引入新的面向对象模型,它只是把 new + prototype 用更像“类”的语法包装了一层。

换句话说:

JavaScript 仍然是基于原型的语言,不是基于类的语言。


二、最直观的证据:class 和构造函数完全等价

1️⃣ 用 class

class Person {constructor(name) {this.name = name;}sayHi() {console.log("Hi, I'm " + this.name);}
}const p = new Person("Tom");

2️⃣ 用 ES5 构造函数写法

function Person(name) {this.name = name;
}Person.prototype.sayHi = function () {console.log("Hi, I'm " + this.name);
};const p = new Person("Tom");

3️⃣ 行为完全一致

p.sayHi();                 // 一样
p instanceof Person;       // true
p.__proto__ === Person.prototype; // true

📌 说明什么?

👉 class 没有改变对象的生成方式
👉 仍然是:new → 绑定 prototype → 返回对象


三、class 语法在底层做了什么?

1️⃣ class 本质仍是函数

class Person {}
console.log(typeof Person); // "function"

⚠️ 这点非常关键:

class 在 JS 里依然是一个函数,而不是新类型


2️⃣ new class() 仍然走 old 流程

当你执行:

new Person("Tom")

JS 引擎做的事仍然是:

const obj = Object.create(Person.prototype);
Person.call(obj, "Tom");
return obj;

💥 没有任何一步是“class 专属”的


四、class 里的方法去哪了?

很多人以为:

class Person {sayHi() {}
}

sayHi 在实例上 ❌
实际上:

Person.prototype.sayHi === p.sayHi // true

等价于:

Person.prototype.sayHi = function () {}

📌 说明:class 方法仍然是 prototype 方法


五、继承:extends ≈ 原型链拼接

1️⃣ ES6 写法

class Parent {say() {}
}class Child extends Parent {}

2️⃣ 等价的 ES5 原型写法

function Parent() {}Parent.prototype.say = function () {};function Child() {}Child.prototype = Object.create(Parent.prototype);
Child.prototype.constructor = Child;

3️⃣ extends 做了两件事

Child.prototype.__proto__ === Parent.prototype
Child.__proto__ === Parent

📌 所以你会看到:

Child instanceof Function // true
Child.__proto__ === Parent // true

👉 这仍然是原型链,不是类继承


六、那 class 到底“新”在哪里?

答案是:语法层面的约束和糖

🍬 1️⃣ 更像传统 OOP(Java / C++)

  • constructor
  • extends
  • super

底层机制没变


🍬 2️⃣ 方法默认不可枚举(重要细节)

Object.keys(Person.prototype); // []

而 ES5 手写时容易变成可枚举


🍬 3️⃣ class 必须用 new(防止误用)

Person(); // ❌ TypeError

ES5 构造函数可以被当普通函数调用(容易出 bug)


🍬 4️⃣ 自动开启严格模式

class A {foo() {// 自动 strict mode}
}

七、一个“致命证据”:class 没有私有实例方法(直到后来)

如果 JS 真的是“类语言”:

  • 每个实例应该有自己的方法副本
    ❌ 但 JS 一直是 共享 prototype 方法
p1.sayHi === p2.sayHi // true

这恰恰说明:

JS 的设计核心仍然是“原型共享”,不是“类复制”


八、为什么说“语法糖”是准确的?

判断标准只有一个:

是否引入了新的运行时机制?

答案:❌ 没有

特性 是否 class 独有
prototype
[[Prototype]]
new 流程
instanceof

📌 class 只是写法变了模型没变


九、用一句“底层话”总结(非常重要)

ES6 class 只是把 JavaScript 原本的「构造函数 + prototype + new」用更像传统 OOP 的方式包装了一下,本质仍是原型委托。

或者一句更狠的:

class 是给“写 Java 的人”看的,prototype 是给“JS 引擎”看的。


十、如果你继续深入(下一步建议)

你现在已经到了 JS 原型的“理解门槛”,接下来非常适合看:

1️⃣ super 到底是怎么工作的(不是简单父类方法调用)
2️⃣ this 在 class / prototype / arrow function 中的差异
3️⃣ 为什么 Object.create 在某些场景 比 class 更“纯 JS”

如果你选一个,我可以直接帮你画“JS 对象关系图(脑图级)”。


用户 · 2025/12/20 23:21:39

class中的属性可以不指定初始值,也不用构造函数初始化吗?


助手 · 2025/12/20 23:21:40

可以,但要分清“你指的属性是哪一类”。
这是一个很多人被 class 语法误导的点,我们一步一步拆开说。


一句话结论(先记住)

class 里“不写初始值”的,只有两种情况是成立的:

1️⃣ 原型方法(method)
2️⃣ 只存在于类型层面、但实例上还没创建的属性

真正的“实例属性”

如果你不初始化,它就根本不存在


一、先看最容易误解的例子

❌ 这样写,并不会创建实例属性

class Person {name;age;
}

很多人以为:

“我声明了 nameage,实例上就有了”

但实际上:

const p = new Person();console.log(p.name); // undefined
console.log("name" in p); // false ❌

📌 关键点

p.name === undefined

p 有一个 name 属性


二、那 class field 到底干了什么?

1️⃣ class field 的真实语义

class Person {name;
}

等价于(规范层面)

class Person {constructor() {this.name = undefined;}
}

⚠️ 但注意一个重要区别(取决于运行环境):

  • ES2022+ 标准中
    👉 实例上确实会创建该属性,值为 undefined
  • 老环境 / 编译前直觉
    👉 很多人误以为“只是声明”

所以要记住一句非常重要的话:

class field 不是“声明”,而是“实例赋值语法糖”


三、那为什么你会觉得“不用初始化也能用”?

因为 JS 的原型查找 + undefined 特性在迷惑你。

看这个例子 👇

class Person {}Person.prototype.name = "default";const p = new Person();console.log(p.name); // "default"

你以为:

“我没初始化 name,但能用!”

实际上:

这是原型上的属性,不是实例属性

p.hasOwnProperty("name"); // false

四、真正的分类:class 里的“属性”分 3 种

① 原型方法(不用初始化,天然存在)

class Person {sayHi() {}
}

特点:

  • Person.prototype
  • 所有实例共享
  • 不需要 constructor
  • ✅ 合法、推荐

② 实例属性(必须初始化)

✅ 正确方式 1:构造函数

class Person {constructor() {this.name = "Tom";}
}

✅ 正确方式 2:class field(现代写法)

class Person {name = "Tom";
}

等价于 constructor 里的赋值。


③ “未初始化的字段”(值为 undefined)

class Person {name;
}

结果(现代标准):

const p = new Person();p.hasOwnProperty("name"); // true
p.name === undefined;     // true

📌 注意
这不是“声明”,而是:

实例创建时自动执行 this.name = undefined


五、那能不能完全不写初始化?

❌ 不能(如果你指的是“实例属性”)

class Person {}const p = new Person();
p.age; // undefined

但此时:

p.hasOwnProperty("age"); // false

👉 这个属性根本不存在,只是访问不存在的 key 返回 undefined


六、一个非常重要的对比(面试高频)

访问 undefined 的 3 种情况

情况 obj.x hasOwnProperty
未声明 undefined ❌ false
class field undefined ✅ true
构造函数赋值 ✅ true

七、继承时更容易踩坑的地方 ⚠️

class Parent {data;
}class Child extends Parent {}const c = new Child();

执行顺序是:

super(); // Parent 的字段初始化先执行

所以:

c.hasOwnProperty("data"); // true

📌 字段初始化是在构造函数之后、原型之前的规范步骤


八、最终总结(请记住这几句话)

1️⃣ class 里没有“只声明不创建”的实例属性
2️⃣ 不初始化 ≠ 不存在(在 class field 场景)
3️⃣ 真正不写的属性,连实例都没有
4️⃣ 原型方法不需要初始化,这是 prototype 的特性

终极一句话:

JS 没有“类字段声明”,只有“实例赋值”,class 只是把赋值藏起来了。


如果你愿意,我可以下一步帮你讲一个非常反直觉但很重要的点

👉 为什么 class field 会破坏 prototype 的“纯粹性”,以及它和内存/性能的关系

这个点很多高级 JS 开发者都没真正想明白。


用户 · 2025/12/20 23:26:50

讲一个吧


助手 · 2025/12/20 23:27:32

好,那我就讲最容易被忽略、但一旦懂了就“升一个段位”的那个点👇
我们就讲这一件事:

为什么 class field 会“破坏” prototype 的纯粹性,以及它对内存 / 性能 / 设计的真实影响


一、先给结论(非常重要)

class field 把“本来应该放在 prototype 上共享的东西,变成了每个实例各自一份”。

这不是语法问题,是对象模型的变化


二、prototype 的“原教旨模型”是什么?

在 JS 诞生之初,设计是这样的:

function Person(name) {this.name = name;      // 每个实例一份(状态)
}Person.prototype.sayHi = function () {console.log(this.name);
};

这个模型的哲学是:

  • 状态(data) → 实例
  • 行为(method) → prototype
  • 所有实例共享行为

👉 这就是 JS 的原型委托模型


三、class field 做了什么“越界”的事?

看这个 class

class Person {sayHi = () => {console.log(this.name);};
}

很多人写这个是为了:

  • 自动绑定 this
  • 少写 constructor

但你知道它等价于什么吗?

class Person {constructor() {this.sayHi = () => {console.log(this.name);};}
}

💥 致命点来了

sayHi 不在 Person.prototype 上了
而是在 每一个实例上


四、用一行代码证明“破坏共享”

const p1 = new Person();
const p2 = new Person();p1.sayHi === p2.sayHi; // false ❌

对比 prototype 方法:

class Person {sayHi() {console.log(this.name);}
}p1.sayHi === p2.sayHi; // true ✅

五、这到底“破坏”了什么?

1️⃣ 内存共享被破坏

  • prototype:1 个函数
  • class field:N 个函数(N = 实例数)

在组件 / 列表 / 大量对象场景下,这是真实成本


2️⃣ 行为 ≠ 类型行为,而变成了“实例行为”

prototype 方法表达的是:

所有 Person 都会 sayHi

而 class field 方法表达的是:

这个具体对象有一个 sayHi

📌 这已经不是“类行为”了,而是“对象定制”


3️⃣ 原型链的“语义优势”消失了

原型链的优势是:

对象 → 类型 → 父类型 → Object.prototype

class field 把方法直接塞在对象上:

对象(方法) ❌

👉 你绕开了整个 prototype 体系


六、那为什么 React / 前端工程里这么爱用?

你一定见过这种写法 👇

class Button extends React.Component {handleClick = () => {this.setState({});};
}

原因只有一个:

this 绑定

传统 prototype 方法:

this.handleClick = this.handleClick.bind(this);

class field = 自动绑定 + 少写代码

📌 这是工程便利性,不是模型优雅性


七、什么时候“应该用”,什么时候“不该用”?

✅ 适合用 class field 方法

  • 事件回调
  • UI 组件
  • 生命周期绑定
  • 需要稳定 this 的函数
  • 实例数量有限

👉 React class 组件


❌ 不适合用 class field 方法

  • 数据模型(Model / Entity)
  • 底层库
  • 高频实例(比如 10 万对象)
  • 强调继承 / 多态的场景

👉 这些地方 prototype 才是 JS 的本体


八、一个“认知升级”的视角

你现在可以这样看:

class 有两种“方法”

  • method() → 类型行为(prototype)
  • field = () => {} → 实例行为(instance)

这不是风格问题,是对象模型选择


九、终极总结(请背下来)

1️⃣ class field 本质是 constructor 里的赋值
2️⃣ 它会让方法变成“实例私有”,失去 prototype 共享
3️⃣ 代价是内存 & 原型语义,收益是 this 绑定 & 工程便利
4️⃣ class 并没有让 JS 变成“类语言”,只是给了你更多“绕开 prototype 的方式”

最狠的一句话:

你用 class field 写方法时,其实是在“假装 JS 是 Java”,但 JS 引擎心里很清楚:这只是对象赋值。


如果你愿意,我下一步可以讲一个更底层、但非常漂亮的点

👉 为什么说 Object.create 才是“最纯粹的 JS 继承”
👉 或者 为什么很多 JS 库刻意“不用 class”

你选哪个?


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询