__proto__VS. JavaScript中的原型

这张图再次表明每个对象都有一个原型。构造函数功能Foo也有自己的__proto__,Function.prototype,并且反过来也通过其__proto__属性再次引用到Object.prototype.因此,重复,Foo.prototype只是一个明确的Foo的属性,指的是b和c对象的原型。

var b = new Foo(20);var c = new Foo(30);

__proto__prototype有什么区别?

输入图片描述

这个数字取自dmitrysoshnikov.com

注意:现在有第二版(2017)上述2010年的文章。

269209 次浏览

__proto__是查找链中用于解析方法的实际对象,等等。prototype是使用new创建对象时用于构建__proto__的对象:

( new Foo ).__proto__ === Foo.prototype( new Foo ).prototype === undefined

prototype是Function对象的属性。它是由该函数构造的对象的原型。

__proto__是对象的内部属性,指向其原型。当前标准提供了等效的Object.getPrototypeOf(obj)方法,尽管事实上的标准__proto__更快。

您可以通过比较函数的prototype和对象的__proto__链来找到instanceof关系,您可以通过更改prototype来打破这些关系。

function Point(x, y) {this.x = x;this.y = y;}
var myPoint = new Point();
// the following are all truemyPoint.__proto__ == Point.prototypemyPoint.__proto__.__proto__ == Object.prototypemyPoint instanceof Point;myPoint instanceof Object;

这里Point是一个构造函数,它在程序上构建一个对象(数据结构)。myPointPoint()构造的对象,因此Point.prototype当时保存到myPoint.__proto__

prototype属性是在声明函数时创建的。

例如:

 function Person(dob){this.dob = dob};

Person.prototype属性在声明上述函数后在内部创建。许多属性可以添加到Person.prototype中,这些属性由使用new Person()创建的Person实例共享。

// adds a new method age to the Person.prototype Object.Person.prototype.age = function(){return date-dob};

值得注意的是,默认情况下Person.prototypeObject字面量(可以根据需要进行更改)。

使用new Person()创建的每个实例都有一个指向Person.prototype__proto__属性。这是用于遍历以查找特定对象的属性的链。

var person1 = new Person(somedate);var person2 = new Person(somedate);

创建Person的2个实例,这2个对象可以调用Person.prototypeage方法作为person1.ageperson2.age

在上图中,您可以看到FooFunction Object,因此它有一个__proto__链接到Function.prototype,而Function.prototype又是Object的实例,并且有一个__proto__链接到Object.prototype。原始链接在这里结束,Object.prototype中的__proto__指向null

任何对象都可以访问其原始链中由__proto__链接的所有属性,从而形成原型继承的基础。

__proto__不是访问原型链的标准方法,标准但类似的方法是使用Object.getPrototypeOf(obj)

下面的instanceof运算符代码可以更好地理解:

对象instanceof当对象是类的实例时,类运算符返回true,更具体地说,如果在该对象的原型链中找到Class.prototype,则该对象是该类的实例。

function instanceOf(Func){var obj = this;while(obj !== null){if(Object.getPrototypeOf(obj) === Func.prototype)return true;obj = Object.getPrototypeOf(obj);}return false;}

上述方法可以称为:instanceOf.call(object, Class),如果对象是Class的实例,则返回true。

一个很好的想法是…

prototypeconstructor函数使用。它应该被称为"prototypeToInstall",因为它就是这样。

__proto__是对象上的“安装原型”(是通过所述constructor()函数在对象上创建/安装的)

我的理解是:__proto__和原型都是为原型链技术服务的。不同的是,用下划线命名的函数(如__proto__)根本不是针对开发人员显式调用的。换句话说,它们只是为了一些机制,如继承等。它们是“后端”。但是没有下划线的函数是为显式调用而设计的,它们是“前端”。

另一种理解它的好方法:

var foo = {}
/*foo.constructor is Object, so foo.constructor.prototype is actuallyObject.prototype; Object.prototype in return is what foo.__proto__ links to.*/console.log(foo.constructor.prototype === foo.__proto__);// this proves what the above comment proclaims: Both statements evaluate to true.console.log(foo.__proto__ === Object.prototype);console.log(foo.constructor.prototype === Object.prototype);

仅在支持IE11__proto__之后。在该版本之前,例如IE9,您可以使用constructor来获取__proto__

原型VS.__proto__VS.[[原型]]

创建函数时,会自动创建一个名为原型的属性对象(您不是自己创建的),并将其附加到函数对象(constructor)。
说明:这个新的原型对象还指向或具有指向本机JavaScript对象的内部私有链接。

示例:

