__proto__ VS. JavaScript中的原型

0x9*_*x90 730 javascript prototype prototypal-inheritance javascript-objects

该图再次显示每个对象都有一个原型.构造函数Foo也有自己__proto__的Function.prototype,它又通过其__proto__属性再次引用到Object.prototype.因此,重复,Foo.prototype只是Foo的一个显式属性,它指的是b和c对象的原型.

var b = new Foo(20);
var c = new Foo(30);
Run Code Online (Sandbox Code Playgroud)

__proto__prototype属性有什么区别?

在此输入图像描述

这个数字来自这里.

Mar*_*ahn 712

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

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;
Run Code Online (Sandbox Code Playgroud)

  • 啊! 因此`prototype`在实例本身(或其他对象)上不可用,但仅在构造函数上可用. (220认同)
  • @rvighne:`prototype` 仅适用于函数,因为它们派生自 `Function`、`Function` 和 `Object`,但在其他任何情况下都不是。然而,`__proto__` 无处不在。 (37认同)
  • 因此`__proto__`是保存并用作原型的实际对象,而`Myconstructure.prototype`只是`__proto__`的蓝图,实际上是保存并用作原型的实际对象.因此`myobject.prototype`不会是实际对象的属性,因为它只是构造函数用来概括`myobject .__ proto__`应该是什么样子的临时事物. (19认同)
  • @Alex_Nabu不太好.`newCar .__ proto__`*IS*`Car.prototype`,而不是`Car.prototype`的实例.而`Car.protoype`*IS*是`object`的一个实例.`Car.prototype`不是给`newCar`任何属性或结构的东西,它只是*IS**`newCar`原型链中的下一个`object`.`Car.prototype`不是一个临时的`对象`.它是`object`被设置为使用`Car`作为`构造函数`创建的任何新`对象`的`__proto__`属性的值.如果你想把任何东西想象成一个蓝图"对象",可以把"汽车"想象成新车"对象"的蓝图. (10认同)
  • 可以公平地说,对象的`__proto__`属性是指向对象的构造函数的`prototype`属性的指针吗?即foo .__ proto__ === foo.constructor.prototype (9认同)
  • @Daniel-破解JavaScript的方法有很多,但是老实说,在讨论极端情况下,没有一个理智的人会碰到这一点的,我看不到重点!:) (2认同)

Imp*_*Imp 320

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

__proto__是对象的内部属性,指向其原型.现行标准提供了一种等效Object.getPrototypeOf(O)方法,但事实上的标准__proto__更快.

您可以instanceof通过将函数prototype与对象的__proto__链进行比较来找到关系,并且可以通过更改来中断这些关系prototype.

function Point(x, y) {
    this.x = x;
    this.y = y;
}

var myPoint = new Point();

// the following are all true
myPoint.__proto__ == Point.prototype
myPoint.__proto__.__proto__ == Object.prototype
myPoint instanceof Point;
myPoint instanceof Object;
Run Code Online (Sandbox Code Playgroud)

Point是一个构造函数,它在程序上构建一个对象(数据结构).myPoint是一个由Point()so 构造的对象Point.prototype,myPoint.__proto__在那时被保存到.

  • David Herman在他的新书http://effectivejs.com/中出色地描述了这一点. (5认同)
  • 此外,如果更改对象的`__proto__`属性,它将更改完成原型查找的对象.例如,您可以将方法对象添加为函数的`__proto__`以具有一种可调用的实例对象. (2认同)
  • myPoint.__proto__.constructor.prototype == Point.prototype (2认同)
  • 我想我已经明白你的意思了。 (2认同)

小智 113

声明函数时会创建Prototype属性.

例如:

 function Person(dob){
    this.dob = dob
 }; 
Run Code Online (Sandbox Code Playgroud)

一旦声明了上面的函数,就会在内部创建Person.prototype属性.可以将许多属性添加到Person.prototype中,这些属性由使用新Person()创建的Person实例共享.

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

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

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

var person1 = new Person(somedate);
var person2 = new Person(somedate);
Run Code Online (Sandbox Code Playgroud)

创建2个Person实例,这2个对象可以将Person.prototype的age属性称为person1.age,person2.age.

在上图中,您可以看到Foo是一个Function对象,因此它有一个__proto__指向Function.prototype 的链接,而Function.prototype又是Object的一个实例,并且有一个Person.prototype指向Object.prototype 的链接.proto链接Person在Object.prototype中指向null.

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

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

