学习.prototype

8
编辑:对于未来看到这篇文章的人们,我强烈推荐使用这个网站来学习JavaScript,如果你是从传统面向对象编程的背景过来的话。那些类似UML的图表非常棒。

我仍然无法理解JavaScript中的.prototype属性。它只是一个指向另一个对象的引用吗?还是一种指向另一个对象指针的引用?作为一个C/C++/x86的开发者,我无法看出它的工作原理。让我们来看看一些例子,以便更好地指出我的错误并了解事物的运作方式。我甚至不知道其中一些是否是有效的语法。ObjectFunction分别是全局对象/函数对象。

1                                        // Global.prototype = ??
2                                        // Function.prototype = ??
3 
4   var obj1 = {};                       // obj1.prototype = Object 
5   obj2 = {};                           // obj2.prototype = Object
6
7   var func1 = function() {};           // func1.prototype = Function
8   func2 = function() {};               // func2.prototype = Function
9   function func3() {}                  // func3.prototype = Function  
10

我很困惑。

11  var Foo = function() { this.prop1 = 0; }
12  var foo = new Foo();                 // should it be 'new Foo' or 'new Foo()'?
13  // Foo.prototype = Function
14  // foo.prototype = Foo
15  var Goo = function() { this.prop2 = 0; }
16  var goo = new Goo();
17  // goo.prototype = Goo
18  goo.prototype = new Foo();
19  // goo.prop1 now exists ?

我也不理解在原型之间进行交换。

20  function A () {
21     this.prop1 = 1;
22  }
23  function B () {
24     this.prop2 = 2;
25  }
26  function C () {
27     this.prop3 = 3;
28  }
29  C.prototype = new B();
30  var c = new C();
31  // c.prop1 = 1
32  // c.prop2 = 2
33  // c.prop3 = undefined
34  C.prototype = new A();
35  // c.prop2 = 2???
36  // c.prop3 = 3

我无法理解这个概念。我不太明白。我不明白克隆对象如何获得它们自己的本地数据副本,但是对原始对象(原型)进行的更改会以某种方式影响到克隆体。我一直在使用 FigureBug 进行尝试,但是我无法想出符合每个示例的一致性的想法。
C++ 可能是一个庞大的怪物,但至少我知道确切的情况。这里......我只能猜测......可能是一种新的范例。无论如何,如果您能帮助我,非常感谢......我在 .prototype 上感到很困扰。

请在此问题中检查我的答案:http://stackoverflow.com/questions/17047025/trying-to-understand-javascript-inheritence/17049716#17049716 - Hoffmann
如果你请求 obj.x 而 obj 没有自己的 x 属性,JS 将会检查 obj.prototype.x 是否存在,如果存在则返回它,否则返回 undefined。可以将其视为编程中的呼叫转移,原型是你可以尝试访问数据的备用号码。由于这是一个不同的电话,如果备用号码被销毁,你仍然可以拨打主线。 - dandavis
@dandavis 好的,我明白了这种情况。但我不理解.prototype引用的是什么,默认设置是什么,以及当我开始交换原型时会发生什么。 - gone
@gone。".prototype"引用了不同的对象,一个普通的旧对象,没有什么神奇的。默认情况下,构造函数具有不同于实例的原型。对于构造函数,它默认为{},而对于对象,则为Object.prototype。如果您使用new,则相当于说inst=Con.call({}},将Con中所有“this.”绑定传递给空白对象。new还将实例的 .prototype 属性硬编码为指向其构造函数的 .prototype 属性。 - dandavis
@Bergi:是的,instance.prototype本质上是指Constructor.prototype,如果有instance.prototype这样的东西的话。例如:function A(){this.a=1;} A.prototype={b:2}; var a=new A(); Object.getPrototypeOf(a)==A.prototype; - dandavis
显示剩余3条评论
2个回答

4

哇,这是很多问题。让我们逐个解答。

它只是指向另一个对象的引用吗?还是指向指向另一个对象的指针?

