call本身不破坏继承关系,它仅临时绑定this,不修改原型链、不挂载方法、不改变对象结构;真正破坏继承的是误将方法赋值到实例或重写原型等后续操作。

直接用 call 借用方法本身不会破坏继承关系——它只是临时指定一次 this,不修改原型链、不重写属性、不改变任何对象的结构。关键在于“怎么调”和“别误操作”。
明确 call 的本质:一次性的 this 绑定
func.call(obj, ...args) 的作用非常单纯:让 func 内部的 this 指向 obj,执行一次,仅此而已。它不复制方法、不挂载到 obj 上、也不影响 obj.__proto__ 或 func.prototype。
- 原对象的
[[Prototype]]不变,子类实例依然能正常访问父类原型上的方法 - 被借用的方法(比如来自
Array.prototype.slice)自身原型链也不受影响 - 没有赋值、没有
Object.assign、没有obj.method = func,就不存在污染目标对象的风险
常见误操作:看似借用,实则悄悄破坏了继承
真正导致继承关系出问题的,往往不是 call,而是后续不当操作:
-
错误地把方法挂到实例上:
obj.clone = Array.prototype.slice.call—— 这会让obj自身拥有了一个不可枚举、非原型方法的clone属性,虽不破坏原型链,但混淆语义,且下次obj.clone()调用时若忘了传this,会出错 -
用 call 改写原型上的方法:
SomeConstructor.prototype.method = function() { return Array.prototype.slice.call(arguments); }—— 这本身没问题;但若误写成SomeConstructor.prototype = { method: ... },就切断了原有原型链 -
在借用时意外覆盖了 this 的原始行为:比如对类数组对象调用
Array.prototype.push.call(arrLike, item)是安全的;但如果对普通对象乱用Array.prototype.map.call(obj, ...),因对象没有length和数字键,结果不可预期,但这属于逻辑错误,不是继承被破坏
安全借用的推荐写法
聚焦“只调用、不留存、不改链”:
-
即用即调,不保存引用:
const args = Array.prototype.slice.call(arguments, 1);—— 经典类数组转数组,无副作用 -
封装为纯函数,隔离 this 依赖:
const toArray = obj => Array.prototype.slice.call(obj);
调用时toArray(nodelist),不碰任何对象的原型 -
借用构造器时用 Object.create 配合 call(模拟继承式创建):
function Child() { Parent.call(this, ...arguments); }<br>Child.prototype = Object.create(Parent.prototype);<br>Child.prototype.constructor = Child;这里Parent.call只负责初始化实例属性,原型链由Object.create显式建立,清晰可控
验证是否真的没破坏继承
借用后快速检查两件事:
-
obj instanceof OriginalConstructor仍为true?→ 说明原型链未断 -
obj.__proto__ === OriginalConstructor.prototype?→ 若为true,说明没被意外重写 - 在
obj上新增属性后,obj.hasOwnProperty('newProp')为true,而'method' in obj为false(如果只是 call 借用过,没挂载)→ 说明没污染实例
call 本身是中立工具,像一把刀,切菜不伤砧板。问题总出在握刀的手势上:别把方法钉在对象身上,别重写原型,别混淆调用上下文。用得干净,继承自然稳固。










