__JavaScript中的原型与原型

__JavaScript中的原型与原型,javascript,prototype,javascript-objects,prototypal-inheritance,Javascript,Prototype,Javascript Objects,Prototypal Inheritance,此图再次显示每个对象都有一个原型。建造师 函数Foo也有自己的_proto__,即function.prototype, 而这反过来又通过它的_proto______________________________ 对象。原型。因此,重复一下,Foo.prototype只是一个显式的 Foo的属性,它引用b和c对象的原型 原型和原型之间有什么区别 该图取自。\uuuuu proto\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

此图再次显示每个对象都有一个原型。建造师 函数Foo也有自己的_proto__,即function.prototype, 而这反过来又通过它的_proto______________________________ 对象。原型。因此,重复一下,Foo.prototype只是一个显式的 Foo的属性,它引用b和c对象的原型

原型和原型之间有什么区别

该图取自。

\uuuuu proto\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;
原型是函数对象的属性。它是由该函数构造的对象的原型

__proto__u;是对象的内部属性,指向其原型。当前的标准提供了一个等效的Object.getPrototypeOfO方法,尽管事实上的标准proto更快

通过将函数的原型与对象的_proto_______________________________________

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

这里的Point是一个构造函数,它按程序构建对象数据结构。myPoint是由Point构造的对象,因此Point.prototype会保存到myPoint。uuu proto_uuu当时。

在声明函数时会创建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.prototype在默认情况下是一个对象文本,可以根据需要进行更改

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

var person1 = new Person(somedate);
var person2 = new Person(somedate);
创建两个Person实例,这两个对象可以将Person.prototype的age方法调用为person1.age,person2.age

在您问题的上图中,您可以看到Foo是一个函数对象,因此它有一个到Function.prototype的uu proto_u链接,而Function.prototype又是对象的一个实例,有一个到Object.prototype的u proto_u链接。proto链接在这里结束,Object.prototype中的_proto_uuu指向null

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

__proto_uu不是访问原型链的标准方法,标准但类似的方法是使用Object.GetPrototypeObj

下面的instanceof运算符代码提供了更好的理解:

当对象是类的实例时,object instanceof Class运算符返回true,更具体地说,如果在该对象的proto链中找到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.callobject,如果对象是类的实例,则返回true的类。

一个很好的方法是

原型由构造函数使用。它真的应该被称为prototypeToInstall,因为它就是这样


“原型”是指在一个对象上安装的原型,该对象是通过上述构造函数创建/安装在该对象上的。

我的理解是:“\u原型”和原型都是为原型链技术服务的。不同之处在于,以下划线命名的函数类似于proto,根本不适合显式调用的开发人员。换句话说,它们只是用于一些机制,如继承等。它们是“后端”。但不带下划线的函数是为显式调用而设计的,它们是“前端”

理解它的另一个好方法:

var foo={} /* 构造函数是对象,所以foo.constructor.prototype实际上是 对象原型;作为回报,Object.prototype是foo.\uuuu proto\uuu链接到的对象。 */ console.logfoo.constructor.prototype==foo.\uuu proto\uuuu; //这证明了上述评论所宣称的:两种说法的评估结果都是正确的。 console.logfoo.\uuuu proto\uuuu==Object.prototype; console.logfoo.constructor.prototype==Object.prototype; 仅在支持IE11 ___;协议之后。在该版本之前,例如IE9,您可以使用构造函数来获取_proto__

创建函数时,会自动创建一个名为prototype的属性对象,而不是您自己创建的,而是由构造函数附加到函数对象。注意:这个新的原型对象还指向本机JavaScript对象,或者具有本机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
专用链接 使用该函数的对象double-方括号prototype或只是[[prototype]]。许多浏览器都为我们提供了一个公共链接,称为_uproto__;

更具体地说,proto实际上是属于本机JavaScript对象的。它返回这个绑定的内部私有原型链接,返回b的[[prototype]]:

值得注意的是,从ECMAScript 5开始,您还可以使用该方法获取内部私有链接:

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

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

除了上面的好答案外,还想说清楚一点:

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

var eve = new Person("Eve");

eve.__proto__ == Person.prototype //true

eve.prototype  //undefined
实例有原型,类有原型。

简单地说:

