__proto__ VS. prototype in JavaScript

后端 未结 30 1942
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-11-21 06:14

This figure again shows that every object has a prototype. Constructor function Foo also has its own __proto__ which is Function.prototype, a

相关标签:
30条回答
  • 2020-11-21 06:51

    Another good way to understand it:

    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);
    

    Only after IE11 __proto__ is supported. Before that version, such as IE9, you could use the constructor to get the __proto__.

    0 讨论(0)
  • 2020-11-21 06:52

    Prototype property is created when a function is declared.

    For instance:

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

    Person.prototype property is created internally once you declare above function. Many properties can be added to the Person.prototype which are shared by Person instances created using new Person().

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

    It is worth noting that Person.prototype is an Object literal by default (it can be changed as required).

    Every instance created using new Person() has a __proto__ property which points to the Person.prototype. This is the chain that is used to traverse to find a property of a particular object.

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

    creates 2 instances of Person, these 2 objects can call age method of Person.prototype as person1.age, person2.age.

    In the above picture from your question, you can see that Foo is a Function Object and therefore it has a __proto__ link to the Function.prototype which in turn is an instance of Object and has a __proto__ link to Object.prototype. The proto link ends here with __proto__ in the Object.prototype pointing to null.

    Any object can have access to all the properties in its proto chain as linked by __proto__ , thus forming the basis for prototypal inheritance.

    __proto__ is not a standard way of accessing the prototype chain, the standard but similar approach is to use Object.getPrototypeOf(obj).

    Below code for instanceof operator gives a better understanding:

    object instanceof Class operator returns true when an object is an instance of a Class, more specifically if Class.prototype is found in the proto chain of that object then the object is an instance of that Class.

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

    The above method can be called as: instanceOf.call(object, Class) which return true if object is instance of Class.

    0 讨论(0)
  • 2020-11-21 06:52

    '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
    

    In JavaScript, Every object(function is object too!) has a __proto__ property, the property is reference to its prototype.

    When we use the new operator with a constructor to create a new object, the new object's __proto__ property will be set with constructor's prototype property, then the constructor will be call by the new object, in that process "this" will be a reference to the new object in the constructor scope, finally return the new object.

    Constructor's prototype is __proto__ property, Constructor's prototype property is work with the new operator.

    Constructor must be a function, but function not always is constructor even if it has prototype property.

    Prototype chain actually is object's __proto__ property to reference its prototype, and the prototype's __proto__ property to reference the prototype's prototype, and so on, until to reference Object's prototype's __proto__ property which is reference to null.

    For example:

    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]] and __proto__ property actually is same thing.

    We can use Object's getPrototypeOf method to get something's prototype.

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

    Any function we written can be use to create an object with the new operator, so anyone of those functions can be a constructor.

    0 讨论(0)
  • 2020-11-21 06:53

    Summary:

    The __proto__ property of an object is a property that maps to the prototype of the constructor function of the object. In other words:

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

    This is used to form the prototype chain of an object. The prototype chain is a lookup mechanism for properties on an object. If an object's property is accessed, JavaScript will first look on the object itself. If the property isn't found there, it will climb all the way up to protochain until it is found (or not)

    Example:

    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 

    Our first log results to true, this is because as mentioned the __proto__ property of the instance created by the constructor refers to the prototype property of the constructor. Remember, in JavaScript, functions are also Objects. Objects can have properties, and a default property of any function is one property named prototype.

    Then, when this function is utilized as a constructor function, the object instantiated from it will receive a property called __proto__. And this __proto__ property refers to the prototype property of the constructor function (which by default every function has).

    Why is this useful?

    JavaScript has a mechanism when looking up properties on Objects which is called 'prototypal inheritance', here is what it basically does:

    • First, it's checked if the property is located on the Object itself. If so, this property is returned.
    • If the property is not located on the object itself, it will 'climb up the protochain'. It basically looks at the object referred to by the __proto__ property. There, it checks if the property is available on the object referred to by __proto__.
    • If the property isn't located on the __proto__ object, it will climb up the __proto__ chain, all the way up to Object object.
    • If it cannot find the property anywhere on the object and its prototype chain, it will return undefined.

    For example:

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

    0 讨论(0)
  • 2020-11-21 06:53

    [[Prototype]] :

    [[Prototype]] is an internal hidden property of objects in JS and it is a reference to another object. Every object at the time of creation receives a non-null value for [[Prototype]]. Remember [[Get]] operation is invoked when we reference a property on an object like, myObject.a. If the object itself has a property, a on it then that property will be used.

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

    But if the object itself directly does not have the requested property then [[Get]] operation will proceed to follow the [[Prototype]] link of the object. This process will continue until either a matching property name is found or the [[Prototype]] chain ends(at the built-in Object.prototype). If no matching property is found then undefined will be returned. Object.create(specifiedObject) creates an object with the [[Prototype]] linkage to the specified object.

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

    Both for..in loop and in operator use [[Prototype]] chain lookup process. So if we use for..in loop to iterate over the properties of an object then all the enumerable properties which can be reached via that object's [[Prototype]] chain also will be enumerated along with the enumerable properties of the object itself. And when using in operator to test for the existence of a property on an object then in operator will check all the properties via [[Prototype]] linkage of the object regardless of their enumerability.

    // 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 :

    .prototype is a property of functions in JS and it refers to an object having constructor property which stores all the properties(and methods) of the function object.

    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
    
    */
    

    But normal objects in JS does not have .prototype property. We know Object.prototype is the root object of all the objects in JS. So clearly Object is a function i.e. typeof Object === "function" . That means we also can create object from the Object function like, let myObj= new Object( ). Similarly Array, Function are also functions so we can use Array.prototype, Function.prototype to store all the generic properties of arrays and functions. So we can say JS is built on functions.

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

    Also using new operator if we create objects from a function then internal hidden [[Prototype]] property of those newly created objects will point to the object referenced by the .prototype property of the original function. In the below code, we have created an object, a from a fn, Letter and added 2 properties one to the fn object and another to the prototype object of the fn. Now if we try to access both of the properties on the newly created object, a then we only will be able to access the property added to the prototype object of the function. This is because the prototype object of the function is now on the [[Prototype]] chain of the newly created object, 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__ is a property of objects in JS and it references the another object in the [[Prototype]] chain. We know [[Prototype]] is an internal hidden property of objects in JS and it references another object in the [[Prototype]] chain. We can get or set the object referred by the internal [[Prototype]] property in 2 ways

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

    2. obj.__proto__

    We can traverse the [[Prototype]] chain using: .__proto__.__proto__. . . Along with .constructor, .toString( ), .isPrototypeOf( ) our dunder proto property (__proto__) actually exists on the built-in Object.prototype root object, but available on any particular object. Our .__proto__ is actually a getter/setter. Implementation of .__proto__ in Object.prototype is as below :

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

    To retrieve the value of obj.__proto__ is like calling, obj.__proto__() which actually returns the calling of the getter fn, Object.getPrototypeOf(obj) which exists on Object.prototype object. Although .__proto__ is a settable property but we should not change [[Prototype]] of an already existing object because of performance issues.

    Using new operator if we create objects from a function then internal hidden [[Prototype]] property of those newly created objects will point to the object referenced by the .prototype property of the original function. Using .__proto__ property we can access the other object referenced by internal hidden [[Prototype]] property of the object. But __proto__ is not the same as [[Prototype]] rather a getter/setter for it. Consider below code :

    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
    

    0 讨论(0)
  • 2020-11-21 06:54

    __proto__ is the actual object that is used in the lookup chain to resolve methods, etc. prototype is the object that is used to build __proto__ when you create an object with new:

    ( new Foo ).__proto__ === Foo.prototype;
    ( new Foo ).prototype === undefined;
    
    0 讨论(0)
提交回复
热议问题