使用纯原型方法的 Javascript 寄生继承

2023-12-06

我正在学习 JavaScript 中的 OOP,并且已经阅读了相关的各种帖子。据我所知,道格拉斯·克罗克福德(Douglas Crockford)开出了一种纯原型方法继承而不是经典方法。

以下代码摘自here实现 Crockford 的方法:

var superInstance = {
  member1: 'superMember1',
  member2: 'superMember2'
};

var subInstance = Object.create(superInstance);
subInstance.member3 = 'subMember3';

我知道 Crockford 的方法取消了构造函数(如果我错了,请纠正我)。这是否意味着用这种方法初始化对象成员的唯一方法是使用上面代码所示的对象文字?另外,我该如何实施寄生遗传使用这种方法允许父类中共享成员、私有变量和非标量值(参考这篇文章)?

Crockford 在他的文章中提到了“创客函数”,但没有给出任何示例代码。如果有人能够使用 Crockford 的纯原型方法来演示寄生继承,那就太好了。

Thanks.


对原型继承的误解源于与经典继承相反的问题,即不调用基构造函数来实例化基对象。将原型设置为基础对象并不等同于经典继承,因为原型在实例之间共享。正如 Jimmy Breck-McKye 详细描述的那样。所以要达到寄生继承你必须遵循两条规则。

  1. 切勿直接在原型中定义字段成员。
  2. 实例化后继者时始终调用基构造函数

后者可以根据自己的喜好来实现Object.create或者将基础对象的实例直接分配给原型。鉴于Base是一个构造函数,继承的代码如下
Way #1

 function Base(){
 //a new object is created which is assigned to 'this'
 //this object has __proto__ === Base.prototype
     this.baseMember = 'I am the parent';
 }
 Base.prototype.baseMethod = function(){
     console.log('I am Base');
 };

 function Successor(){
 //a new object is created which is assigned to 'this'
 //this object has __proto__ === Successor.prototype

 //we override the object's property which is used for prototypal lookup
 //we lose members defined in Successor.prototype
      this.__proto__ = new Base();
 //we add a new property in the inherited object
      this.successorMember = 'I am a child';
 }
 Successor.prototype.successorMethod = function(){
     console.log('I am Successor');
 };

我们将按以下方式使用定义的构造函数

var child = new Successor();
//resulting in structure
//child: { //instance of Successor
//  successorMember: 'I am a child', 
//  __proto__: {//instance of Base
//     baseMember: 'I am the parent'
//     __proto__: {//Base.prototype
//        baseMethod : function 
//  }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

关注失踪者successorMethod定义通过Successor.prototype。发生这种情况是因为我们覆盖了__proto__对象的属性。

Way #2
另一种覆盖的方法__proto__属性是调用Object.create。然而这个函数返回一个新的对象,因此我们必须重写返回的对象Successor构造函数

 function Successor(){
 //a new object #1 is created which is assigned to 'this'
 //this object has __proto__ === Successor.prototype

 //a new instance #2 of Base is created with __proto__ === Base.prototype
 //a new object #3 is created with a __proto__ set to #2
      var successor = Object.create(new Base());
 //a new property is added to #1
      this.neverShowMember = 'I will not exist in resulting object';
 //a new property is added to #3 
      successor.successorMember = 'I am a child';
 //return of a non-primitive type object from constructor overrides the result
      return successor;//return object #3
 }

让我们详细研究一下这种方法的用法:

var child = new Successor();
//child: { //instance of Object
//  successorMember: 'I am a child', 
//  __proto__: {//instance of Base
//     baseMember: 'I am the parent'
//     __proto__: {//Base.prototype
//        baseMethod : function 
//  }}}
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via prototype lookup
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

结果行为几乎相同。关注失踪者neverShowMember尽管它被定义为this在构造函数内。这可能是错误的根源。