function Foo () {this.name = 'John Doe';}
// Foo has an object property called prototype.// prototype was created automatically when we declared the function Foo.Foo.hasOwnProperty('prototype'); // true
// Now, we can assign properties and methods to it:Foo.prototype.myName = function () {return 'My name is ' + this.name;}

如果您使用new关键字从Foo创建一个新对象,您基本上是在创建(除其他外)一个新对象,该对象对我们之前讨论的函数Foo的原型具有内部或专用链接

var b = new Foo();
b.[[Prototype]] === Foo.prototype  // true


私人链接到该函数的对象称为双括号原型或只是[[Prototype]]。许多浏览器为我们提供了公共链接到它,称为__proto__

更具体地说,__proto__实际上是属于本机JavaScript对象的getter函数。它返回this绑定的内部私有原型链接(返回b[[Prototype]]):

b.__proto__ === Foo.prototype // true

值得注意的是,从ECMAScript5开始,还可以使用获取原型方法获取内部私有链接:

Object.getPrototypeOf(b) === b.__proto__ // true


注意:这个答案并不打算涵盖创建新对象或新构造函数的整个过程,而是为了帮助更好地理解什么是__proto__prototype[[Prototype]]以及它是如何工作的。

为了让它有点清楚除了上面的伟大的答案:

function Person(name){this.name = name};
var eve = new Person("Eve");
eve.__proto__ == Person.prototype //true
eve.prototype  //undefined

实例__proto__原型

简单地说:

> var a = 1undefined> a.__proto__[Number: 0]> Number.prototype[Number: 0]> Number.prototype === a.__proto__true

这允许您将属性附加到X.prototype在实例化了X类型的对象之后,它们仍然可以通过Javascript引擎用于向上走原型链的__proto__引用访问这些新属性。

原型或Object.prototype是对象文字的属性。它表示对象原型对象,您可以覆盖它以在原型链上进一步添加更多属性或方法。

__proto__是一个访问器属性(get和set函数),它通过访问对象公开对象的内部原型。

参考文献:

!!!这是世界上最好的解释!!!!!

var q = {}var prototype = {prop: 11}
q.prop // undefinedq.__proto__ = prototypeq.prop // 11

在函数构造函数中,当我们写入new Class时,javascript引擎会自动调用此q.__proto__ = prototype,并在__proto__ prop setClass.prototype

function Class(){}Class.prototype = {prop: 999} // set prototype as we need, before call new
var q = new Class() // q.__proto__ = Class.prototypeq.prop // 999

享受%)

我知道我迟到了,但让我试着简化一下。