> var a = 1
undefined
> a.__proto__
[Number: 0]
> Number.prototype
[Number: 0]
> Number.prototype === a.__proto__
true
console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
这允许您在实例化类型为X的对象后将属性附加到X.prototype,并且它们仍然可以通过Javascript引擎用于遍历prototype链的_proto__引用访问这些新属性。

prototype或Object.prototype是对象文本的属性。它表示对象原型对象,您可以覆盖该对象以沿原型链添加更多属性或方法

__proto_u;是一个访问器属性get and set函数,它公开了对象的内部原型,对象通过该原型被访问

参考资料:


我知道,我迟到了,但让我尽量简化一下

假设有一个函数

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);
 function a (name) {
  this.name = name;
 }
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都有消息属性的副本。 这两个对象a和b链接到构造函数Foo的原型对象。 在对象a和b上,我们可以在所有浏览器中使用_uproto_uu属性访问Foo prototype,在IE中,我们可以使用Object.getPrototypeOfa或Object.getPrototypeOfb 现在,Foo.prototype,a

    b.__proto__ === Object.getPrototypeOf(a);
    a.__proto__ ===  Foo.prototype;
    a.constructor.prototype  === a.__proto__;
所有这些都将返回真值

正如我们所知,在JavaScript中可以动态添加属性。我们可以向对象添加属性

    Foo.prototype.Greet = function(){

         console.log(this.message);
    }
    a.Greet();//a
    b.Greet();//b
    a.constructor.prototype.Greet();//undefined 
正如您所看到的,我们在Foo.prototype中添加了Greet方法,但在a和b或使用Foo构造的任何其他对象中都可以访问它

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


我希望,现在prototype和proto被简化了一点。

在JavaScript中,函数可以用作构造函数。这意味着我们可以使用new关键字从中创建对象。每个构造函数都有一个与之链接的内置对象。这个内置对象称为原型。构造函数的实例使用_proto__访问其构造函数的prototype属性

首先,我们创建了一个构造函数:函数Foo{}。明确地说,Foo只是另一个函数。但是我们可以用new关键字从中创建一个对象。这就是为什么我们称它为构造函数

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

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

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
Function.prototype本身就是一个对象,它是由另一个名为[[object]]的系统构造函数构造的。所以,[[Object]]是Function.prototype的构造函数。所以,我们可以说Function.prototype是[[Object]]的一个实例。所以Function.prototype的proto指向Object.prototype

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
Object.prototype是原型链中的最后一个人。我的意思是它还没有建成。它已经存在于系统中。所以它的proto指向null

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

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

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

事情很简单。原型是一个如何建造的例子。因此:

我是一个函数,我构建了与原型相似的新对象

我是一个物体 我是以我的原型为例构建的

证明:


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

    function Foo(message){

         this.message = message ; 
     };

     console.log(Foo.prototype);
 function a (name) {
  this.name = name;
 }
当JavaScript执行此代码时,它会将prototype属性添加到,prototype属性是一个具有两个属性的对象:

建造师 __原型__ 所以当我们这样做的时候

a、 它返回的原型

     constructor: a  // function definition
    __proto__: Object
现在你可以看到构造函数只是函数a本身 proto指向JavaScript的根级对象

让我们看看当我们使用带有新关键字的函数时会发生什么

var b = new a ('JavaScript');
当JavaScript执行此代码时,它会执行4项操作:

它创建一个新对象,一个空对象//{} 它在b上创建uuu proto uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu 它执行一个.prototype.constructor,它是函数a的定义,在步骤1中创建的新对象作为其上下文,因此作为“JavaScript”传递的name属性被添加到新创建的对象中。 它返回在步骤1中创建的新创建的对象,以便将变量b分配给新创建的对象。 现在,如果我们添加a.prototype.car=BMW并 b、 汽车,输出宝马出现


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

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

这常常与对象的_proto_______)属性相混淆。有些人可能会感到困惑,除了对象的prototype属性可能会使他们成为对象的proto之外。但事实并非如此。prototype用于获取从函数构造函数创建的对象的proto

在上述示例中:

函数人名{ this.name=name }; var eve=新员工; console.logeve.\uuuuu proto\uuuuu==Person.prototype//true //这正是原型所做的,使Person.prototype等于eve 括号内的数字是下面代码的“链接”

