这张图再次表明,每个对象都有一个原型。构造函数
function Foo也有自己的__proto__,也就是function .prototype,
而它又通过__proto__属性再次引用
Object.prototype。因此,重复,Foo。原型只是一个显式
Foo的属性,引用b和c对象的原型。
var b = new Foo(20);
var c = new Foo(30);
__proto__和prototype之间有什么区别?
这一数据来自dmitrysoshnikov.com网站。
注:上述2010年的文章现在有第二版(2017年)。
我知道,我迟到了,但让我试着简化一下。
假设有一个函数
function Foo(message){
this.message = message ;
};
console.log(Foo.prototype);
Foo函数将有一个原型对象链接。所以,无论何时我们在JavaScript中创建一个函数,它总是有一个原型对象链接到它。
现在让我们继续使用函数Foo创建两个对象。
var a = new Foo("a");
var b = new Foo("b");
console.log(a.message);
console.log(b.message);
现在我们有两个对象,对象a和对象b。它们都被创建了
使用构造函数Foo。记住,构造函数在这里只是一个词。
对象a和b都有message属性的副本。
这两个对象a和b链接到构造函数Foo的原型对象。
在对象a和b上,我们可以在所有浏览器中使用__proto__属性访问Foo prototype,在IE中我们可以使用Object.getPrototypeOf(a)或Object.getPrototypeOf(b)
现在,Foo。Prototype, a.__proto__和b.__proto__都表示同一个对象。
b.__proto__ === Object.getPrototypeOf(a);
a.__proto__ === Foo.prototype;
a.constructor.prototype === a.__proto__;
所有这些都将返回true。
如我们所知,在JavaScript中属性可以动态添加。我们可以向对象添加属性
Foo.prototype.Greet = function(){
console.log(this.message);
}
a.Greet();//a
b.Greet();//b
a.constructor.prototype.Greet();//undefined
如你所见,我们在Foo中添加了Greet()方法。但它可以在a和b或任何其他使用Foo构造的对象中访问。
在执行a.Greet()时,JavaScript将首先在对象a的属性列表中搜索Greet。如果没有找到,它将在a. Since a.__proto__和Foo的__proto__链中上升。prototype是同一个对象,JavaScript会找到Greet()方法并执行它。
我希望,现在prototype和__proto__被简化了一点。
这个问题有很多很好的答案,但为了概括和紧凑形式的答案,我添加了以下内容:
我们必须考虑的第一件事是,当JS发明的时候,计算机的内存非常低,所以如果我们需要一个进程来创建新的对象类型,我们必须考虑内存性能。
因此,他们在内存的独立部分,定位由特定对象类型创建的对象需要的方法,而不是每次我们创建一个新对象时,在对象之外存储方法。
因此,如果我们用JS的新特性重新定义新的运算符和构造函数概念,我们有以下步骤:
和空对象。(这将是对象类型实例化的最终结果)
let empty={}
我们已经知道,由于内存性能原因,对象类型实例所需的所有方法都位于构造函数的prototype属性上。(函数也是对象,所以它们可以有属性)
因此,我们将空对象的__protp__引用到这些方法存在的位置。
(我们将概念上作为构造函数使用的函数命名为构造函数。
empty.__proto__ = constructor.prototype
我们必须初始化对象类型值。
在JS中的函数与对象断开连接。使用点表示法或函数对象的bind call apply等方法,我们必须知道“函数的上下文是什么”。
let newFunc = constructor.bind(empty)
现在我们有了一个新函数,它有一个空对象作为这个context。
执行此函数后。空对象将被填充,如果定义的构造函数函数没有返回,类型object的实例化结果将是这个空对象(就好像这将是该过程的结果一样)
所以正如你所看到的,__proto__是一个对象的属性,它引用了其他对象(在JS中函数也是对象)原型对象属性,它由跨特定对象类型的实例使用的属性组成。
正如你可以从短语中猜到的那样,函数是对象,函数也有__proto__属性,因此它们可以引用其他对象的prototype属性。这就是原型继承的实现方式。
只有一个对象用于原型链接。该对象显然有一个名称和值:__proto__是它的名称,prototype是它的值。这是所有。
为了让它更容易理解,看看这篇文章顶部的图表(由dmitry soshnikov绘制的图表),你永远不会发现__proto__的值指向prototype以外的其他东西。
要点是:__proto__是引用原型对象的名称,prototype是实际的原型对象。
这就像是在说:
let x = {name: 'john'};
X是对象名称(指针),{name: 'john'}是实际对象(数据值)。
注意:这只是一个非常简单的提示,说明它们在较高的水平上是如何相互关联的。
更新:下面是一个简单具体的javascript示例,以便更好地说明:
let x = new String("testing") // Or any other javascript object you want to create
Object.getPrototypeOf(x) === x.__proto__; // true
这意味着当Object.getPrototypeOf(x)为我们获取x的实际值(这是它的原型)时,正是x的__proto__所指向的。因此__proto__确实指向x的原型。因此__proto__引用x (x的指针),而prototype是x的值(它的原型)。
我希望现在大家都明白了。