【问题标题】:Purpose of this Javascript prototype snippet此 Javascript 原型片段的目的
【发布时间】:2013-08-14 19:50:59
【问题描述】:

对不起,我不能更好地表达这个。但我遇到了如下代码:

MyObject.prototype = Object.create(MyObject.prototype);
MyObject.prototype.constructor = MyObject;

而且我似乎无法弄清楚它的作用。 MyObject 在它上面定义是这样的:

function MyObject(options) {
    this.someProp = someDefault;
    this.otherProp = process(options.something);
    // etc...
}

它总是被称为构造函数。我只是想知道前两行提供了什么好处,以及它是否是 Javascript 中的已知模式。

【问题讨论】:

  • 你确定作业两边都应该是MyObject吗?
  • 这只是向 MyObject 实例的原型链添加了一层(无用的)间接性......你在哪里找到的代码?
  • 说真的,为什么人们会这样写JS?
  • 目前我不想在这里做出任何判断。我多年来一直在编写 Javascript 编程,但很遗憾地说我仍然没有深入了解原型。只是想弄清楚..
  • 好的,但你确定MyObject.prototype = Object.create(MyObject.prototype); 不是真的MyObject.prototype = Object.create(MyOtherObject.prototype);

标签: javascript


【解决方案1】:

我似乎无法弄清楚它的作用

它创建一个新对象,该对象通过Object.create从[旧]MyObject.prototype继承,然后用它覆盖MyObject.prototype。它还显式添加了一个实际上应该已经存在的.constructor 属性。

我只是想知道前两行有什么好处

没有,除非在 sn-p 之前有人损坏了原型(如 MyObject.prototype = Object.prototype)并且这是试图修复它。

…如果它是 Javascript 中的已知模式。

不是这样的。使用Object.createinheritance between constructor-defined "classes" is a known pattern 设置原型链,但是构造函数在分配的每一侧都会不同。