让我们说有一个功能

    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);
  1. 现在我们有两个对象,对象a和对象b。都被创建了使用构造函数Foo。请记住,构造函数在这里只是一个词。
  2. 对象a和b都有一个消息属性的副本。
  3. 这两个对象a和b链接到构造函数Foo的原型对象。
  4. 在对象a和b上,我们可以在所有浏览器中使用__proto__属性访问Foo原型,在IE中,我们可以使用Object.get原型(a)或Object.get原型(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();//ab.Greet();//ba.constructor.prototype.Greet();//undefined

如您所见,我们在Foo.prototype中添加了Greet()方法,但它可以在a和b或任何其他使用Foo构造的对象中访问。

在执行a. Greet()时,JavaScript将首先在属性列表中的对象a中搜索Greet。如果找不到,它将在a__proto__链中上升。由于.__proto__和Foo.prototype是同一个对象,JavaScript将找到Greet()方法并执行它。

我希望,现在原型和__proto__简化了一点。

在JavaScript中,函数可以用作构造函数。这意味着我们可以使用new关键字从它们中创建对象。每个构造函数都带有一个与它们链接的内置对象。这个内置对象称为原型。Instances of a constructor function use __proto__ to access the prototype property of its constructor function.

原型图

  1. 首先我们创建了一个构造函数:function Foo(){}。需要明确的是,Foo只是另一个函数。但我们可以使用new关键字从中创建一个对象。这就是为什么我们称之为构造函数

  2. 每个函数都有一个称为原型属性的唯一属性。因此,构造函数Foo有一个原型属性指向它的原型,即Foo.prototype(见图)。

  3. 构造函数本身就是一个函数,它是称为[[Function]]构造函数的系统构造函数的实例。所以我们可以说function Foo是由[[Function]]构造函数构造的。所以,我们Foo function中的__proto__将指向其构造函数的原型,即Function.prototype

  4. Function.prototype本身只不过是一个由另一个名为[[Object]]的系统构造函数构造的对象。所以,[[Object]]Function.prototype的构造函数。所以,我们可以说Function.prototype[[Object]]的一个实例。所以Function.prototype__proto__指向Object.prototype

  5. Object.prototype是原型链中的最后一个人。我的意思是它还没有被构建。它已经在系统中了。所以它的__proto__指向null

  6. 现在我们来看看Foo的实例。当我们使用new Foo()创建一个实例时,它创建了一个新对象,它是Foo的实例。这意味着Foo是这些实例的构造函数。这里我们创建了两个实例(x和y)。x和y的__proto__因此指向Foo.prototype

我会尝试一个四年级的解释:

事情很简单。Aprototype是应该如何构建的一个例子。所以:

  • 我是function,我构建了与prototype类似的新对象

  • 我是一个object,我是用我的__proto__作为例子构建的

证明

function Foo() { }
var bar = new Foo()
// `bar` is constructed from how Foo knows to construct objectsbar.__proto__ === Foo.prototype // => true
// bar is an instance - it does not know how to create objectsbar.prototype // => undefined

为了解释,让我们创建一个函数

 function a (name) {this.name = name;}

当JavaScript执行此代码时,它将prototype属性添加到aprototype属性是一个具有两个属性的对象:

  1. constructor
  2. __proto__

所以当我们这么做的时候

a.prototype返回

     constructor: a  // function definition__proto__: Object

现在你可以看到constructor只是函数a本身__proto__指向JavaScript的根级别Object

让我们看看当我们使用a函数和new关键字时会发生什么。

var b = new a ('JavaScript');

当JavaScript执行这段代码时,它会做4件事:

  1. 它创建一个新对象,一个空对象//{}
  2. 它在b上创建__proto__并使其指向a.prototype因此b.__proto__ === a.prototype
  3. 它以新创建的对象(在步骤a中创建)作为其上下文(this)执行a.prototype.constructor(这是函数a的定义),因此作为“JavaScript”传递的name属性(添加到this)被添加到新创建的对象中。
  4. 它返回新创建的对象(在步骤#1中创建),因此varb被分配给新创建的对象。

现在如果我们添加a.prototype.car = "BMW"并做b.car,输出“BMW”出现。

这是因为当JavaScript执行此代码时,它在b上搜索car属性,它没有找到然后JavaScript使用b.__proto__(在步骤b.__proto__中指向“a.prototype”)并找到car属性,因此返回“BMW”。

您创建的每个函数都有一个名为prototype的属性,它的生命开始时是一个空对象。在您将此函数用作构造函数(即使用'new'关键字)之前,此属性毫无用处。

这通常与对象的__proto__属性混淆。有些人可能会感到困惑,除了对象的prototype属性可能会让他们获得对象的原型。但事实并非如此。prototype用于获取从函数构造函数创建的对象的__proto__

在上面的例子中:

function Person(name){this.name = name};
var eve = new Person("Eve");
console.log(eve.__proto__ == Person.prototype) // true// this is exactly what prototype does, made Person.prototype equal to eve.__proto__

我希望这有道理。

定义

(括号内的数字()是下面编写的代码的“链接”)

prototype-一个包含以下内容的对象:
=>函数(3)每个都可以访问的特定ConstructorFunction.prototype(5)通过此构造函数(1)创建或将要创建的对象(4)
=>构造函数本身(1)
=>这个特定对象的__proto__(原型对象)

__proto__(dandor proto?)-通过特定构造函数(1)创建的任何对象(2)之间的链接,以及该构造函数的原型对象的属性(5),允许每个创建的对象(2)访问原型的函数和方法(4)(__proto__默认包含在JS中的每个对象中)

代码澄清

1.

    function Person (name, age) {this.name = name;this.age = age;  
}

2.

    var John = new Person(‘John’, 37);// John is an object

3.

    Person.prototype.getOlder = function() {this.age++;}// getOlder is a key that has a value of the function

4.

    John.getOlder();

5.

    Person.prototype;

我碰巧从你不知道JS:这个和对象原型学习原型,这是一本很好的书,可以理解下面的设计并澄清这么多误解(这就是为什么我试图避免使用继承和instanceof之类的东西)。

但我也有同样的问题。有几个答案真的很有帮助和启发。我也很乐意分享我的理解。


什么是原型?

JavaScript中的对象有一个内部属性,在规范中表示为[[Prototype]],它只是对另一个对象的引用。几乎所有对象在创建时都为此属性赋予了一个非null值。

如何获取对象的原型?

通过__proto__Object.getPrototypeOf

var a = { name: "wendi" };a.__proto__ === Object.prototype // trueObject.getPrototypeOf(a) === Object.prototype // true
function Foo() {};var b = new Foo();b.__proto__ === Foo.prototypeb.__proto__.__proto__ === Object.prototype

prototype是什么?

prototype是作为函数的特殊属性自动创建的对象,用于建立委托(继承)链,也称为原型链。

当我们创建函数a时,prototype会自动创建为a上的特殊属性,并将函数代码保存为prototype上的constructor

function Foo() {};Foo.prototype // Object {constructor: function}Foo.prototype.constructor === Foo // true

我喜欢将此属性视为存储函数对象属性(包括方法)的地方。这也是JS中实用函数定义为Array.prototype.forEach()Function.prototype.bind()Object.prototype.toString().的原因

为什么要强调函数的属性?

{}.prototype // undefined;(function(){}).prototype // Object {constructor: function}
// The example above shows object does not have the prototype property.// But we have Object.prototype, which implies an interesting fact thattypeof Object === "function"var obj = new Object();

所以,AraryFunctionObject都是函数。我应该承认这刷新了我对JS的印象。我知道函数在JS中是一等公民,但似乎它是建立在函数之上的。

__proto__prototype有什么区别?

__proto__a引用适用于每个对象以引用其[[Prototype]]属性。

prototype是作为函数的特殊属性自动创建的对象,用于存储函数对象的属性(包括方法)。

有了这两个,我们可以在精神上绘制出原型链。就像这张图所示:

function Foo() {}var b = new Foo();
b.__proto__ === Foo.prototype // trueFoo.__proto__ === Function.prototype // trueFunction.prototype.__proto__ === Object.prototype // true

原型

原型是函数的一个属性。它是通过使用带有new关键字的(构造函数)函数创建对象的蓝图。

__proto__

__proto__在查找链中用于解析方法、属性。当创建对象时(使用带有new关键字的构造函数),__proto__设置为(构造函数)Function.prototype

function Robot(name) {this.name = name;}var robot = new Robot();
// the following are truerobot.__proto__ == Robot.prototyperobot.__proto__.__proto__ == Object.prototype

以下是我的(假想的)解释,以澄清混淆:

假设有一个与函数相关联的虚构类(蓝图/饼干切割器)。那个虚构的类用于实例化对象。prototype是扩展机制(C#中的扩展方法,或Swift扩展),用于向该虚构类添加内容。

function Robot(name) {this.name = name;}

以上可以想象为:

// imaginary classclass Robot extends Object{
static prototype = Robot.class// Robot.prototype is the way to add things to Robot class// since Robot extends Object, therefore Robot.prototype.__proto__ == Object.prototype
var __proto__;
var name = "";
// constructorfunction Robot(name) {
this.__proto__ = prototype;prototype = undefined;
this.name = name;}
}

所以,

var robot = new Robot();
robot.__proto__ == Robot.prototyperobot.prototype == undefinedrobot.__proto__.__proto__ == Object.prototype

现在将方法添加到Robot的prototype

Robot.prototype.move(x, y) = function(x, y){ Robot.position.x = x; Robot.position.y = y};// Robot.prototype.move(x, y) ===(imagining)===> Robot.class.move(x, y)

以上可以想象为Robot类的扩展:

// Swift way of extentionextension Robot{function move(x, y){Robot.position.x = x; Robot.position.y = y}}

反过来,

// imaginary classclass Robot{
static prototype = Robot.class // Robot.prototype way to extend Robot classvar __proto__;
var name = "";
// constructorfunction Robot(name) {
this.__proto__ = prototype;prototype = undefined;
this.name = name;}
// added by prototype (as like C# extension method)function move(x, y){Robot.position.x = x; Robot.position.y = y};}