Way #3
继承的另一种方法是不要乱搞proto链。 Jimmy Breck-McKye 的文章中描述了这种方法。我将跳过之前提供的详细评论,并将重点放在更改上

 function Successor(){
 //a new instance  Base is created with __proto__ === Base.prototype
      var successor = new Base();
 //extend object with a new property 
      successor.successorMember = 'I am a child';
      return successor;//return instance of Base with extra properties
 }

 var child = new Successor();
//child: { //instance of Base
//  successorMember: 'I am a child', 
//  baseMember: 'I am the parent'
//  __proto__: {//Base.prototype
//        baseMethod : function 
//  }} 
console.log(child.successorMember);//accessible via direct property
console.log(child.baseMember);//accessible via direct property
console.log('baseMethod' in child);//true, accessible via prototype lookup
console.log('successorMethod' in child);//false, method doesn't exist anywhere in the chain

您会看到该架构变得扁平化。作为一个明显的结论,如果您覆盖基本成员,您将无法访问它们。所以如果在里面Successor我们定义

successor.baseMember = 'I am already grown enough!';

实例(child)将失去对baseIntance.baseMember这等于“我是父母”。与以前的方法相反,它可以通过child.__proto__.baseMember。但我相信这在使用 javascript 开发时并不常见,应该在另一个问题下讨论。

Note在所有情况下定义的成员Successor.prototype都迷失了。您应该注意手动将它们复制到Successor构造函数。

Conclusion
I hope this description was clear enough to understand that CraCrockford's object function

function object(o) {
    function F() {}
    F.prototype = o;
    return new F();
}

总是需要一个新实例作为参数传递o实现寄生遗产。因此它的用法应该如下所示

var child = object(new Base());
child.successorMember = 'I am a child';

同样适用于 OP 中的代码。跟随寄生遗产superInstance每次传递到时都应该是一个新实例Object.create。因此它应该是一个工厂函数

var superInstance = function(){
    return {
      member1: 'superMember1',
      member2: 'superMember2'
    }
};

var subInstance = Object.create(superInstance());

或构造函数

function superInstance(){
    this.member1: 'superMember1',
    this.member2: 'superMember2'
};

var subInstance = Object.create(new superInstance());

希望这可以帮助

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