以下代码为person1.age运算符提供了更好的理解:

object person2.age类操作符Foo在对象是Class的实例时返回,更具体地说,如果Function Object在该对象的proto链中找到该对象,则该对象是该Class的实例.

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

上面的方法可以调用为:__proto__如果object是Class的实例,则返回true.

  • 我想知道为什么首先在内部创建`prototype`对象?可以简单地将静态方法分配给函数对象本身.例如`function f(a){this.a = a}; f.increment = function(){return ++ this.a}`?为什么没有选择这种方法而不是将方法添加到`prototype`对象?如果`f .__ proto__ = g`,其中g是基类,这将有效. (2认同)
  • 实际上,这会很混乱,因为“instanceof”会导致“({}) instanceof Function === true”,因为如果删除“prototype”属性,就无法区分原型。 (2认同)

sar*_*ink 62

想到它的好方法是......

prototypeconstructor()函数使用.它应该被称为类似的东西"prototypeToInstall",因为它就是它的本质.

并且__proto__是对象的"已安装的原型"(从所述constructor()函数创建/安装在对象上)

  • 我赞成它,但也许是downvote的原因是因为语句"原型由构造函数()函数使用"听起来好像非构造函数没有,但事实并非如此,但除此之外它现在也不是我们关注的焦点可以注意到,如果使用new调用,每个函数都可能是构造函数... (2认同)
  • 请将"`constructor()`functions"更改为"构造函数",因为可能会混淆"`__proto __.constructor()`functions".我认为这很重要,因为当使用`new`关键字时,实际上并没有调用\ _ _ _ proto\_ _ _.构造函数. (2认同)

Man*_*z90 53

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

 function a (name) {
  this.name = name;
 }
Run Code Online (Sandbox Code Playgroud)

当JavaScript执行此代码时,它会向其添加prototype属性a,prototypeproperty是一个具有两个属性的对象:

  1. constructor
  2. __proto__

所以,当我们这样做

a.prototype 它返回

     constructor: a  // function definition
    __proto__: Object
Run Code Online (Sandbox Code Playgroud)

现在你可以看到constructor只是函数a本身,并__proto__指向ObjectJavaScript 的根级别.

让我们看看当我们使用关键词a功能时会发生什么new.

var b = new a ('JavaScript');
Run Code Online (Sandbox Code Playgroud)

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

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

现在,如果我们添加a.prototype.car = "BMW"并执行 b.car,输出"BMW"就会出现.