【讨论】:

    【解决方案2】:

    提供的两行代码似乎是对使用原型继承的错误尝试,但我知道你在哪里以及你想要完成什么。

    我们知道,在 JavaScript 中有两种方法可以定义具有属性和方法作为成员的对象——对象字面量表示法和函数表示法。使用对象字面量表示法,我们无法立即访问 new 关键字(将其想象为在 Java 或 C# 中使用抽象类)。使用函数表示法,我们可以访问new 关键字,因为作为函数的对象的初始声明用作我们的构造函数。

    在 ECMAScript 5 中,Object 对象被赋予了一个名为 create 的方法,它为开发人员提供了一种简单的方法,可以从使用对象文字符号声明的现有对象创建新对象。 (参见文档here)。但是,以函数表示法创建的对象在此方法中存在问题,因为它们是 Function 对象。 Object.create 方法是使用简单继承的好方法,允许访问基本属性和方法。

    使用函数表示法,一旦使用了new 关键字,结果就不是一个函数,而是一个对象。例如,我可以测试这个:

    var Obj = function(){};
    console.log(typeof Obj) // "function"
    
    console.log(typeof new Object()); // "object"
    

    因此,你只能继承一次(意味着子对象不能派生):

    var MyObject = new Object();
    var anotherObj = new MyObject() // throws exception
    

    要缓解这个问题,你需要遵循三个步骤:

    1. 以函数表示法创建您的子对象(这样您就可以使用 new 关键字创建它的新实例并从中继承)。
    2. 将子对象的原型(对象)设置为基础对象(也将是对象)的新实例的结果。
    3. 将子对象(恰好位于对象的原型上)的构造函数设置回引用自身的函数(这是实例化之前的函数)。如果你不这样做,构造函数将保持一个对象,不能产生新的实例。

    从这里,您可以使用该模式创建子对象和父对象的新实例并从两者派生。这是一个实际的例子:

    var Vehicle = function(){};
    Vehicle.prototype.start = function() {
       return this.make + " " + this.model + " " + "started";
    }
    
    var Car = function(color, make, model) {
       this.color = color;
       this.make = make;
       this.model = model;
    }
    Car.prototype = new Vehicle();
    Car.prototype.constructor = Car; 
    
    var myCar = new Car("red", "chevy", "aveo");
    myCar.start(); //"chevy aveo started"
    

    【讨论】:

    • 你可以使用Object.create 来设置继承,它被大量使用了。如果 Vehicle 构造函数需要在创建 Car 实例之前未知的参数怎么办? Car.prototype = Object.create(Vehicle.prototype);Car.prototype.constructor=Car;
    【解决方案3】:

    我真的看不出这样做有什么好处。

    它所做的是为新对象提供以前的对象方法。但它来自同一个对象......

    这是一个很好的 JS 继承示例:

    http://jsfiddle.net/aDCmA/2/

    var App = (function(){
        var Being = function() {
            this.living = true;
            this.breathes = function () {
                return true;
            };
        };
    
        var Robert = function() {
            this.blogs = true;
            this.getsBored = function () {
                return "You betcha";
            }
        };
        Robert.prototype = new Being();
    
        return {
            Being: Being,
            Robert: Robert,
            being: function(){ return new Being(); },
            robert: function(){ return new Robert(); }
        }
    }());
    

    这是另一个类似的问题:inherit prototype methods from other classes without overriding own prototype methods

    感谢 Robert Nyman 最初写博客:http://robertnyman.com/2008/10/06/javascript-inheritance-how-and-why/

    【讨论】:

    • Robert.prototype = new Being(); 不是继承的好例子。 What is the reason (not) to use the 'new' keyword here?
    • 因为如果你决定添加到 Robert 的原型中,它会覆盖 Beings 方法。
    • 如果你能提供一个使用原型的 JS 继承的方法或链接,我对更好的方法很感兴趣。老实说,这些天在我的工作中,我从来没有写过 Vanilla JS,这些问题/讨论令人耳目一新。
    • @MichaelBenin 在这个答案stackoverflow.com/questions/16063394/… 中,我试图涵盖 JS 构造函数的基础知识。
    【解决方案4】:

    让我们逐行查看:

    MyObject.prototype = Object.create(MyObject.prototype);
    

    这会将MyObject.prototype 重新定义为继承自MyObject.prototype 的对象。这是不寻常的,因为从自身继承是没有意义的。

    MyObject.prototype.constructor = MyObject;
    

    由于上一行覆盖了MyObject.prototype,这只是修复了过程中丢失的构造函数属性。

    我可以想到一个可能有用的场景:如果之前的某些代码与MyObject.prototype 混淆了,例如将另一个构造函数的原型分配给它:

    MyObject.prototype = SomethingElse.prototype; // wrong way to do inheritance.
    

    那么您发布的代码将尝试修复它。

    【讨论】:

      【解决方案5】:

      这是完全有效的 Javascript。

      任何 javascript 函数(比如Func)都可以用作构造函数,并且构造函数调用还需要prototype 属性(即F.prototype 或与函数关联的原型)。因此(几乎)每个函数都有一个原型属性。此属性的值(即Func.prototype)。

      现在与函数关联的这个原型的值是一个对象本身,它有一个称为构造函数的单个不可枚举属性。而这个构造函数属性的值就是函数对象(即F本身)。

      举个例子。

      假设我构造了一个函数Func

      var 函数 = 函数() { //你的定义 };

      现在既然可以作为构造函数调用它,它必须有一个prototype 属性Func.prototype 让我们称之为proto

      原型 = Func.prototype;

      现在原型有一个称为构造函数的单一属性(即不可枚举)。这个构造函数的值等于函数对象本身。

      不要相信我这样检查它

      Func.prototype.constructor === Func // =>true

      任何函数都会返回 true

      现在从您解释的代码中: 所以基本上这两行

      MyObject.prototype = Object.create(MyObject.prototype); MyObject.prototype.constructor = MyObject;

      正在修改 prototye 的值,使其具有一个定义为 MyObject 的构造函数属性。但这无论如何都会在正常情况下发生。但原因可能是对象的prototype 可能已经从它继承的类中更早地更改了。在那种情况下,这两行是否有意义。

      希望有帮助:)

      【讨论】:

        猜你喜欢
        • 2015-01-24
        • 2020-05-21
        • 2014-08-29
        • 2016-09-19
        • 2020-07-10
        • 2017-03-09
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多