0

I know the concept of inheritance in JavaScript is through prototype chain, but I'm not sure I understand it right. When a property is been read, the engine will first search for the instance's own property, if not found will search for the [[Prototype]] property of the instance, which is a reference to the prototype of the function that creates the instance, the search will go on until it reaches to the Object.prototype. For the following code:

var person1 = {
    name: "Qiushi",
    sayName: function() {
        console.log(this.name);
    }
};

person1.sayName();  // Qiushi

var person2 = Object.create(person1);
person2.name = "Alex";
console.log(person2.hasOwnProperty("sayName")); // false
person2.sayName();  // Alex

when person2 is inherit from person1, so that person2 can use the method defined in person1. But the sayName method is not a property of the prototype of person1, but instead it is just a own property of it. My question is as the method searching is following alone the prototype chain, how would person2 use a method which is not in this chain?

-------------------------------FINAL EDIT-------------------------

If you have same concern for the problem, please read the conversation between me and Jimbo.

8
  • 1
    It is in the chain, only not owned (not defined on person2 prototype). That's why we have hasOwnProperty() in the first place. Commented Dec 27, 2015 at 8:42
  • Here's something to think about: There is no inheritance in JavaScript. Nothing inherits anything from anywhere, ever. All there is is a singly linked list of objects called the prototype chain. The objects in that list are searched, in order, for properties with a given name. Either an object has a certain property defined (then hasOwnProperty() is true for that particular object), or one of its parents in the chain has (then hasOwnProperty() is true for that particular parent, but false for the initial object), or none has, then the property is undefined. Commented Dec 27, 2015 at 8:52
  • @Tomalak: "There is no inheritance in JavaScript" is simply untrue. Just because the inheritance mechanism is readily explained, that doesn't make it not inheritance. The inheritance mechanisms of Java and C++ are readily explained as well. Commented Dec 27, 2015 at 9:01
  • @T.J.Crowder I know, and we agree on that point. The purpose of the comment was to break the common thought pattern that an inherited property somehow becomes an actual part of the object at the end of the prototype chain. If I replace one element of an object's prototype chain, that object immediately appears to have different properties. Prototypical inheritance mimics the effects of inheritance, but the objects in question do not really get the properties they respond to (as opposed to how it works in Java/C++). Commented Dec 27, 2015 at 9:20
  • @Tomalak: It's not mimicking, it's just a different mechanism. Agreed on the way it's different, and how that can surprise people. (Amusingly, you also regularly see Java questions where the OP has thought in terms of separate objects, one for the base class part and another for the derived part, and gotten confused that way. :-) ) Commented Dec 27, 2015 at 9:25

2 Answers 2

6

There's nothing special about the objects that are prototypes of other objects, they're just objects.

When the engine goes to read a property, first it looks at the object itself to see if it has it and, if it does, uses it. If it doesn't, it looks to the prototype of the object, and then to its prototype, etc.

In your code, person1 is the prototype of person2, so when looking up sayName on person2, since the engine doesn't find it on person2, it looks on person2's prototype, person1, and finds it.

Here's a simple ASCII-art diagram of what you've set up in your code:

                                  +-------------------+
person1-----------------------+-->|     (object)      |
                              |   +-------------------+
                              |   | __proto__         |-->(not shown, Object.prototype)
                              |   | name: "Qiushi"    |
                              |   | sayName: function |
                              |   +-------------------+
                              |
            +--------------+  |
person2---->|   (object)   |  |
            +--------------+  |
            | __proto__    |--+
            | name: "Alex" |
            +--------------+

Here's a more-but-still-not-entirely complete version:

          +------------+                                  
Object--->| (function) |  +->(not shown, Function.prototype)                              
          +------------+  |                                 
          | __proto__  |--+                                  +--------------------+
          | prototype  |---------------------------------+-->|      (object)      |
          +------------+                                 |   +--------------------+
                                  +-------------------+  |   |   __proto__: null  |
person1-----------------------+-->|     (object)      |  |   | toString: function |
                              |   +-------------------+  |   | valueOf: function  |
                              |   | __proto__         |--+   | ...                |
                              |   | name: "Qiushi"    |      +--------------------+
                              |   | sayName: function |   
                              |   +-------------------+   
                              |                           
            +--------------+  |
person2---->|   (object)   |  |
            +--------------+  |
            | __proto__    |--+
            | name: "Alex" |
            +--------------+
Sign up to request clarification or add additional context in comments.

3 Comments

Nice going with the diagrams.
so the prototype indicated here is just another object based on which the current object got created, rather than the [[prototype]] property of the current object, is that right?
@photosynthesis: The [[prototype]] property (shown above as __proto__) is a property that refers to the object's prototype, which is "just another object based on which the current object got created". :-) Prototype objects aren't special, they're just normal objects that happen to have another object's [[prototype]] property referring to them.
1

Object.create returns a new object where the supplied argument is the prototype object of the new object.

So you've now got this:

{person2}
    - name:'Alex'
    - {prototype}
        - name:'Quishi'
        - sayName:function

So if you look for the property name on person2, it will find that property on person2 itself, and not look on the prototype. If you look for sayName it will not find it on person2, so it will look on the prototype and find it there.

The this keyword will reference in the function depends on where the function is called FROM. That's just how this works. When you call a method on an object the object will be the this inside that method. So even though the method is on the prototype, this will still reference person2 if you call person2.sayName();. If you were to change that (such as via .call) you could change the output.

console.log(person2.name); // -> Alex

person2.sayName(); // -> Alex
person2.sayName.call(person2.__proto__); // -> Quishi, even though called on person2

person1.sayName(); // -> Quishi
person1.sayName.call(person2); // -> Alex, even though called on person1

I point this out because there's just as much possibility for misunderstanding this in this example as there is for misunderstanding prototypes.

11 Comments

guess I messed up the prototype and the prototype property of the object. To be more specific, when a property is not found in the own properties, the search engine will goes to the prototype of it, which is the object the current instance based on, rather than going to the prototype property of the current instance.
@photosynthesis - what you just said didn't make much sense. First off, understand that Object.create is just a way of making a new object while specifying its prototype (something that wasn't originally publicly accessible on objects). It doesn't play a role in what the fundamental nature of what prototypes are or how they're to be handled. In this case we just specified that we wanted our person2 object's prototype to be the object person1. Therefore when the engine doesn't find a property on person2 and checks person2.__proto__ what it finds IS a reference to person1.
so every object created from object literal has its [[Prototype]] property pointed to the Object.prototype. So what does the [[Prototype]] property of person2 points to, person1 or person1.prototype?
@photosynthesis - In fact, Object.create wasn't even originally part of JS. In fact, all it is is a user made function by Douglas Crockford where he figured out a nice way to make new objects and manually determine their prototype...and the spec makers liked it so much they added it to the actual spec. You are treating it like it's a fundamental part of prototype inheritance itself...it is not. It's just a function for working with prototypes and objects.
@photosynthesis - there's no pointing of [[Prototype]] to Object.prototype...they're just 2 terms for the same thing. The prototype of an object was not traditionally accessible. So it is referred to as the inaccessible property [[Prototype]] to distinguish that we weren't actually talking about a property you could just access with a dot operator. But with functions you can just go .prototype to access it, so some people talk like that with objects even though it doesn't actually work. Both have prototypes...it just wasn't publicly accessible on objects. The new __proto__ changes this.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.