为什么需要原型对象(在函数中)?

2024-05-26

我阅读了大量有关原型的材料并了解继承的一般情况。 然而,这是困扰我的一件事,我无法弄清楚。

On dmitrysoshnikov.com http://dmitrysoshnikov.com/ecmascript/javascript-the-core-2nd-edition/#comments有一个简化的示例说明了如何使用以下代码片段实现原型继承:

// Generic prototype for all letters.
let letter = {
  getNumber() {
    return this.number;
  }
};
 
let a = {number: 1, __proto__: letter};
let b = {number: 2, __proto__: letter};
// ...
let z = {number: 26, __proto__: letter};
 
console.log(
  a.getNumber(), // 1
  b.getNumber(), // 2
  z.getNumber(), // 26
);

下面是这张图

然而,当我们开始使用实际的继承结构(使用 new 关键字)时,它开始看起来像这样:

我明白它是如何运作的。我不明白的是,为什么我们突然需要所有子实例继承自的 Letter.prototype 对象,而不是像上面的第一个图那样拥有它。对我来说,第一个示例似乎没有任何问题。

我能想到的一个潜在原因是实际方法允许在类中实现静态方法/属性。在上面的示例中,如果您添加静态方法,那么它将是添加到 Letter 对象的函数,而不是添加到 Letter.prototype 对象的函数。子对象 (a,b,z) 将无权访问该函数。 在第一个示例中,这种功能必须以不同的方式实现,但我仍然认为这不是创建新 Prototype 对象的充分理由。我认为这个静态方法功能可以在没有它的情况下实现。

我错过了什么吗?

EDIT:

我认为有很多人试图解释我很感激的事情,但我不确定我的问题为什么 javascript 运行时被设计为以一种方式而不是另一种方式运行正确理解。

为了表明我的意思,我尝试了一些事情。

class Car{
     method() {
         console.log("hello")
     }
 }

 myCar = new Car();

// First a few tests as expected
myCar.method() // works
console.log(myCar.method === Car.method) // False, JS doesn't work that way, ok...
console.log(myCar.method === Car.prototype.method) // This is how it works, fine...

// How about we move the reference to the method up one level
Car.method = Car.prototype.method

// Delete the reference to it in prototype object,
// Btw. I tried to remove reference to whole prototype but somehow doesn't let me
delete Car.prototype.method

// Change the prototype chain so it links directly to Car and not Car's prototype object
myCar.__proto__ = Car

myCar.method() // Still works!!!
console.log(myCar.method === Car.method) // True !
console.log(myCar.method === Car.prototype.method) // False, we deleted the method property out of Car.prototype

So, Car.prototype不再需要,至少对于 myCar 的执行来说不再需要。 那么为什么该方法会进入到里面呢Car.prototype并不是Car那为什么不呢myCar.__proto__ = Car代替myCar.__proto__ = Car.prototype?


我不明白为什么我们突然需要Letter.prototype所有子实例都继承自该对象,而不是像上面的第一个图那样拥有它。

实际上那里什么都没有改变。它仍然是同一个对象,与名为的对象具有相同的用途const letter在第一个例子中。字母实例继承自它,它存储getNumber方法,它继承自Object.prototype.

改变的是额外的Letter功能。

对我来说,第一个例子似乎没有什么问题。

是的:{number: 2, __proto__: letter}是一种非常丑陋的创建实例的方式,并且在必须执行更复杂的逻辑来初始化属性时不起作用。

解决这个问题的方法是

// Generic prototype for all letters.
const letterPrototype = {
  getNumber() {
    return this.number;
  }
};
const makeLetter = (number) => {
  const letter = Object.create(letterPrototype); // {__proto__: letterPrototype}
  if (number < 0) throw new RangeError("letters must be numbered positive"); // or something
  letter.number = number;
  return letter;
}
 
let a = makeLetter(1);
let b = makeLetter(2);
// ...
let z = makeLetter(26);
 
console.log(
  a.getNumber(), // 1
  b.getNumber(), // 2
  z.getNumber(), // 26
);

现在我们有两个值,makeLetter and letterPrototype某种程度上属于彼此。另外,在比较各种make…函数,它们都共享相同的模式,首先创建一个继承各自原型的新对象,然后在最后返回它。为了简化,引入了通用构造:

// generic object instantiation
const makeNew = (prototype, ...args) => {
  const obj = Object.create(prototype);
  obj.constructor(...args);
  return obj;
}

// prototype for all letters.
const letter = {
  constructor(number) {
    if (number < 0) throw new RangeError("letters must be numbered positive"); // or something
    letter.number = number;
  },
  getNumber() {
    return this.number;
  }
};
 
let a = makeNew(letter, 1);
let b = makeNew(letter, 2);
// ...
let z = makeNew(letter, 26);
 
console.log(
  a.getNumber(), // 1
  b.getNumber(), // 2
  z.getNumber(), // 26
);

你能看到我们要去哪里吗?makeNew实际上是语言的一部分new操作员。虽然这可行,但实际选择的语法是使constructor传递给的值new和存储的原型对象.prototype的构造函数。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

