在使用继承时,构造函数和原型对象有什么区别吗?
Is there any difference between constructor function and prototype object when using inheritance?
考虑以下JavaScript代码片段:
function foo() {
this.bar = function() { };
}
// or... (if we used an empty constructor function)
foo.prototype.bar = function() { };
当我这样做的时候有什么不同呢?
function baz() {
}
baz.prototype = new foo();
在这两种情况下,baz
最终都有成员bar
,但有什么区别呢?我为什么要在不同的地方做这件事?
区别在于属性在原型链中的位置。
假设我们有f = new foo();
和b = new baz()
。然后我们有以下情况:
不使用原型的foo
定义:
+-----------+ +---------------+
| f | | foo.prototype |
| __proto__-+---->| constructor |
| bar | | |
+-----------+ +---------------+
bar
是对象本身的属性(f.howOwnProperty('bar')
返回true
)。
如果你把属性赋值给原型,情况是:
+-----------+ +---------------+
| f | | foo.prototype |
| __proto__-+---->| constructor |
| | | bar |
+-----------+ +---------------+
f
没有自己的属性bar
,但该属性与所有其他foo
实例共享。
与第二个代码片段类似,结果是
+-----------+ +---------------+ +---------------+
| b | | foo instance | | foo.prototype |
| __proto__-+---->| __proto__ -+---->| constructor |
| | | bar | | |
+-----------+ +---------------+ +---------------+
或
+-----------+ +---------------+ +---------------+
| b | | foo instance | | foo.prototype |
| __proto__-+---->| __proto__ -+---->| constructor |
| | | | | bar |
+-----------+ +---------------+ +---------------+
你为什么要这样做?
这主要是关于结构和不浪费内存。可以在构造函数中向对象添加函数:
function Foo() {
this.bar = function() {};
}
,但这也意味着Foo
的每个实例都有它自己的函数,也就是说,f1.bar === f2.bar
是false
,尽管两个函数都在做完全相同的事情。
使用原型为您提供了一种清晰的方式来分离所有实例的公共属性和特定于实例的属性。
最后,它"只是"继承,这是软件开发中的一个概念(像聚合一样),可以在任何有意义的地方使用。第二个代码片段基本上意味着baz
是-a foo
,所以baz
实例除了自己的属性外,还具有与foo
实例相同的属性(继承)。
一个很大的区别是,如果你改变了原型的属性,这些改变将适用于所有的实例,包括那些已经存在的,而如果你改变了一个在构造函数中创建的属性,它只会在你改变它的实例中改变它。
关于在构造函数中设置bar
导致每个实例都有自己的函数副本的其他一些答案:如果您在构造函数中有一个函数表达式,如问题中的代码所示,那么这是正确的,但如果您像这样分配函数引用,则不正确:
function myFunction() {}
function foo() {
this.bar = myFunction;
}
在这种情况下,所有实例将有一个bar
属性引用相同的函数-但一个单独的实例仍然可以将其bar
属性分配给其他东西,而不影响其他实例
添加到现有答案:
创建原型函数将允许继承对它的更改。例如,如果你写
function foo(){}
foo.prototype.bar = function(){return 1};
function baz(){}
baz.prototype = new foo();
new baz().bar(); //returns 1
foo.prototype.bar = function(){return 2};
new baz().bar(); //returns 2
然而,把它放在构造函数中会让从它继承的其他对象也"拥有"该函数,但该函数不被继承。
function foo(){this.bar = function(){return 1};}
function baz(){}
baz.prototype = new foo();
new baz().bar(); //returns 1
foo.prototype.bar = function(){return 2};
new baz().bar(); //returns 1
我想我回答的问题是正确的,否则请告诉我。
区别在于使用prototype只会产生一个实例。
例如,baz。在一个例子中Bar和baz是一样的。酒吧在另一个。它们将在'foo'实例中共享值:
function foo() {
var x = 0;
this.bar = function() {};
this.getVal = function() {
return x;
}
this.setVal = function(val) {
x = val;
}
}
function baz() {}
baz.prototype = new foo();
var a = new baz(),
b = new baz();
a.setVal("1234")
console.log(b.getVal()); // prints '1234'
http://jsfiddle.net/jonathon/7GtRD/如果a
和b
直接调用'foo',那么它们不会在foo
内共享值。然而,这是设置this.bar
和使用原型创建bar之间略有不同的地方。
使用原型将创建一个bar
实例。所以a.bar
和b.bar
是一样的。如果你用另一种方法,它们将是两个不同的函数(做同样的事情)。
- 全局变量和全局对象的属性之间有什么区别吗
- 在Javascript中重新分配对象变量时,原始对象会发生什么
- 确定var是否是javascript中的elementFinder对象的方法是什么
- 在这个使用hasOwnProperty的对象扩展程序中有一个错误,I'我不确定那个bug是什么,也不确定这个扩展
- 用javascript修复这个JSON对象字符串最干净的方法是什么
- 从AngularJs获取谷歌地图对象的正确方法是什么
- 什么是“;原型;通过JavaScript中的Object Literal Notation创建的对象的链接
- 克服错误的更优雅的方法是什么:需要对象说明符.当通过JXA通过Messages发送SMS时,参数没有对象说明符
- XMLHttpRequest对象的open()和send()方法之间有什么区别
- 这两种不同的创建对象文字的方法有什么区别
- 什么'是从对象列表中一次编辑一个对象的正确Angular/Firebase方法
- 我需要使用什么语法来向一个对象的成员添加一个临时数组,该成员等同于一个字符串的通用列表
- 使用查询将对象数组发布到asp.net-mvc控制器操作的正确方法是什么
- 在jquery中,从同一对象的属性设置输入字段和标签的正确方法是什么
- 什么是'值是引用'表示JavaScript对象
- localStorage-对象的getter-, setter-方法的目的是什么?
- 什么是 ClojureScript 类似地将不存在的对象值设置为 JavaScript 中的 null
- 返回多个变量的 JavaScript 函数:数组与对象.最佳实践是什么
- Javascript:将类/对象引用设置为 NULL,内存中的子对象/类会发生什么
- 通过传递日期来创建Javascript Date对象?什么是dateString