如何使用__proto__作为静态方法?

function Foo(name){this.name = nameFoo.__proto__.collection.push(this)Foo.__proto__.count++
}
Foo.__proto__.count=0Foo.__proto__.collection=[]
var bar = new Foo('bar')var baz = new Foo('baz')
Foo.count;//2Foo.collection // [{...}, {...}]bar.count // undefined

__proto__是构造prototype和构造函数的基础,例如:function human(){}prototype,它在构造函数的新实例中通过__proto__共享。更详细的阅读这里

(function(){let a = function(){console.log(this.b)};a.prototype.b = 1;a.__proto__.b = 2;let q = new a();console.log(a.b);console.log(q.b)})()

尝试此代码以了解

JavaScript原型vs__prototype__

'use strict'function A() {}var a = new A();class B extends A {}var b = new B();console.log('====='); // =====console.log(B.__proto__ === A); // trueconsole.log(B.prototype.__proto__ === A.prototype); // trueconsole.log(b.__proto__ === B.prototype); // trueconsole.log(a.__proto__ === A.prototype); // trueconsole.log(A.__proto__ === Function.__proto__); // trueconsole.log(Object.__proto__ === Function.__proto__); // trueconsole.log(Object.prototype === Function.__proto__.__proto__); // trueconsole.log(Object.prototype.__proto__ === null); // true