为什么需要原型对象(在函数中)? 的相关文章

  • 由于 apollo-client 未定义,无法解构 GraphQL 查询?

    我正在寻找调试与错误消息相关的问题 未捕获的类型错误 无法解构 0 apollo client WEBPACK IMPORTED MODULE 4 useQuery 因为它未定义 Context 我正在为我的 React js 项目设置后端
  • 是否存在 IsCallable 为 false 但 IsConstructor 为 true 的 JS 对象?

    ECMAScript 规范函数可调用 https www ecma international org ecma 262 6 0 index html sec iscallable当且仅当其参数具有 Call 内部方法时返回 true 它在
  • Javascript Promise“then”始终运行,即使 Promise 未能执行

    我希望当调用第二个 then 时不执行第三个 then 但是 即使 Promise 被拒绝 调用第二个 then 并且代码返回 rejected 然后返回 undefined 它仍然调用第三个 then 如何不运行第三个 then 这样 未
  • 如何在react-bootstrap中禁用表单提交的

    在下面的代码片段中 我有许多文本类型的输入表单 如果用户点击 我似乎会得到相同的合成事件 就像他们按下提交按钮一样 我想忽略作为表单提交 只允许一个人按下 提交 按钮 我删除了一些表单组以减少示例 在所有情况下 按钮或 ENTER 键 e
  • Chrome 中的性能问题

    我目前正在从事一个相对较大的项目 使用 AngularJs 构建 应用程序的一部分是一个表单 您可以向其中添加任意数量的页面 不幸的是 添加了很多不必要的垃圾 即表示表单模型的对象可能会变得非常大 在某些时候 Chrome 基本上无法处理它
  • 使用 JavaScript 禁用第三方 cookie

    我正在努力根据所有在欧盟运营的公司的数据保护规则实施新的 Cookie 政策合规性 根据该规则 用户在使用任何网站时必须能够拒绝 接受除必需的 Cookie 之外的所有内容 在我客户的网站中 我可以看到正在存储以下第三方 cookie ga
  • 带有淘汰赛js的隐形recaptcha

    我正在完成隐形验证码 但我在实现它时遇到问题 谷歌开发人员页面中的代码显示它应该是这样的
  • 隐藏 Div 的父级

    我只是想隐藏父divcomments section div class content content green div div div 我试过这个 document getElementById comments section pa
  • 防止 iOS 键盘在 cordova 3.5 中滚动页面

    我正在使用 Cordova 3 5 和 jQuery mobile 构建 iOS 应用程序 我在大部分应用程序中禁用了滚动功能 但是 当我选择输入字段时 iOS 键盘会打开并向上滚动页面 我不想要这个功能 由于输入足够高 键盘不会覆盖它 我
  • 如何将函数附加到弹出窗口关闭事件(Twitter Bootstrap)

    我做了一些搜索 但我只能认为我可以将事件附加到导致其关闭的按钮 https stackoverflow com questions 13205103 attach event handler to button in twitter boo
  • Angular - CSS - 自定义类型=文件输入,如何使用按钮而不是标签?

    我制作了一个类型为 file 的自定义输入字段 因为我不喜欢默认的输入字段 为了实现这一目标 我做了
  • 在 HTML5 画布中,如何用我选择的背景遮盖图像?

    我试图用画布来实现这一点 globalCompositeOperation 但没有运气 所以我在这里问 这里有类似的问题 但我没有在其中找到我的案例 我的画布区域中有图层 从下到上的绘制顺序 画布底座填充纯白色 fff 用fillRect
  • 将 UMD Javascript 模块导入浏览器

    你好 我正在对 RxJS 进行一些研究 我可以通过在浏览器中引用它来使用该库 如下所示 它使用全局对象命名空间变量 Rx 导入 我可以制作可观察的东西并做所有有趣的事情 当我将 src 更改为指向最新的 UMD 文件时 一切都会崩溃 如下所
  • 页面上使用 HTML Editor Extender 进行回发会导致 IE11 中出现 JavaScript 错误

    我已将 HTML 编辑器扩展程序添加到我正在处理的页面中 现在每当我在页面上发回帖子时 都会收到以下 Javascript 错误 JavaScript 运行时错误 参数无效 之后什么也没有发生 这在 IE10 或更低版本以及我所知道的所有其
  • 使用 Vue 的多模式组件

    我在 Vue 中实现动态模式组件时遇到问题 A common approach I follow to display a set of data fetched from the db is I dump each of the rows
  • 代码镜像错误:未捕获错误:扩展集中无法识别扩展值([对象对象])

    全部 我目前正在从事一个React Electron项目 该项目的目标是完成一个Markdown编辑器 当我配置codemirror 该程序报告错误说 Uncaught Error Unrecognized extension value
  • 在 Javascript 中连接空数组

    我正在浏览一些代码 我想知道这有什么用处 grid push concat row 根据我的理解 它等同于 grid push row 为什么要大惊小怪 连接 你想使用 concat当您需要展平数组并且没有由其他数组组成的数组时 例如 va
  • 如何用另一个响应替换窗口的 URL 哈希?

    我正在尝试使用替换方法更改哈希 URL document location hash 但它不起作用 function var anchor document location hash this returns me a string va
  • 从 FileReader 设置背景图像样式

    我正在寻找一种解决方案 允许我从文件上传输入中获取文件并通过设置 document body style backgroundImage 来预览它 以下代码用于在 Image 元素中显示预览 function setImage id tar
  • 如何在执行新操作时取消先前操作的执行?

    我有一个动作创建器 它会进行昂贵的计算 并在每次用户输入内容时调度一个动作 基本上是实时更新 但是 如果用户输入多个内容 我不希望之前昂贵的计算完全运行 理想情况下 我希望能够取消执行先前的计算并只执行当前的计算 没有内置功能可以取消Pro

随机推荐