使用call()实现继承:为何其效果在后续创建实例时仍持续?
嘿,这个问题刚好戳中了JavaScript原型机制和call()方法结合的核心,我给你一步步拆解清楚~
首先先把你提到的示例补全,方便对照着说:
// 定义一个混入函数,给对象添加圆形相关方法 var asCircle = function() { this.area = function() { return Math.PI * this.radius * this.radius; }; this.grow = function() { this.radius += 1; }; this.shrink = function() { this.radius -= 1; }; }; // 基础构造函数 function Shape(x, y) { this.x = x; this.y = y; } // 关键调用:把asCircle的this绑到Shape.prototype上 asCircle.call(Shape.prototype); // 创建新实例 var myCircle = new Shape(10, 20); myCircle.radius = 5; console.log(myCircle.area()); // 输出约78.54
核心原因拆解:
call()的本质是改变this指向
当你执行asCircle.call(Shape.prototype)时,你强制让asCircle函数内部的this指向了Shape.prototype这个对象。也就是说,asCircle里所有this.xxx = ...的赋值操作,其实都是在给Shape.prototype添加属性和方法——相当于把area、grow、shrink直接挂到了Shape的原型上。原型链的继承规则
JavaScript中,用new Shape()创建的实例,它的内部原型(__proto__)会直接指向Shape.prototype。实例在访问某个方法时,会先看自己有没有,如果没有就顺着原型链往上找。只要Shape.prototype上有这些方法,不管实例是在call()调用前还是之后创建的,只要call()执行过,原型上的方法就已经存在了,后续的新实例自然能继承到这些方法。对比一下你可能误解的点
你可能以为call()只是临时给某个对象加方法,但这里我们绑的是构造函数的原型对象,而原型对象是所有实例共享的“公共仓库”。一旦这个仓库里多了方法,所有后续创建的实例都能从仓库里拿到这些方法,这就是效果一直存在的原因。
如果还是有点懵,你可以把Shape.prototype想象成一个共享的工具箱:call()操作就是把asCircle里的工具(方法)放进这个工具箱里,之后所有新做出来的Shape实例(比如myCircle)都能直接用这个工具箱里的工具~
内容的提问来源于stack exchange,提问作者Barleby