在JavaScript中,每个对象(函数也是对象!)都有一个__proto__属性,该属性是对其原型的引用。

当我们使用new运算符和构造函数来创建一个新对象时,新对象的__proto__属性将使用构造函数的prototype属性设置,然后构造函数将被新对象调用,在该过程中,“this”将是对构造函数范围内新对象的引用,最后返回新对象。

Constructor的原型是__proto__属性,Constructor的prototype属性与new运算符一起使用。

构造函数必须是函数,但函数并不总是构造函数,即使它具有prototype属性。

原型链实际上是对象的__proto__属性来引用它的原型,和原型的__proto__属性来引用原型的原型,依此类推,直到引用Object的原型的__proto__属性,该属性引用null。

例如:

console.log(a.constructor === A); // true// "a" don't have constructor,// so it reference to A.prototype by its ``__proto__`` property,// and found constructor is reference to A

[[Prototype]]__proto__属性实际上是一样的。

我们可以使用Object的getOritypeOf方法来获取某物的原型。

console.log(Object.getPrototypeOf(a) === a.__proto__); // true

我们编写的任何函数都可以使用new运算符创建对象,所以这些函数中的任何一个都可以是构造函数。

总结:

对象的__proto__属性是映射到对象构造函数的prototype的属性。换句话说:

instance.__proto__ === constructor.prototype // true

这用于形成对象的prototype链。prototype链是对象属性的查找机制。如果访问了对象的属性,JavaScript将首先查看对象本身。如果在那里找不到该属性,它将一直爬到protochain,直到找到(或没有找到)

示例:

function Person (name, city) {this.name = name;}
Person.prototype.age = 25;
const willem = new Person('Willem');
console.log(willem.__proto__ === Person.prototype); // the __proto__ property on the instance refers to the prototype of the constructor
console.log(willem.age); // 25 doesn't find it at willem object but is present at prototypeconsole.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 

我们的第一个日志结果是true,这是因为如前所述,构造函数创建的实例的__proto__属性指的是构造函数的prototype属性。请记住,在JavaScript中,函数也是对象。对象可以有属性,任何函数的默认属性都是一个名为原型的属性。

然后,当这个函数被用作构造函数时,从它实例化的对象将收到一个名为__proto__的属性。这个__proto__属性指的是构造函数的prototype属性(默认情况下每个函数都有)。

为什么这个有用?

JavaScript在查找Objects上的属性时有一种机制,称为原型继承,这是它的基本功能:

  • 首先,检查属性是否位于对象本身上。如果是,则返回此属性。
  • 如果属性不位于对象本身,它将“爬上原型链”。它基本上查看__proto__属性引用的对象。在那里,它检查属性是否在__proto__引用的对象上可用。
  • 如果属性不在__proto__对象上,它将爬上__proto__链,一直爬到Object对象。
  • 如果它在对象及其prototype链的任何位置都找不到属性,它将返回undefined

例如:

function Person (name) {this.name = name;}
let mySelf = new Person('Willem');
console.log(mySelf.__proto__ === Person.prototype);
console.log(mySelf.__proto__.__proto__ === Object.prototype);

解释性示例:

function Dog(){}Dog.prototype.bark = "woof"
let myPuppie = new Dog()

现在,myPupppy有__proto__属性指向Dog.prototype.

> myPuppie.__proto__>> {bark: "woof", constructor: ƒ}

但是myPuppie没有原型属性。

> myPuppie.prototype>> undefined

因此,myPuppie的__proto__是用于实例化此对象的构造函数的.原型属性的参考(并且当前myPuppie对象与此__proto__对象具有“委托”关系),而myPuppie的.原型属性根本不存在(因为我们没有设置它)。

MPJ在这里做出了很好的解释:原型与原型-JavaScript中的对象创建

这个正确地指出

__proto__是查找链中使用的实际对象解析方法等。原型是用于构建的对象__proto__当您使用new创建对象时:

( new Foo ).__proto__ === Foo.prototype;( new Foo ).prototype === undefined;

我们可以进一步注意到,使用函数构造函数创建的对象的__proto__属性指向相应构造函数的原型属性指向的内存位置。

