原型链中‘new person()’与‘person.prototype’的区别及继承疑问
关于JS原型继承的两个核心问题解答
嘿,这个问题问到点子上了,原型继承里这两个细节很容易搞混,我来给你拆解清楚:
1. 直接用person1.prototype = person.prototype继承父类原型属性是否正确?
答案是:绝对不推荐,甚至可以说是错误的做法。
原因很简单:JavaScript里对象是引用类型,当你把person.prototype直接赋值给person1.prototype时,二者指向的是同一个内存地址的对象。这意味着后续你给子类原型添加的任何方法(比如你的代码里的tellMyAge),都会直接修改父类的原型对象。
举个直观的例子,如果你这么写:
person1.prototype = person.prototype; person1.prototype.tellMyAge = function () { console.log(this.age); } // 现在父类的实例也能调用子类的方法了! const parentInst = new person("Bob"); parentInst.tellMyAge(); // 输出undefined(因为父类实例没有age属性)
这完全违背了继承的初衷——我们希望子类拥有自己独立的原型,不会影响父类的原型和实例。
2. 原型链中new person()与person.prototype的区别
这两者本质是完全不同的对象,放在原型链里的作用也天差地别:
① person.prototype:父类的原型对象本身
- 它是一个普通对象,是所有父类实例的
__proto__指向的目标。 - 如果把它赋值给子类原型,子类和父类会共享同一个原型对象,就会出现上面说的“子类修改原型影响父类”的问题。
- 此时子类实例的原型链是:
子类实例 -> person.prototype -> Object.prototype
② new person():父类的一个实例对象
- 当你调用
new person()时,会创建一个新对象,这个新对象的__proto__会指向person.prototype,同时会执行父类构造函数里的代码(给实例添加属性,比如你的代码里的this.myName)。 - 把这个实例赋值给子类原型后,子类原型是一个独立的对象(父类实例),子类添加新方法只会修改这个独立对象,不会影响父类的原型。
- 此时子类实例的原型链是:
子类实例 -> new person()实例 -> person.prototype -> Object.prototype
不过这里要补充一个小细节:用new person()作为子类原型的话,父类构造函数里的实例属性(比如myName)会被继承到子类原型上(值是undefined,因为你调用new person()时没传name参数),这其实是不必要的。所以更优雅的做法是用Object.create(person.prototype)来创建一个以person.prototype为原型的空对象,避免继承这些多余的实例属性:
person1.prototype = Object.create(person.prototype); // 别忘了把子类原型的constructor指回自己,不然会指向person person1.prototype.constructor = person1;
回到你的代码,你用new person()的方式是可行的(虽然有小瑕疵),但绝对不能直接赋值person.prototype给子类原型。
内容的提问来源于stack exchange,提问作者SameerShaik
相关产品推荐
相关产品推荐