这是因为当JavaScript执行此代码时,它搜索car属性b,它没有找到使用的JavaScript b.__proto__(在步骤#2中指向'a.prototype')并找到car属性所以返回"BMW".

  • 1. `constructor` 不返回 `a()`!它返回`a`。2. `__proto__` 返回 `Object.prototype`,而不是 Javascript 中的根对象。 (3认同)
  • +1这是解释原型实际上是什么(具有两个属性的对象)以及Javascript如何执行每段代码的最佳答案。这些信息出人意料地难以获得。 (3认同)
  • 这是一个很好的答案! (2认同)

Lio*_*rom 45

原型VS. __proto__ VS. [[原型]]

在创建函数时,会自动创建一个名为prototype的属性对象(您自己没有创建它)并且正在附加到函数对象(the 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;
}
Run Code Online (Sandbox Code Playgroud)

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

var b = new Foo();

b.[[Prototype]] === Foo.prototype  // true
Run Code Online (Sandbox Code Playgroud)


该函数对象的私有链接称为双括号原型或仅[[Prototype]].很多浏览器都为我们提供了一个公共链接,它叫做__proto__!

更具体地说,__proto__实际上是属于本机JavaScript对象的getter函数.它返回无论内部和私营部门的原型联动this的结合是(返回[[Prototype]]b):

b.__proto__ === Foo.prototype // true
Run Code Online (Sandbox Code Playgroud)

值得注意的是,启动时ECMAScript5,您还可以使用getPrototypeOf方法获取内部私有链接:

Object.getPrototypeOf(b) === b.__proto__ // true
Run Code Online (Sandbox Code Playgroud)


注意:这个答案并不打算涵盖创建新对象或新构造的全过程,但以帮助更好地理解什么是__proto__,prototype[[Prototype]]它是如何工作的.

  • @Taurus,单击标题,它会指向ECMAScript规范文档。请查看第9节(普通和奇异对象的行为),它会对其进行详细说明。 (2认同)

ser*_*kan 29

除了上面的答案之外,还要清楚一点:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined
Run Code Online (Sandbox Code Playgroud)

实例__proto__,原型.

  • 构造函数和类也有一个“__proto__”属性,它不是为实例保留的。构造函数和类具有“__proto__”属性和“prototype”属性。请参阅/sf/answers/2940192461/ (2认同)

ade*_*hox 17

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

接受的答案是有帮助的,但它可能意味着(不完美)这__proto__与使用构造函数创建的对象相关new,但事实并非如此。

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

  • __proto__到底是什么?

    • 嗯,它是一个引用另一个对象的对象,该对象也是所有对象的属性,称为[[prototype]]
    • 值得一提的是,[[prototype]]这是 JavaScript 在内部处理的事情,开发人员无法访问
  • [[prototype]]为什么我们需要一个(所有对象的)属性的引用对象?

    • 因为 JavaScript 不允许[[prototype]]直接获取/设置,所以它允许通过中间层__proto__. 所以你可以将其视为属性__proto__的 getter/setter [[prototype]]
  • 那是什么prototype

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

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

      let child = new Parent();
      child.__proto__ === Parent.prototype // --> true.
      
      Run Code Online (Sandbox Code Playgroud)

      (记住child.[[prototype]]无法访问,所以我们使用 检查它__proto__。)


注意 1:只要子属性不存在,__proto__就会“隐式”搜索它。因此,例如,如果child.myprop返回一个值,您无法判断“myprop”是否是子级的属性,或其父级原型之一的属性。这也意味着您永远不需要做这样的事情:child.__proto__.__proto__.myprop您自己,只会child.myprop自动为您做这件事。

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

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


AL-*_*ami 12

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

原型图

  1. 首先我们创建了一个构造函数:function Foo(){}.要清楚,Foo只是另一个功能.但我们可以使用new关键字从中创建一个对象.这就是我们称之为构造函数的原因

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

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

  4. Function.prototype本身只不过是一个从另一个被称为的系统构造函数构造的对象[[Object]].所以,[[Object]]是构造函数Function.prototype.所以,我们可以说Function.prototype是一个实例[[Object]].所以__proto__Function.prototypeObject.prototype.

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

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


林奕忠*_*林奕忠 8

 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); // true
console.log(B.prototype.__proto__ === A.prototype); // true
console.log(b.__proto__ === B.prototype); // true
console.log(a.__proto__ === A.prototype); // true
console.log(A.__proto__ === Function.__proto__); // true
console.log(Object.__proto__ === Function.__proto__); // true
console.log(Object.prototype === Function.__proto__.__proto__); // true
console.log(Object.prototype.__proto__ === null); // true
Run Code Online (Sandbox Code Playgroud)

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

当我们使用new带有构造函数的运算符来创建一个新对象时,新对象的__proto__属性将被设置为构造函数的prototype属性,然后构造函数将被新对象调用,在这个过程中“this”将成为对新对象的引用在构造函数作用域中,最终返回新对象。

构造函数的原型是__proto__属性,构造函数的prototype属性是与new操作符。

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

原型链实际上是对象的__proto__属性引用其原型,原型的__proto__属性引用原型的原型,以此类推,直到引用对象的原型__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
Run Code Online (Sandbox Code Playgroud)

[[Prototype]]__proto__财产实际上是一回事。

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

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
Run Code Online (Sandbox Code Playgroud)

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


deb*_*yan 8

考虑下面的代码:

let Letter= function() {}
    
let a= new Letter();
let b= new Letter();
let z= new Letter();

// output in console
a.__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
Run Code Online (Sandbox Code Playgroud)

我们可以用下图来描述上面的代码:

原型 vs 原型 vs 原型


现在让我们详细探讨[[Prototype]]一下:__proto__prototype

[[Prototype]]

[[Prototype]]是JS中对象的内部隐藏属性,它是对另一个对象的引用。每个对象在创建时都会收到一个对象(或 null)作为[[Prototype]]。当我们引用对象上的属性时[[Get]],就会调用像myObject.a. 如果对象本身具有属性,a则将使用该属性。

let myObject = {
  a: 2,
};