原型-由以下部分组成的对象: =>此功能的功能3 特定的构造函数Function.prototype5,每个 通过此构造函数函数1创建或将创建的对象4 =>构造函数本身1 =>此特定对象原型对象的原型

__原生动物默认情况下,JS中的每个对象都包含通过特定构造函数函数1创建的任何对象2与该构造函数的原型对象属性5之间的链接,该构造函数允许每个创建的对象2访问原型的函数和方法4

代码澄清 一,

二,

三,

四,

五,


我碰巧在学习prototype,这是一本很好的书,可以理解下面的设计,澄清很多误解,这就是为什么我试图避免使用继承和instanceof之类的东西

但我的问题和这里的人一样。有几个答案确实很有帮助,也很有启发性。我也很乐意分享我的理解

什么是原型? JavaScript中的对象有一个内部属性,在规范中表示为[[Prototype]],它只是对另一个对象的引用。几乎所有对象在创建时都为此属性指定了非Null值

如何获取对象的原型? 通过proto或Object.getPrototypeOf

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

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

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

我想把这个属性当作存储属性的地方,包括函数对象的方法。这也是为什么JS中的实用函数定义为Array.prototype.forEach、Function.prototype.bind、Object.prototype.toString

为什么要强调函数的性质

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

{}.prototype;                            // SyntaxError: Unexpected token '.'

(function(){}).prototype;                // {constructor: f}
原型和原型有什么区别? __proto_u引用作用于每个对象以引用其[[Prototype]]属性

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

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

*/
有了这两个,我们可以在脑海中描绘出原型链。如图所示:

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

b.__proto__ === Foo.prototype // true
Foo.__proto__ === Function.prototype // true
Function.prototype.__proto__ === Object.prototype // true
原型 原型是原型的一个属性 作用它是通过使用带有new关键字的构造函数创建对象的蓝图

__原型__ __proto_uuu在查找链中用于解析方法和属性。当使用具有new关键字的构造函数创建对象时,_proto_uu设置为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
以下是我的想象解释,以消除混淆: 假设有一个虚构的类blueprint/coockie cutter与函数关联。这个虚构的类用于实例化对象。prototype是C语言中的扩展机制扩展方法,或用于向该虚拟类添加内容的Swift扩展

function Robot(name) {
    this.name = name;
}
上述情况可以想象为:

所以

现在为机器人原型添加方法:

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

// Swift way of extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}
反过来

对静态方法使用proto如何

function Foo(name){
  this.name = name
  Foo.__proto__.collection.push(this)
  Foo.__proto__.count++

}

Foo.__proto__.count=0
Foo.__proto__.collection=[]

var bar = new Foo('bar')
var baz = new Foo('baz')

Foo.count;//2
Foo.collection // [{...}, {...}]
bar.count // undefined
__proto___是构造原型的基础,构造函数函数例如:函数human{}具有原型,该原型通过构造函数新实例中的__proto______共享。更详细的阅读

函数{ 设a=函数{console.logthis.b}; a、 原型b=1; a、 _uuuproto_uuu.b=2; 设q=新的a; 控制台loga.b; 控制台logq.b } 在JavaScript中,每个objectfunction也是object!具有_proto__属性,该属性是对其原型的引用

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
当我们使用new运算符和构造函数来创建新对象时, 将使用构造函数的prototype属性设置新对象的prototype属性, 然后新对象将调用构造函数, 在这个过程中,这将是对构造函数作用域中新对象的引用,最后返回新对象

构造函数的原型是_proto__属性,构造函数的原型属性是与新操作符一起工作

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

> myPuppie.prototype
>> undefined
原型链实际上是对象的_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
[[Prototype]]和[uuuuu proto\uuuuu]属性实际上是一样的

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

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
我们编写的任何函数都可以使用新操作符创建对象, 因此,这些函数中的任何一个都可以是构造函数。

Summary: 对象的_uproto_u属性是映射到对象的构造函数原型的属性。换言之:

实例.\uuuu proto\uuuuu==constructor.prototype//true

这用于形成对象的原型链。原型链是对象属性的查找机制。如果访问对象的属性,JavaScript将首先查看对象本身。如果在那里找不到属性,它将一直爬升到protochain,直到找到它为止