如果我们改变构造函数原型的内存位置,派生对象的__proto__仍将继续指向原始地址空间。因此,为了使公共属性在继承链上可用,总是将属性附加到构造函数原型,而不是重新初始化它(这将改变其内存地址)。

考虑以下示例:

function Human(){this.speed = 25;}
var himansh = new Human();
Human.prototype.showSpeed = function(){return this.speed;}
himansh.__proto__ === Human.prototype;  //truehimansh.showSpeed();    //25
//now re-initialzing the Human.prototype aka changing its memory locationHuman.prototype = {lhs: 2, rhs:3}
//himansh.__proto__ will still continue to point towards the same original memory location.
himansh.__proto__ === Human.prototype;  //falsehimansh.showSpeed();    //25

只有一个对象用于原件链接。这个对象显然有一个名称和一个值:__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__引用xx的指针),prototypex(它的原型)的值。

我希望现在有点清楚了。

我为自己绘制了一个小图,表示以下代码片段:

var Cat = function() {}var tom = new Cat()

理解__proto__和原型

我有一个经典的OO背景,所以以这种方式表示层次结构很有帮助。为了帮助你阅读这个图表,请将图像中的矩形视为JavaScript对象。是的,函数也是对象。;)

JavaScript中的对象有属性,__proto__只是其中之一。

这个属性背后的想法是指向(继承)层次结构中的祖先对象。

JavaScript中的根对象是Object.prototype,所有其他对象都是这个对象的后代。根对象的__proto__属性是null,它代表继承链的末端。

您会注意到prototype是函数的属性。Cat是一个函数,但FunctionObject也是(本机)函数。tom不是函数,因此它没有这个属性。

这个属性背后的想法是指向一个将在构造中使用的对象,即当您调用该函数的new运算符时。

注意原型对象(黄色矩形)有另一个名为constructor,它指向相应的函数对象。对于简而言之,这是没有描述的原因。

实际上,当我们用new Cat()创建tom对象时,创建的对象将__proto__属性设置为构造函数的prototype对象。

最后,让我们稍微玩弄一下这个图表。以下陈述是正确的:

  • tom.__proto__属性指向与Cat.prototype相同的对象。

  • Cat.__proto__指向Function.prototype对象,就像Function.__proto__Object.__proto__一样。

  • Cat.prototype.__proto__tom.__proto__.__proto__指向同一个对象,即Object.prototype

干杯!

这是一个非常重要的问题,对于任何想了解原型继承的人来说都是如此。据我所知,当使用函数的new创建对象时,默认情况下会分配原型,因为Function根据定义具有原型对象:

function protofoo(){}var protofoo1 = new protofoo();console.log(protofoo.prototype.toString()); //[object Object]

当我们创建一个没有new的普通对象时,即显式地从函数中创建,它没有原型,但它有一个空的原型,可以分配一个原型。

var foo={check: 10};console.log(foo.__proto__); // emptyconsole.log(bar.prototype); //  TypeErrorfoo.__proto__ = protofoo1; // assignedconsole.log(foo.__proto__); //protofoo

我们可以使用Object.create显式地链接一个对象。

// we can create `bar` and link it to `foo`var bar = Object.create( foo );bar.fooprops= "We checking prototypes";console.log(bar.__proto__); // "foo"console.log(bar.fooprops); // "We checking prototypes"console.log(bar.check); // 10 is delegated to `foo`

[[原型]]:

[[原型]]是JS中对象的内部隐藏属性,它是对另一个对象的引用。每个对象在创建时都会收到[[原型]]的非空值。请记住,当我们引用对象上的属性时,会调用[[Get]]操作,例如myObject. a。如果对象本身有属性,那么将使用该属性。

let myObject= {a: 2};
console.log(myObject.a);            // 2

但是,如果对象本身直接没有请求的属性,则[[Get]]操作将继续跟随对象的[[原型]]链接。此过程将继续进行,直到找到匹配的属性名称或[[原型]]链结束(在内置Object.prototype)。如果没有找到匹配的属性,则返回未定义。Object.create(指定对象)创建一个与指定对象具有[[原型]]链接的对象。

let anotherObject= {a: 2};
// create an object linked to anotherObjectlet myObject= Object.create(anotherObject);console.log(myObject.a);                // 2

因此,如果我们使用for… in循环来迭代对象的属性,那么可以通过该对象的[[原型]]链到达的所有可枚举属性也将与对象本身的可枚举属性一起被枚举。当使用in运算符测试对象上属性的存在时,in运算符将通过对象的[[原型]]链接检查所有属性,而不管它们的可枚举性如何。

