Instructor: To get started, let's do const foo equals an object with name of Tyler, const bar equals an object of last name of Clark. Then we'll do object.setPrototypeOf, bar and foo. Polymorphism or shadowing, is when an inherited property is redefined.
Here, we have two objects, bar and foo. We're setting foo to be the next-in-line prototype of object bar. If we console.log bar.name, we get Tyler, even though name lives on foo, and not bar. Properties that live on the prototype chain can be redefined in all but two cases.
If we commented out name inside the object and did object.definePropertyOf foo, called name, and give it a value of Tyler, but make it writable false, we can see down at the bottom that our console.log is not James anymore, but back to Tyler.
When a property exists up the prototype chain, and that property is configured as writable false, you're not able to assign that property to down-the-chain objects. Even though that configuration does not exist on bar, we cannot set it. It stays and goes back to Tyler.
If we were in strict mode, if we tried to reassign a property, we would get an error. Now, if we were to comment our defined property and make our name a setter, which means we turn it into a function that takes an argument of name.
Let's just assign current name to name. Now, if we look back down to our console.log, we'll see that we get an undefined. If a property is a setter up the chain, then the setter will always be called. The property will not be added to our bar object, and the setter is not redefined.
Since we're calling a setter by doing bar.name, we're going to get an undefined back. If we console.log just bar, we'd see that we get a property, current name of James. To recap, properties with the same key can be defined on a down-the-chain object in all but two cases.
If that same name key is configured writable false, or it's a setter, it cannot be added. In strict mode, trying to assign a same name key that is configured writable false up the chain will throw an error.