例子: 职能人员姓名、城市{ this.name=名称; } Person.prototype.age=25; 康斯特·威廉=新人“威廉”; console.logwillem.\uuuu proto\uuuu==Person.prototype;//实例上的_uproto_uu属性引用构造函数的原型 console.logwillem.age;//25在willem object上找不到它,但在原型上出现了 console.logwillem.\uuuu proto\uuuu.age;//现在我们直接访问Person函数的原型解释性示例:

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

let myPuppie = new Dog()
现在,MyPuppie具有指向Dog.prototype的uuu proto_uuu属性

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
但是我的小狗没有原型属性

> myPuppie.prototype
>> undefined
因此,mypuppie的.prototype是对用于实例化此对象的构造函数的.prototype属性的引用,当前mypuppie对象具有与此对象的关系的委托,而mypuppie的.prototype属性则不存在,因为我们没有设置它

MPJ对此做出了很好的解释:

如正确所述

__proto_uu是在查找链中用于 解析方法等。原型是用于构建的对象 __proto_uu;使用新的创建对象时:

( new Foo ).__proto__ === Foo.prototype;
( new Foo ).prototype === undefined;
我们可以进一步注意到,使用函数构造函数创建的对象的_uproto_u属性指向相应构造函数的prototype属性指向的内存位置

如果我们改变构造函数原型的内存位置,派生对象的proto仍然指向原始地址空间。因此,要使公共属性在继承链中可用,请始终将属性附加到构造函数原型中,而不是重新初始化它,这样会更改其内存地址

考虑以下示例:

function Human(){
    this.speed = 25;
}

var himansh = new Human();

Human.prototype.showSpeed = function(){
    return this.speed;
}

himansh.__proto__ === Human.prototype;  //true
himansh.showSpeed();    //25

//now re-initialzing the Human.prototype aka changing its memory location
Human.prototype = {lhs: 2, rhs:3}

//himansh.__proto__ will still continue to point towards the same original memory location. 

himansh.__proto__ === Human.prototype;  //false
himansh.showSpeed();    //25

只有一个对象用于protypal链接。这个对象显然有一个名称和一个值:\uu\p roto_________________________________。就这些

为了让它更容易掌握,看看dmitry soshnikov在这张博文图顶部的图表,你永远不会发现_proto__________________________________

要点是:_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.getPrototypeOfx得到x的实际值时,它就是x的原型,正是x的_proto__所指向的。因此,proto确实指向x的原型。因此uu proto_uu引用x的x指针,prototype是其prototype的x值

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

我希望现在有点清楚了。

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

var Cat = function() {}
var tom = new Cat()
我有一个经典的OO背景,所以用这种方式表示层次结构很有帮助。为了帮助您阅读此图,请将图像中的矩形视为JavaScript对象。是的,函数也是对象

JavaScript中的对象具有属性,而proto只是其中之一

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

JavaScript中的根对象是object.prototype,所有其他对象都是这个对象的后代。根对象的_uproto_uu属性为null,表示继承链的结束

您会注意到原型是函数的属性。Cat是函数,但函数和对象也是本机函数。tom不是函数,因此它不具有此属性

> myPuppie.prototype
>> undefined
此属性背后的思想是指向将在构造中使用的对象,即在调用该函数的新运算符时

请注意,原型对象黄色矩形还有另一个属性,称为 指向相应函数对象的构造函数。对于 简洁的原因是没有描述这一点

实际上,当我们用新的Cat创建tom对象时,所创建的对象将把_proto__属性设置为构造函数的prototype对象

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

tom.\uuuu proto\uuuu属性指向与Cat.prototype相同的对象

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
Cat.\uuuu proto\uuu指向Function.prototype对象,就像Function.\uu proto\uu和object.\uu proto\uu一样

Cat.prototype.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu和tom.\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo

干杯

对于任何想了解原型遗传的人来说,这是一个非常重要的问题。据我所知,当使用函数中的新对象创建对象时,默认情况下会指定prototype,因为函数定义了prototype对象:

function protofoo(){
}
var protofoo1 = new protofoo();
console.log(protofoo.prototype.toString()); //[object Object]
当我们创建一个普通对象而没有新对象时,即显式地从一个函数创建,它没有prototype,但它有一个空proto,可以为它分配一个prototype

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.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`
[[原型]]:

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

let myObject= {
    a: 2
};

console.log(myObject.a);            // 2
但是,如果对象本身直接没有请求的属性,那么[[Get]]操作将继续遵循对象的[[Prototype]]链接。此过程将继续,直到找到匹配的属性名称或内置Object.Prototype的[[Prototype]]链结束。如果未找到匹配的属性,则将返回undefined。Object.createspecifiedObject创建与指定对象具有[[Prototype]]链接的对象

let anotherObject= {
    a: 2
};

// create an object linked to anotherObject
let myObject= Object.create(anotherObject);
console.log(myObject.a);                // 2
对于..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
.原型:

.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

*/
但是JS中的普通对象没有.proto 类型属性。我们知道Object.prototype是JS中所有对象的根对象。很明显,Object是一个函数,即typeof Object===函数。这意味着我们也可以从object函数创建object,比如,让myObj=newobject。类似地,数组、函数也是函数,因此我们可以使用Array.prototype、Function.prototype来存储数组和函数的所有通用属性。所以我们可以说JS是基于函数构建的

{}.prototype;                            // SyntaxError: Unexpected token '.'

(function(){}).prototype;                // {constructor: f}
如果我们从函数中创建对象,那么这些新创建对象的内部隐藏[[Prototype]]属性将指向原始函数的.Prototype属性所引用的对象。在下面的代码中,我们创建了一个对象,一个来自fn的字母,并向fn对象和fn的原型对象分别添加了两个属性。现在,如果我们尝试访问新创建的对象上的两个属性,那么我们将只能访问添加到函数的原型对象中的属性。这是因为函数的prototype对象现在位于新创建的对象a的[[prototype]]链上

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
.uuu协议uuuu:

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

Object.getPrototypeObj/Object.setPrototypeObj

对象原型__

我们可以使用:。dunder proto属性的.constructor、.toString、.isProtoTypes和.protoTypes实际上都存在于内置的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.getPrototypeObj的调用。尽管._proto__是一个可设置的属性,但我们不应该因为性能问题而更改现有对象的[[Prototype]]

使用new运算符如果我们从函数创建对象,则这些新创建对象的内部隐藏[[Prototype]]属性将指向原始函数的.Prototype属性引用的对象。使用._proto__属性,我们可以访问对象的内部隐藏[[Prototype]]属性引用的其他对象。但是,protoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotoprotopro。考虑下面的代码:

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

我想你需要知道原型和原型之间的区别

console.log(Object.getPrototypeOf(a) === a.__proto__); // true
> myPuppie.__proto__
>> {bark: "woof", constructor: ƒ}
var foo={
  check: 10
};
console.log(foo.__proto__); // empty
console.log(bar.prototype); //  TypeError
foo.__proto__ = protofoo1; // assigned
console.log(foo.__proto__); //protofoo
公认的答案是有帮助的,但它可能不完全地暗示_uproto_uuu只是与使用构造函数上的new创建的对象相关,这是不正确的

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

但什么是“原始”呢

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

因为JavaScript不允许直接获取/设置[[prototype]],所以它允许它通过一个中间层,即proto。因此,您可以将uu proto_uu视为[[prototype]]属性的getter/setter。 那么原型是什么呢

它是特定于Function中定义的Function的东西,即Function.prototype,然后由新创建的函数原型继承,然后这些函数再次将其赋予子函数,形成原型继承链

JavaScript使用父函数的原型来设置它的子函数“[[prototype]”,当该父函数使用新函数运行时,还记得我们说过所有对象都有[[prototype]”吗?嗯,函数也是对象,所以它们也有[[原型]]。因此,当一个functionchild的[[prototype]]被设置为另一个functionparent的原型时,您最终会得到以下结果:

让孩子=新的父母; child.\uuuu proto\uuuu===Parent.prototype/->true。 记住child。[[prototype]]是不可访问的,所以我们使用_uproto_;检查了它

注意1:只要属性不在子级中,就会隐式搜索它的_proto__。例如,如果child.myprop返回一个值,您就不能说myprop是该子对象的属性,还是其父对象的原型的属性。这也意味着你永远不需要自己做像:child.\uuuuu proto.\uuuuuu proto.\uuuuuuu.myprop这样的事情,只有child.myprop会自动为你做

注意2:即使父母的原型中有项目,孩子自己的原型也会被删除 最初是一个空对象。如果您想进一步将inhertance chainadd child[ren]扩展到子项,您可以向其中添加项或手动从中删除项。或者可以隐式地操纵它,例如,使用


注意3:uuu proto_uuu有点像,现代JavaScript建议使用Object.setPrototypeOf和Object.getPrototypeOf来代替。

另请参见我认为自顶向下或自下而上是首选方法。实际上我更喜欢这种方式,所以我可以追踪图表,直到找到某些东西的来源。我喜欢JavaScript如何使用原型继承将y.constructor解析为y.。uu proto_uu.constructor。我还喜欢Object.prototype位于原型继承链的顶端,Object.prototype.\uuuu proto\uuu设置为null。我还喜欢该图如何使程序员将对象视为1的三列概念可视化。实例2。建设者,3。当通过new关键字实例化时,构造器与这些实例关联的原型。图表在您观看类似的内容后立即变得有意义,BTW现在,正如我已经阅读的答案一样,觉得有义务真正推荐上述视频,因为它确实对正在发生的事情有一个非常清晰和非WTFy的解释:啊!因此,prototype在实例本身或其他对象上不可用,但仅在构造函数上可用。@rvighne:prototype仅在函数上可用,因为它们是从函数、函数和对象派生的,但在任何其他对象上都不可用。然而,uuuu proto_uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。因此,myobject.prototype不会是实际对象的属性,因为它只是构造函数用来勾勒myobject.proto\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu?i、 e.foo.\uuuu proto\uuuu==foo.constructor。prototype@Alex_Nabu不完全是。newCar._proto__是Car.prototype,不是Car.prototype的实例。而Car.protype是对象的实例。原型不是赋予新车任何属性或结构的东西,它只是新车原型链中的下一个对象。Car.prototype不是临时对象。该对象被设置为使用Car作为构造函数生成的任何新对象的_proto____)属性的值。如果您想将任何东西视为蓝图对象,请将汽车视为新汽车对象的蓝图。此外,如果更改对象的_proto_____________________________________。例如,您可以添加一个方法对象作为函数的_proto _u,以具有一种可调用的实例对象.myPoint._proto _.constructor.prototype==Point。prototype@kzhlol给了我有趣的结果console.logobj1.call/[Function:call]obj1.call//TypeError:obj1.call不是一个函数。我做了obj.\uuuuu proto\uuuuu=Function.\uuuuu proto\uuuuuu myFn.\uuuuu proto\uuuuuuu={foo:'bar'}我想我明白你的意思了。除了命名约定之外,还有更多关于uuuu proto\uuuuuu和原型的内容。它们可能指向同一对象,也可能不指向同一对象。参见@zyklus-answer@demisx你说的当然是对的,但我的观点是名称差异暴露了功能的对比。根据你的理解,这还不足以说明,特别是在之前已经提供了其他好的答案的情况下……我投了更高的票,但可能是因为构造函数使用的语句原型听起来好像非构造函数没有,但事实并非如此,然而,除了这不是我们现在关注的焦点之外,我们还可以注意到,如果使用new调用,每个函数都可能是一个构造函数……请将构造函数函数更改为构造函数函数,因为可能会与_uproto_;构造函数函数混淆。我认为这一点很重要,因为在新的关键字被使用时,构造函数实际上并没有被调用。构造函数中使用的原型语句只告诉了一个重要的事实,但它告诉读者的方式可能会让读者认为这是整个事实。prototype是根据Javascript中的每个函数声明在内部创建的,不管将来如何调用该函数,无论是否使用新关键字;声明函数的原型指向一个对象文字。只是我会用另一种方式写它:foo.\uuu proto\uuu==foo.constructor.prototypeI我想知道为什么原型对象首先是在内部创建的?可以简单地将静态方法分配给函数对象本身吗。e、 函数fa{this.a=a};f、 增量=函数{return++this.a}?为什么不选择这种方式而不是将方法添加到prototype对象?如果f.\uuuuu proto\uuuuu=g,其中g是基类,那么这将起作用

选择对象进行共享是因为函数构造函数对象中只能存储独占的函数构造函数属性。实际上,这将是一个混乱,因为instanceof将导致{}instanceof Function===true,因为如果删除prototype属性,将无法区分原型。@阿披实这是什么意思:如果f.\uuuu proto\uuuu=g,其中g是基类,这将起作用。我不知道这是否有某种意义,我不明白,但如果你以这种方式添加属性和方法,那么当你使用new关键字创建实例时,属性和方法不会被复制。不,prototype和a___;proto____;在任何时候都不会被用作创建任何对象的蓝图。这是一个由模糊的类语法及其前身引入的神话。正如回复帖子所说,它只是用于查找链,在原型中用于识别与new一起使用的构造函数,这是假装是一流机制的一部分,让包括我在内的许多用户感到困惑。第一点应该是,我是一个函数,我构建了新的对象,将委托给我的原型1。构造函数不返回一个值!它返回a。2. __proto__;返回Object.prototype,而不是Javascript中的根对象。这是一个很好的答案+1这是解释什么样的原型实际上是一个具有两个属性的对象以及Javascript如何执行每段代码的最佳答案。这个信息出人意料地难以获得。Object.prototype不是对象文本的属性,试图打印出{}。prototype返回未定义的;但是,可以通过{}.\uuuuu proto\uuuuuuuu访问它,它返回Object.prototype.@Taurus,单击标题,它将指向ECMAScript规范文档。查看第9节“普通对象和外来对象行为”,其中对其进行了更详细的解释。我认为这里有一些错误:u一个新对象与函数的原型Foo有内部或私有链接u你的意思是:一个新对象与函数Foo的原型有内部或私有链接?谢谢@KorayTugay!是的,我拼错了:+1 prototype不用于创建对象的_proto___当访问proto时,proto只提供对prototype对象的引用。这就是为什么在JavaScript中对prototype和prototype的回答?是好的还是关于Foo.collection.pushthis Foo.count++仍然在为proto和prototype考虑更一致的名称。也许原型和继承?我想说,原型和原型都应该避免。我们现在有了类,我喜欢OOP。问题是类相对较新,在C上工作时不支持像microsoft JScript这样的非常方便的引擎,需要一个快速且脏的脚本引擎,nashorn Javascript是jjs下所有新Java安装的附带工具,它是将Java放入纯动态环境的一种好方法,在这种环境中,您不需要不断地重新编译东西。问题是,如果类是sugar,这不会是一个问题,但事实并非如此,它提供的东西在旧js版本中没有它们是不可能的。比如扩展函数。最终我们会得到支持。我是后端开发人员,所以我没有问题,我很少用js编写代码。继承静态成员时,Child会注意到从父级添加/删除静态成员,我想不出在JScript上做什么,JScript不提供Object.assign//uuu proto\uu/getPrototypeOf,因此,您必须修改root Object.prototype以进行模拟it@Derick丹尼尔:我不知道你为什么否决这个,但你的编辑并不是我想要传达的。进一步编辑以获得更多许可:。Jyoti,我没有否决你的答案,其他人否决了,我只是编辑了它:只是为了澄清:实例没有.prototype属性?只有构造函数功能正确吗。。。所以实例和它的构造函数之间的区别是:构造函数都有1。原型2。prototype对象,而实例只有.\uuuuu proto\uuuuu属性。。。对吗?@Shaz你是对的。实例使用其proto访问其构造函数的prototype属性;您将获得car.\uuuu proto\uuuuu=Vehicle,但您也将获得指向Vehicle.prototype的car.prototype属性?@shaz您能否提供一个jsfiddle,以便我可以可视化情况?这里car.prototype是一个继承属性。汽车继承了汽车功能的“原型”属性。所以car.prototype==vehicle.prototype。原型属性是车辆上的属性。汽车可以通过它的原型链访问它。我希望这能很好地解释清楚你的困惑@神光,汤姆。原型和猫。原型完全相等,所以,汤姆。原型和猫。原型都是真的。那么,你所说的图像中的箭头是什么意思呢?如果你指的是黑色箭头,它没有特别的含义,除了
物体。所以prototype是您问题中Cat对象的属性。Brilliant explanationConstructor函数和类也有一个_proto______________________________。构造函数函数和类有一个_proto__属性和一个prototype属性。见短而甜