使用纯原型方法的 Javascript 寄生继承 的相关文章

  • 正则表达式替换“NO-BREAK SPACE”

    我正在寻找一个正则表达式来替换字符串中的 NO BREAK SPACE 有一些与 NO BREAK SPACE 相关的问题 但似乎没有一个问题能让我找到正确的答案 到目前为止 我尝试使用 字符串 AB 的第二个字符是不间断空格 但没有成功
  • React Native:找不到变量:需要

    我正在尝试修改一个反应原生样板 https github com rayandrews razzle rnw redux loadable这样我就可以在Android平台上运行了 I installed the expo package a
  • JavaScript 相当于 htonl?

    对于 AJAX 请求 我需要发送一个幻数作为请求正文的前四个字节 首先是最高有效字节 以及请求正文中的其他几个 非常量 值 JavaScript 中是否有相当于 htonl 的东西 例如 给定 0x42656566 我需要生成字符串 Bee
  • 冻结 TH 标题和滚动数据

    我有一个 html 表 我想冻结标题行标签以滚动数据 我怎样才能做到这一点 我需要使用Dom吗 谢谢 我的解决方案是使用两个表并固定列宽 下面的表格位于可滚动的 div 中 并且没有标题
  • 为什么动态安装的 vuejs 内容不是根 vue 实例的子组件?

    我加载一些包含自定义组件的 html 并将该内容挂载到父组件中的固定节点 不幸的是 我发现它们之间没有父子关系 因此动态插入的组件派发的事件无法被根vue接收 我创建了一把小提琴 任何帮助或建议都将受到赞赏 http jsfiddle ne
  • JavaScript 作为 HTML 属性是不好的做法吗?

    例子 https stackoverflow com a 372 89566 710887 https stackoverflow com a 37289566 710887 我看到这种情况越来越频繁地发生 我总是被教导要将 javascr
  • 使用查询字符串使缓存失效,这是不好的做法吗?

    在我制作的网站上 我通常使用查询字符串参数使 CSS 和 JS 的缓存无效 如下所示 注意 这是 chrome 检查器的屏幕截图 这些查询字符串都是由我在渲染到浏览器中时制作的小系统自动附加的 一位朋友现在告诉我 使用查询字符串的缓存效果不
  • 引导崩溃仅切换一次

    我再次在这里拉扯我的头发 所以我已经使用 jsFiddle 进行了引导崩溃 http jsfiddle net rasreye xtPtH 1 http jsfiddle net rasreye xtPtH 1 但是当我添加到我的网站时 它
  • 解析:删除用户及其相关记录

    我有带有实体的解析表 用户 默认类别 Commets 带有指向 User 实体的指针的类 我需要从实体 User 中删除用户及其所有评论 位于 Comments 实体中 现在我有 JS Cloud 代码 Parse Cloud define
  • JavaScript 可以在重新加载后保持任何状态吗?

    有没有办法让 JavaScript 通过重新加载来保存任何变量 如果用户点击重新加载按钮 一旦页面重新加载 JavaScript 是否会保留任何状态 建议 Cookie HTML 5 网络存储https www w3schools com
  • 如何从javascript中的base 64字符串获取图像文件大小? [复制]

    这个问题在这里已经有答案了 我有图像的 Base64 数据 data image png base64 iVBORw0KGgoAAAANSUhEUgAAAOcAAABnCAYAAAD7RFX4AAAACXBIWXMAAAsTAAALEwEA
  • 有效取消引用空指针的规则是什么?

    include
  • .catch() 的承诺被拒绝,但在 Promise.allSettled 中显示为已履行[重复]

    这个问题在这里已经有答案了 这是问题的简化版本 有一些承诺 但很少 then 链条 以及一个 catch 错误处理块 每个承诺都可能解决或拒绝 因此我使用Promise allSetted根据排列顺序和状态了解哪个承诺失败了 当所有承诺都解
  • 使用 Javascript 隐藏数据网格列?

    我有一个包含大约 20 列的 net 数据网格 我需要使用 JavaScript 通过单击按钮来切换列的可见性 有任何想法吗 您想使用 COLGROUP 来执行此操作 否则您必须应用样式every细胞开启everyrow 这将非常低效 并且
  • 禁用 WebSocket 证书验证

    我需要禁用 WebSocket 的证书验证 因为我使用的是自签名证书 我在这个问题中发现Websocket SSL 连接 https stackoverflow com questions 30902547 websocket ssl co
  • 如何获取 Firebase ID

    有人知道如何获取 Firebase 唯一 id 吗 我试过了name name key key 什么都不起作用 我可以看到数据 但不知道如何取回 id 我需要它 Create new customers into firebase func
  • 使用javascript在没有提交按钮的情况下将输入值显示到另一个页面

    我正在尝试将输入值的结果显示到另一个页面 但这个输入没有提交按钮 因此 我正在使用keyup来存储输入数据 我有2页 index1 php and index2 php 索引1 php
  • javascript 权限被拒绝访问属性

    我在从不同的 iframe 访问属性时遇到问题 我不断收到此权限被拒绝访问属性错误 我见过有人多次询问他们是否使用 file 但没有人 除了我 所以这个问题永远不会得到解决 我不会在网络上这样做 我所有帧的 src 都位于硬盘驱动器上的同一
  • 使重复的scrollBy像jQuery的动画scrollTop一样平滑

    如何使重复的scrollBy调用更平滑 就像使用jQuery的animatescrollTop制作动画一样 目前它是跳跃的 页面在不同的滚动位置之间跳转 我怎样才能让它更顺畅 这是滚动代码 window scrollBy 0 10 scro
  • 在 emberjs 中绑定子视图和集合

    我正在尝试渲染视图Team里面一个 outlet This Team视图由一个简单的Person视图 团队领导者 以及集合Person意见 团队成员 插座是通过调用设置的connectOutlet 在应用程序控制器上 虽然Person子视图

随机推荐