JavaScript:Object.create与Object.assign实现原型继承的区别及疑问
Object.create(Sup.prototype) Instead of Object.assign({}, Sup.prototype) for JavaScript Inheritance? Great question! This is a super common point of confusion when learning prototype-based inheritance in JavaScript. Let’s break down the core differences between these two approaches and why Object.create(Sup.prototype) is the standard go-to.
Key Difference: Prototype Chain vs. Static Property Copy
The entire point of JavaScript inheritance is the prototype chain—the ability for an object to access properties and methods from its parent prototype, even as that parent prototype evolves. Let’s look at how each method handles this:
1. Object.create(Sup.prototype): Builds a Live Prototype Chain
When you run Sub.prototype = Object.create(Sup.prototype), you’re creating a new object whose hidden internal [[Prototype]] reference points directly to Sup.prototype. This establishes a dynamic, live link between the child and parent prototypes:
- Any new methods or properties added to
Sup.prototypelater will automatically be accessible to instances ofSub(as long as the instance doesn’t override them). - The
instanceofoperator works as expected: aSubinstance will correctly be recognized as an instance ofSup. - Even non-enumerable properties on
Sup.prototypeare accessible via the prototype chain.
2. Object.assign({}, Sup.prototype): Only Copies Enumerable Properties
Object.assign({}, Sup.prototype) creates a blank object and copies all enumerable own properties from Sup.prototype into it. The catch? This new object’s prototype is the default Object.prototype—it has no connection to Sup.prototype at all. This means:
- Any updates to
Sup.prototypeafter the copy won’t trickle down toSubinstances, since there’s no live prototype chain link. instanceof Supwill returnfalseforSubinstances, because their prototype chain doesn’t includeSup.prototype.- Non-enumerable properties on
Sup.prototypewon’t be copied over, so they’re completely inaccessible toSubinstances.
Concrete Example to See the Gap
Let’s test both approaches with code to highlight the real-world differences:
// Parent constructor function Sup() {} Sup.prototype.sayHello = function() { console.log('Hello from Sup!'); }; // Add a non-enumerable property to the parent prototype Object.defineProperty(Sup.prototype, 'secretProp', { value: 'I am hidden', enumerable: false }); // Approach 1: Object.create (proper inheritance) function Sub1() {} Sub1.prototype = Object.create(Sup.prototype); Sub1.prototype.constructor = Sub1; // Fix constructor reference // Approach 2: Object.assign (property copy, not inheritance) function Sub2() {} Sub2.prototype = Object.assign({}, Sup.prototype); Sub2.prototype.constructor = Sub2; // Test initial behavior const sub1 = new Sub1(); const sub2 = new Sub2(); sub1.sayHello(); // Output: "Hello from Sup!" (works via prototype chain) sub2.sayHello(); // Output: "Hello from Sup!" (works via copied property) // Now add a new method to the parent prototype Sup.prototype.sayHi = function() { console.log('Hi from Sup!'); }; sub1.sayHi(); // Output: "Hi from Sup!" (inherited via prototype chain) sub2.sayHi(); // Error: sub2.sayHi is not a function (no link to parent prototype) // Check instanceof console.log(sub1 instanceof Sup); // true (correct prototype chain) console.log(sub2 instanceof Sup); // false (no chain connection) // Access non-enumerable property console.log(sub1.secretProp); // "I am hidden" (accessible via prototype chain) console.log(sub2.secretProp); // undefined (not copied by Object.assign)
Summary
Object.create(Sup.prototype) is the right choice because it implements the actual prototype chain that defines JavaScript’s inheritance model. It maintains a dynamic link between child and parent prototypes, preserving all the expected inheritance behaviors. Object.assign only creates a static copy of properties, breaking the prototype chain and losing key inheritance features.
内容的提问来源于stack exchange,提问作者karthikaruna




