object.create和prototype之间的关系

时间:2014-12-13 22:00:15

标签: javascript prototype

我有两个代码块,它们似乎也一样。两者之间的唯一区别是一个具有Object.create()而另一个没有。我错过了不使用它的一些潜在后果吗?

First Chunk,不使用Object.create:



function Rectangle(width, height) {
  this.height = height;
  this.width = width;
}

Rectangle.prototype.area = function() {
  return this.width * this.height;
};

function Square(side) {
  Rectangle.call(this, side, side);
}

Square.prototype = Rectangle.prototype;

Square.prototype.constructor = Square;

var sq = new Square(5);
console.log(sq.area())




Second Chunk,使用Object.create:



function Rectangle(width, height) {
  this.height = height;
  this.width = width;
}

Rectangle.prototype.area = function() {
  return this.width * this.height;
};

function Square(side) {
  Rectangle.call(this, side, side);
}

Square.prototype = Object.create(Rectangle.prototype);

Square.prototype.constructor = Square;

var sq = new Square(5);
console.log(sq.area())




2 个答案:

答案 0 :(得分:2)

他们不一样。使用这一行,两个构造函数的原型是相同的对象。

Square.prototype = Rectangle.prototype;

这意味着Square上的任何方法也会显示在Rectangle上。因此,使用Object.create()分配继承自 Rectangle.prototype的新对象。这样,方法将添加到该对象,而不是Rectangle.prototype

答案 1 :(得分:1)

如果您想浏览帖子,我会使用斜体标记与您的示例直接相关的信息。

原型继承

原型继承的工作原理如下:

  1. 每个对象o都有一个原型o.__proto__
  2. 当您在对象p上请求属性o时,则:
    1. 如果对象o具有属性p,则会返回o[p]
    2. 否则:
      1. 如果o.__proto__ !== null,则返回o.__proto__[p]
      2. 否则,将返回undefined
  3. 此行为是递归的,创建了一个所谓的prototype chain。请参阅以下示例代码:

    var o1 = { a: 1 },
        o2 = { b: 2 },
        o3 = { c: 3 };
    o2.__proto__ = o1;
    o3.__proto__ = o2;
    o3.a + o3.b + o3.c == 6;   // true
    

    这基本上就是原型的全部内容。应该注意__proto__是访问原型的deprecated方式。 ECMAScript提供了三种其他(标准)方式:

    • 函数的prototype属性,
    • Object.create()方法,
    • Object.getPrototypeOf()Object.setPrototypeOf()方法。

    现在让我们看看这些。

    函数的prototype属性

    基础知识

    直到ECMAScript 5,函数的prototype属性是处理原型的唯一方法。它的工作原理如下:

    1. 每个函数f都有prototype属性。
    2. 调用new f(arg1, arg2, ..., argN)时,则:
      1. 创建一个空的新对象o,其中o.__proto__ == f.prototype
      2. f的上下文中使用参数arg1, arg2, ..., argN调用函数o
      3. 如果函数f未返回任何值,则返回o
    3. 这种行为基本上模仿了经典继承。使用通过调用f.prototype获得的对象将继承的方法填充new f对象,并将f本身用作构造函数。

      prototype.constructor属性

      就构造函数而言,f.prototype对象默认包含f.prototype.constructor属性,该属性等于f。这可以通过直接检出constructor属性或使用instanceof语法糖来找出对象的构造函数:

      var o = new f;
      o.constructor == f;        // true
      o instanceof f;            // true
      

      在您的第一个示例中,您将prototype.constructorSquare的{​​{1}}更改为Rectangle。因此:

      Square

      这通常不是你想要的。

      扩展内置对象的原型

      扩展内置函数/构造函数的var o = new Rectange; o instanceof Rectangle; // false o instanceof Square; // true 对象(prototypeStringArrayNumber,...)可以是这个原则的有用应用:

      RegExp

      Array.prototype.last = function() { return this[this.length - 1]; }; [ 1, 2, 3, 4, 5 ].last(); // 5 方法

      Object.create()方法是ECMAScript 5的一部分,允许您使用指定的原型创建新对象,而无需创建构造函数。这是使用Object.create()方法重写的初始Object.create()示例代码:

      __proto__

      使用Object.create()的第二个参数设置对象的属性可能会非常冗长。如果您不需要ECMAScript 5提供的灵活性(创建不可变属性,具有setter和getter的属性,......),您可以省略第二个参数并像往常一样用对象填充对象:

      var o1 = Object.create(null, {
            a: {
              writable: true,
              configurable: true,
              value: 1
            }
          }), o2 = Object.create(o1, {
            b: {
              writable: true,
              configurable: true,
              value: 2
            }
          }), o3 = Object.create(o2, {
            c: {
              writable: true,
              configurable: true,
              value: 3
            }
          });
      o3.a + o3.b + o3.c == 6;   // true
      

      在您的第二个示例中,您将var o1 = Object.create(null); o1.a = 1; var o2 = Object.create(o1); o2.b = 2; var o3 = Object.create(o2); o3.c = 3; o3.a + o3.b + o3.c == 6; // true 的{​​{1}}属性更改为prototype,然后将Square设置为Object.create(Rectangle.prototype)。由于Object.create()方法返回一个空对象,因此您不会通过赋值来覆盖Square.prototype原型中的任何内容,因此:

      Rectangle.prototype

      Rectanglevar o1 = new Rectange; var o2 = new Square; o1 instanceof Rectangle; // true o2 instanceof Square; // true 方法

      Object.getPrototypeOf()Object.setPrototypeOf()方法是ECMAScript 6 draft的一部分,只是Object.getPrototypeOf()属性的getter和setter。这是使用Object.setPrototypeOf()方法重写的初始Object.setPrototypeOf()示例代码:

      __proto__