console.log(myObject.a); // 2
Run Code Online (Sandbox Code Playgroud)

但如果对象本身不直接具有所请求的属性,则[[Get]]操作将继续沿着[[Prototype]]对象的链接进行。此过程将继续,直到找到匹配的属性名称或[[Prototype]]链结束(在内置Object.prototype)。如果没有找到匹配的属性,undefined则将返回。现在Object.create(anyObject)创建一个具有[[Prototype]]到指定 的链接的对象anyObject

let anotherObject = {
  a: 2,
};

// create an object linked to anotherObject
let myObject = Object.create(anotherObject);
console.log(myObject.a); // 2
Run Code Online (Sandbox Code Playgroud)

for..in循环和运算符都in使用[[Prototype]]链式查找过程。因此,如果我们使用for..in循环来迭代对象的属性,那么通过该对象的链可以到达的所有可枚举属性[[Prototype]]也将与对象本身的可枚举属性一起枚举。当使用in运算符测试对象上是否存在属性时,运算符将通过对象的链接in检查所有属性,无论其可枚举性如何。[[Prototype]]

// for..in loop uses [[Prototype]] chain lookup process
let 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 process
console.log("a" in myObject); // true
Run Code Online (Sandbox Code Playgroud)

__proto__

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

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

  2. obj.__proto__

我们可以[[Prototype]]使用以下方式遍历链: .__proto__.__proto__. .。随着.constructor.toString().isPrototypeOf()。dunder proto 属性 ( __proto__) 实际上存在于内置Object.prototype根对象中,但可在任何特定对象上使用。__proto__实际上是一个 getter/setter。__proto__in的实现Object.prototype如下:

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

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

new如果我们从函数创建对象,则使用运算符,那么[[Prototype]]这些新创建的对象的内部隐藏属性将指向prototype原始函数的属性引用的对象。使用属性,我们可以访问由对象的__proto__内部隐藏属性引用的其他对象。[[Prototype]]但与它的 getter/setter 不同__proto__[[Prototype]]

prototype

prototype是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: null
            caller: null
            length: 0
            name: "foo"
            prototype: {constructor: f}
            __proto__: f()
            [[FunctionLocation]]: VM789:1
            [[Scopes]]: Scopes[2]
        __proto__: Object
    
*/
Run Code Online (Sandbox Code Playgroud)

但JS中的普通对象没有prototype属性。我们知道Object.prototype是JS中所有对象的根对象。很明显Object是一个函数 ie typeof Object === "function"。这意味着我们还可以从函数创建一个对象Object,例如let myObj= new Object(). 同样ArrayFunction也是函数,因此我们可以使用Array.prototype,Function.prototype来存储数组和函数的所有通用属性。这意味着我们可以说 JS 是建立在函数之上的。

{}.prototype;                            // SyntaxError: Unexpected token '.'
    
(function(){}).prototype;                // {constructor: f}
Run Code Online (Sandbox Code Playgroud)

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

let Letter = function () {};

let obj = new Letter();

Letter.from = "Albuquerque";
Letter.prototype.to = "New Hampshire";

console.log(obj.from); // undefined
console.log(obj.to); // New Hampshire
Run Code Online (Sandbox Code Playgroud)


小智 7

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

假设有一个函数

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);
Run Code Online (Sandbox Code Playgroud)

Foo 函数将链接一个原型对象。因此,每当我们在 JavaScript 中创建一个函数时,它总是有一个链接到它的原型对象。

现在让我们继续使用函数 Foo 创建两个对象。

    var a = new Foo("a");
    var b = new Foo("b");
    console.log(a.message);
    console.log(b.message);
Run Code Online (Sandbox Code Playgroud)
  1. 现在我们有两个对象,对象a和对象b。两者都是使用构造函数 Foo 创建的。请记住,构造函数在这里只是一个词。
  2. 对象 a 和 b 都有一个 message 属性的副本。
  3. 这两个对象a和b链接到构造函数Foo的原型对象。
  4. 在对象 a 和 b 上,我们可以在所有浏览器中使用 __proto__ 属性访问 Foo 原型,在 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__;
Run Code Online (Sandbox Code Playgroud)

以上所有内容都会返回 true。

众所周知,JavaScript 中的属性可以动态添加。我们可以给对象添加属性

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 
Run Code Online (Sandbox Code Playgroud)

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

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

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