// for..in loop uses [[Prototype]] chain lookup processlet anotherObject= {a: 2};
let myObject= Object.create(anotherObject);
for(let k in myObject) {console.log("found: " + k);            // found: a}
// in operator uses [[Prototype]] chain lookup processconsole.log("a" in myObject);              // true

.原型:

原型是JS中函数的属性,它指的是具有构造函数属性的对象,该属性存储函数对象的所有属性(和方法)。

let foo= function(){}
console.log(foo.prototype);// returns {constructor: f} object which now contains all the default properties
foo.id= "Walter White";
foo.job= "teacher";
console.log(foo.prototype);// returns {constructor: f} object which now contains all the default properties and 2 more properties that we added to the fn object/*{constructor: f}constructor: f()id: "Walter White"job: "teacher"arguments: nullcaller: nulllength: 0name: "foo"prototype: {constructor: f}__proto__: f()[[FunctionLocation]]: VM789:1[[Scopes]]: Scopes[2]__proto__: Object
*/

但是JS中的普通对象没有.原型属性。我们知道Object.prototype是JS中所有对象的根对象。所以很明显,Object是一个函数,即typeof Object==="函数"。这意味着我们也可以从Object函数创建对象,比如,让myObj=new Object()。类似地,数组,函数也是函数,所以我们可以使用Array.prototype,Function.prototype来存储数组和函数的所有通用属性。所以我们可以说JS是建立在函数之上的。

{}.prototype;                            // SyntaxError: Unexpected token '.'
(function(){}).prototype;                // {constructor: f}

同样使用new运算符,如果我们从函数创建对象,那么这些新创建对象的内部隐藏[[原型]]属性将指向原始函数的.原型属性引用的对象。在下面的代码中,我们创建了一个对象,a来自fn,字母,并将2个属性一个添加到fn对象,另一个添加到fn的原型对象。现在,如果我们尝试访问新创建对象上的这两个属性,那么我们只能访问添加到函数原型对象的属性。这是因为函数的原型对象现在在新创建的对象a的链上。

let Letter= function(){}
let a= new Letter();
Letter.from= "Albuquerque";
Letter.prototype.to= "New Hampshire";
console.log(a.from);                // undefined
console.log(a.to);                  // New Hampshire

.__proto__

.__proto__是JS中对象的属性,它引用了[[原型]]链中的另一个对象。我们知道[[原型]]是JS中对象的内部隐藏属性,它引用了[[原型]]链中的另一个对象。我们可以通过2种方式获取或设置内部[[原型]]属性引用的对象

  1. Object.getPrototypeOf(obj) / Object.setPrototypeOf(obj)

  2. obj.__proto__

我们可以使用:.__proto__.__proto__. .遍历[[Oritype]]链。除了.构造函数、. toString()、. isOritypeOf()之外,我们的dunder proto属性(__proto__)实际上存在于内置的Object.prototype根对象上,但可用于任何特定对象。我们的.__proto__实际上是一个getter/setter。Object.prototype中.__proto__的实现如下:

Object.defineProperty(Object.prototype, "__proto__", {get: function() {return Object.getPrototypeOf(this);},set: function(o) {Object.setPrototypeOf(this, o);return o;}});

检索obj.__proto__的值就像调用,obj.__proto__()实际上返回了存在于Object.prototype对象上的getter fn的调用,Object.getPrototypeOf(obj)。虽然.__proto__是一个可设置的属性,但由于性能问题,我们不应该更改已经存在的对象的[[原型]]。

如果我们从函数创建对象,则使用new运算符,那么这些新创建对象的内部隐藏[[原型]]属性将指向原始函数的.原型属性引用的对象。使用.__proto__属性,我们可以访问对象的内部隐藏[[原型]]属性引用的另一个对象。但是__proto__与[[原型]]不同,而是它的getter/setter。考虑下面的代码:

let Letter= function() {}
let a= new Letter();
let b= new Letter();
let z= new Letter();
// output in consolea.__proto__ === Letter.prototype;               // true
b.__proto__ === Letter.prototype;               // true
z.__proto__ === Letter.prototype;               // true
Letter.__proto__ === Function.prototype;        // true
Function.prototype.__proto__ === Object.prototype;        // true
Letter.prototype.__proto__ === Object.prototype;          // true

输入图片描述

我认为你需要知道__proto__[[原型]]原型之间的区别。

接受的答案是有帮助的,但它可能暗示(不完美)__proto__是构造函数上的仅与使用#1创建的对象相关,这不是真的。

更准确地说:#0存在于每个对象上

  • 什么是__proto__

    • 好吧,它是一个引用另一个对象也是所有对象的属性,称为#0的对象。
    • 值得一提的是,[[prototype]]是JavaScript内部处理的东西,是开发人员无法访问
  • 为什么我们需要一个指向属性[[prototype]](所有对象)的引用对象?

    • 因为JavaScript不想允许直接获取/设置[[prototype]],所以它允许它通过中间层__proto__。所以你可以把__proto__想象成[[prototype]]属性的getter/setter。
  • 那么prototype是什么?

    • 它是特定于功能(最初在Function中定义,即Function.prototype,然后由<强>新创建的函数原型继承,然后这些函数再次将其传递给它们的子函数,形成原型继承链)。

    • JavaScript使用父函数的prototype来设置其子函数的[[prototype]],当父函数运行new时(记得我们说所有对象有[[prototype]]吗?好吧,函数也是对象,所以它们也有[[prototype]])。所以当一个函数(子)的[[prototype]]设置为另一个函数(父)的prototype时,你最终会得到:

      let child = new Parent();child.__proto__ === Parent.prototype // --> true.

      (记住child.[[prototype]]是不可访问的,所以我们使用__proto__检查它。


注意事项1:每当一个属性不在子进程中时,它的__proto__将被“隐式”搜索。例如,如果child.myprop返回一个值,你就不能说“myprop”是子进程的属性,还是它父母的原型之一的属性。这也意味着你永远不需要自己做这样的事情:child.__proto__.__proto__.myprop,只是child.myprop会自动为你做这件事。

注意事项2:即使父级的原型中包含项目,子级自己的prototype最初也将是一个空对象。如果你想进一步扩展继承链(向子级添加子级[ren]),你可以手动向其中添加项目或从中删除项目。或者它可以隐式操作,例如使用类语法。)

注意3:如果您需要自己设置/获取[[prototype]],使用__proto__有点过时,现代JavaScript建议使用Object.setPrototypeOfObject.getPrototypeOf代替。

这个问题有很多好的答案,但是为了总结和紧凑的答案,我补充以下内容:

我们必须考虑的第一件事是当JS被发明时,计算机的内存非常低,所以如果我们需要一个创建新对象类型的进程,我们必须考虑内存性能。

因此,他们将从特定object type创建的对象需要的方法定位在内存的单独部分,而不是每次我们创建新对象时,在对象之外存储方法。因此,如果我们使用JS的新特性重新发明new运算符和constructor函数概念,我们有以下步骤:

  1. 和空对象。(这将是实例化对象类型的最终结果)
let empty={}
  1. 我们已经知道,出于内存性能的原因,object type实例所需的所有方法都位于构造函数的prototype属性上。(函数也是对象,所以它们可以有属性)因此,我们将empty对象的__protp__引用到这些方法存在的位置。(我们考虑概念上用作构造函数的函数,名为构造函数。
empty.__proto__ = constructor.prototype
  1. 我们必须初始化对象类型值。在JS中,函数与对象断开连接。使用点符号或函数对象具有的bindcallapply等方法,我们必须告诉“函数的this上下文是什么”。
let newFunc = constructor.bind(empty)
  1. 现在我们有了一个新函数,它有一个empty对象作为this上下文。执行此函数后。empty对象将被填充,如果定义的constructor函数不返回,则实例化类型对象的结果将是此empty对象(好像这将是过程的结果)

因此,如您所见,__proto__是引用其他对象的对象属性(在JS函数中也是对象)prototype对象属性,它由跨特定object type实例使用的属性组成。

从短语functions are objects中可以猜到,函数也有__proto__属性,因此它们可以引用其他对象的prototype属性。这就是prototype inheritance的实现方式。

__proto__是在创建类/函数实例时创建的。基本上,它包含创建实例的类/函数的原型。prototype包含可以链接的实际原型。

让我用一个简单的例子来解释:

function User(email, name){this.email = email;this.name = name;this.online = false;// method directly added to the constructorthis.greet = ()=>{console.log(`Hi ${this.name}`);}}// Adding prototype method login to the constructor function.User.prototype.login = function(){this.online = true;console.log(this.email, 'has logged in');};// Adding prototype method logout to the constructor function.User.prototype.logout = function(){this.online = false;console.log(this.email, 'has logged out');}; 
var userOne = new User('ryu@ninjas.com', 'Ryu');var userTwo = new User('yoshi@mariokorp.com', 'Yoshi'); 
console.log(userOne);userTwo.login();userTwo.greet();

输出:输入图片描述

结论:

  • 构造函数中添加的属性和方法是直接添加到对象中。
  • 添加的属性和方法.原型。被添加到对象的__proto__属性中。我们甚至可以通过userOne.__proto__userTwo.__proto__看到那些