这张图再次表明,每个对象都有一个原型。构造函数 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年)。


当前回答

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

其他回答

在声明函数时创建Prototype属性。

例如:

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

的人。Prototype属性在声明上述函数后在内部创建。 可以向Person添加许多属性。由使用new Person()创建的Person实例共享的原型。

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

值得注意的是,Person。prototype默认是Object字面量(可以根据需要更改)。

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

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

创建2个Person实例,这2个对象可以调用Person的age方法。原型作为人物1。年龄,person2.age。

在你的问题的上图中,你可以看到Foo是一个函数对象,因此它有一个__proto__链接到函数。prototype是Object的一个实例,并且有一个指向Object.prototype的__proto__链接。原型链接在这里以对象中的__proto__结束。原型指向null。

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

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

下面的instanceof操作符代码提供了更好的理解:

当一个对象是一个类的实例时,更具体地说,如果Class,则返回true。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。调用(object, Class),如果object是Class的实例则返回true。

原型

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

__proto__

__proto__在查找链中用于解析方法、属性。当创建对象时(使用构造函数函数和new关键字),__proto__被设置为(构造函数)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/ cookie cutter)。那个假想类用于实例化对象。prototype是一种扩展机制(c#或Swift Extension中的扩展方法),用于向虚类中添加内容。

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

以上可以想象为:

// 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;
    }

} 

So,

var robot = new Robot();

robot.__proto__ == Robot.prototype
robot.prototype == undefined
robot.__proto__.__proto__ == Object.prototype

现在为Robot的原型添加方法:

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 extention
extension Robot{
    function move(x, y){    
        Robot.position.x = x; Robot.position.y = y
    }
}

反过来,

// 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
    };
}

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

公认的答案是有帮助的,但它可能暗示(不完全)__proto__只与在构造函数上使用new创建的对象相关,这是不正确的。

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

But what is __proto__ at all? Well, it is an object referencing another object which is also a property of all objects, called [[prototype]]. It's worth mentioning that [[prototype]] is something that JavaScript handles internally and is inaccessible to the developer. Why would we need a reference object to the property [[prototype]] (of all objects)? Because JavaScript doesn't want to allow getting / setting the [[prototype]] directly, so it allows it through a middle layer which is __proto__. So you can think of __proto__ as a getter/setter of the [[prototype]] property. What is prototype then? It is something specific to functions(Initially defined in Function, i.e, Function.prototype and then prototypically inherited by newly created functions, and then again those functions give it to their children, forming a chain of prototypical inheritance). JavaScript uses a parent function's prototype to set its child functions' [[prototype]] when that parent function is run with new (remember we said all objects have [[prototype]]? well, functions are objects too, so they have [[prototype]] as well). So when the [[prototype]] of a function(child) is set to the prototype of another function(parent), you will have this in the end: let child = new Parent(); child.__proto__ === Parent.prototype // --> true. (Remember child.[[prototype]] is inaccessible, so we checked it using __proto__.)


注意1:只要属性不在子对象中,它的__proto__将被“隐式”搜索。例如,if child。Myprop返回一个值,你不能说" Myprop "是子对象的属性,还是父对象原型的属性。这也意味着你永远不需要做这样的事情:child.__proto__.__proto__。我的东西你自己拿去吧,孩子。Myprop会自动为你做这件事。

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

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

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

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

function User(email, name){
    this.email = email;
    this.name = name;
    this.online = false;
    // method directly added to the constructor
    this.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();

输出:

结论:

在构造函数中添加的属性和方法是 直接添加到对象中。 添加的属性和方法 .prototype。被添加到对象的__proto__属性中。我们甚至可以看到userOne。__proto__或userTwo.__proto__