JavaScript 中没有指针。然而,一个持有 "对象" 的变量或属性实际上持有对该对象的引用,因此其他变量可以持有对同一对象的引用。

Global.prototype = ??
全局对象(如果您想要的话是window),在其中定义了所有全局变量,没有原型(不用关心某些环境中的异常情况)。
引用:

我仍然无法理解 Javascript 中的 .prototype 属性。

.prototype 属性是所有函数对象都具有的属性,指向它们的原型对象(一个普通对象)。
您不能将其与每个对象都具有的内部 prototype 引用混淆。该 prototype 指向查找属性的对象,该对象本身没有这些属性。
Function.prototype = ??
这是所有函数对象继承的对象。它包含像callbind这样的内容。
var obj1 = {};              // obj1.prototype = Object
var func1 = function() {};  // func1.prototype = Function

是的,有点像。我认为你掌握了概念,但不知道术语。虽然func.prototype是另一回事,但obj.prototype属性甚至不存在。但是,你指的是内部的原型 - 我们可以通过Object.getPrototypeOf函数访问它们。它们不是指构造函数,而是它们的原型对象。这里是更正:

Object.getPrototypeOf(obj1) === Object.prototype
Object.getPrototypeOf(func1) === Function.prototype

是应该使用'new Foo'还是'new Foo()'?

这没有关系,它们是等效的。只有在想要传递参数时才需要明确使用括号。

var Foo = function() { this.prop1 = 0; }
var foo = new Foo();

你的假设是正确的,但表达方式有误。让我们详细解释一下。

上面提到了“原型对象”,它们是什么?它们是每个函数隐式创建的普通对象。在这种情况下,它是Foo.prototype - 一个空对象。因此,我们在这里处理三个对象: Foo构造函数,它的Foo.prototype原型对象和foo实例。

foo有什么特别之处?它是new运算符执行的第一件事情。当一个函数作为构造函数被调用时 - 使用new - 它的.prototype属性被访问,并且使用其内部的原型创建一个新对象。这就是神奇的地方。然后在新实例上调用函数,以便this是新对象;在您的情况下,它在实例上创建.prop1属性。然后返回结果(并分配给foo)。

现在如何利用这个魔法呢?关键是在原型对象上创建属性,然后将其继承。

// modify `Foo.prototype`, the object which `foo` inherits from:
Foo.prototype.prop2 = 1;
console.log(foo.prop2); // 1!

我也不理解交换原型的概念。

问题在于这几乎是不可能的。一旦实例化,对象的原型链就非常静态了。然而,你通常并不需要这样做。

goo.prototype = new Foo();
那不起作用是因为.prototype属性不是您期望的属性。
var c = new C();
C.prototype = new A();

这只能起到一定的作用。看一下上面提到的new做了什么 - 它只在构造函数中查找.prototype属性一次。内部的prototype就会被锁定 - 您不会改变c实例。但是,如果现在创建一个新的实例var d = new C(),那么它将继承A实例。

希望这可以帮助您。如果您还有其他问题,请留言。


抱歉我回复晚了。但是没错,这就是我需要的:“问题在于这几乎是不可能的”——连同你提到的其他所有内容。非常感谢,我认为这是顶尖的答案。 - gone

2
原型是用于在对象本身未定义属性时进行搜索,仅在读取时使用。写操作始终在对象本身上进行。
当您调用时,
// An instance of Foo ({prop1:0}) is set as the 
// prototype (to all instances of Goo)
var goo = new Goo();

// 0, from the prototype
console.log(goo.prop1); 

// Read from the object itself (set in Goo's constructor)
console.log(goo.prop2); 

// New instance, same prototype as goo
var goo2 = new Goo();
console.log(goo2.prop1) ; // 0, still from the prototype

// Setting is always at the object level, not the prototype
goo.prop1 = 5;

// goo2 is still reading from the prototype
console.log(goo2.prop1); 

注意:

不要实例化父类来设置继承关系。点击此处了解详情。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接