ify*_*ndy 7

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

但我有同样的问题,就像人们在这里问的那样.几个答案真的很有帮助和启发.我也很想分享我的理解.


什么是原型?

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

如何获得对象的原型?

通过__proto__Object.getPrototypeOf

var a = { name: "wendi" };
a.__proto__ === Object.prototype // true
Object.getPrototypeOf(a) === Object.prototype // true

function Foo() {};
var b = new Foo();
b.__proto__ === Foo.prototype
b.__proto__.__proto__ === Object.prototype
Run Code Online (Sandbox Code Playgroud)

什么是prototype

prototype是一个自动创建的对象,它是一个函数的特殊属性,用于建立委托(继承)链,即原型链.

当我们创建一个函数时a,prototype会自动创建一个特殊属性a并将函数代码保存为constructoron prototype.

function Foo() {};
Foo.prototype // Object {constructor: function}
Foo.prototype.constructor === Foo // true
Run Code Online (Sandbox Code Playgroud)

我很乐意将此属性视为存储函数对象的属性(包括方法)的位置.这也是为什么在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 that
typeof Object === "function"
var obj = new Object();
Run Code Online (Sandbox Code Playgroud)

所以Arary,Function,Object是所有功能.我应该承认这会刷新我对JS的印象.我知道函数是JS中的一等公民,但它似乎是建立在函数之上的.

__proto__和之间有什么区别prototype

__proto__引用适用于每个对象以引用其[[Prototype]]属性.

prototype是一个自动创建的对象,它是一个函数的特殊属性,用于存储函数对象的属性(包括方法).

有了这两个,我们就可以在精神上绘制原型链.如下图所示:

function Foo() {}
var b = new Foo();

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
Run Code Online (Sandbox Code Playgroud)


Wil*_*een 7

摘要:

__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 prototype
console.log(willem.__proto__.age); // now we are directly accessing the prototype of the Person function 
Run Code Online (Sandbox Code Playgroud)

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

然后,当将此函数用作构造函数时,从该函数实例化的对象将收到称为的属性__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);
Run Code Online (Sandbox Code Playgroud)


Yad*_*ood 6

理解它的另一个好方法:

var foo = {}

/* 
foo.constructor is Object, so foo.constructor.prototype is actually 
Object.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);
Run Code Online (Sandbox Code Playgroud)

仅在__proto__支持IE11之后.在那个版本之前,比如IE9,你可以用它constructor来获取__proto__.


the*_*ght 6

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

var Cat = function() {}
var tom = new Cat()
Run Code Online (Sandbox Code Playgroud)

理解 __proto__ 和原型

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

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

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

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

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

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

请注意,原型对象(黄色矩形)有另一个名为 的属性, constructor 该属性指向相应的函数对象。出于简洁原因,没有对此进行描述。

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

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

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

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

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

干杯!


Has*_*req 5

原型

prototype是Function的属性。这是通过使用带有new关键字的(构造函数)功能创建对象的蓝图。

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

function Robot(name) {
    this.name = name;
}
var robot = new Robot();

// the following are true   
robot.__proto__ == Robot.prototype
robot.__proto__.__proto__ == Object.prototype
Run Code Online (Sandbox Code Playgroud)

这是我(虚构的)解释,以消除混乱:

想象有一个与功能相关的假想类(蓝图/库奇刀具)。该虚构类用于实例化对象。prototype是将事物添加到该虚构类的扩展机制(C#或Swift扩展中的扩展方法)。

function Robot(name) {
    this.name = name;
}
Run Code Online (Sandbox Code Playgroud)

以上可以想象为:

// imaginary class
class 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 = "";

    // constructor
    function Robot(name) {

        this.__proto__ = prototype;
        prototype = undefined;

        this.name = name;
    }

} 
Run Code Online (Sandbox Code Playgroud)

所以,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype
Run Code Online (Sandbox Code Playgroud)

现在向prototypeRobot的方法添加方法:

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)
Run Code Online (Sandbox Code Playgroud)

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

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}
Run Code Online (Sandbox Code Playgroud)

反过来,

// imaginary class
class Robot{

    static prototype = Robot.class // Robot.prototype way to extend Robot class
    var __proto__;

    var name = "";

    // constructor
    function 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
    };
}
Run Code Online (Sandbox Code Playgroud)