我有两个代码块,它们似乎也一样。两者之间的唯一区别是一个具有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())

答案 0 :(得分:2)
他们不一样。使用这一行,两个构造函数的原型是相同的对象。
Square.prototype = Rectangle.prototype;
这意味着Square
上的任何方法也会显示在Rectangle
上。因此,使用Object.create()
分配继承自 Rectangle.prototype
的新对象。这样,方法将添加到该对象,而不是Rectangle.prototype
。
答案 1 :(得分:1)
如果您想浏览帖子,我会使用斜体标记与您的示例直接相关的信息。
原型继承的工作原理如下:
o
都有一个原型o.__proto__
。p
上请求属性o
时,则:
o
具有属性p
,则会返回o[p]
。o.__proto__ !== null
,则返回o.__proto__[p]
。undefined
。此行为是递归的,创建了一个所谓的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
属性是处理原型的唯一方法。它的工作原理如下:
f
都有prototype
属性。new f(arg1, arg2, ..., argN)
时,则:
o
,其中o.__proto__ == f.prototype
。f
的上下文中使用参数arg1, arg2, ..., argN
调用函数o
。f
未返回任何值,则返回o
。这种行为基本上模仿了经典继承。使用通过调用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.constructor
和Square
的{{1}}更改为Rectangle
。因此:
Square
这通常不是你想要的。
扩展内置函数/构造函数的var o = new Rectange;
o instanceof Rectangle; // false
o instanceof Square; // true
对象(prototype
,String
,Array
,Number
,...)可以是这个原则的有用应用:
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
Rectangle
和var 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__