对象内部别名指向异常:创建正常后续指向最后对象的原因与解决
问题分析与解决
问题代码
function obj() {}; obj.prototype.custom = function () { this.custom.alias = this; this.check(); } obj.prototype.check = function () { console.log(this === this.custom.alias); } os = []; for (let i = 1; i <= 10; i++) { let o = new obj(); o.custom(); os.push(o); } for (let o of os) { o.check(); }
问题现象
创建10个对象时,每次调用custom()都会输出true;但循环结束后遍历所有对象调用check(),前9个都会输出false,只有最后一个是true。
问题原因
核心问题出在**this.custom指向的是原型链上的共享函数**:
obj.prototype.custom是定义在原型上的方法,所有obj实例都会共享同一个custom函数对象。- 当你执行
this.custom.alias = this时,并不是给当前实例添加属性,而是给原型上的那个custom函数添加alias属性。 - 每次创建新实例调用
custom(),都会覆盖custom函数的alias属性,最后这个alias会指向最后一个创建的实例。 - 所以后续所有实例调用
check()时,this.custom.alias取的都是原型上custom函数的alias,自然只有最后一个实例能匹配上。
解决方法
要让每个实例的别名只指向自己,需要给每个实例单独存储别名,而不是复用原型上的函数属性,有两种常用方式:
方法1:给实例添加独立属性存储别名
修改custom和check方法,把别名存在实例自身的属性里:
function obj() {}; obj.prototype.custom = function () { // 给当前实例添加_alias属性,指向自身 this._alias = this; this.check(); } obj.prototype.check = function () { console.log(this === this._alias); } os = []; for (let i = 1; i <= 10; i++) { let o = new obj(); o.custom(); os.push(o); } for (let o of os) { o.check(); }
这样每个实例的_alias都是自己的属性,互相独立,不会被覆盖。
方法2:给每个实例分配独立的custom方法
如果一定要保留custom.alias的形式,可以在构造函数里给每个实例创建专属的custom函数,这样每个实例的custom都是独立的,它的alias也不会互相影响:
function obj() { // 每个实例都有自己的custom函数 this.custom = () => { this.custom.alias = this; this.check(); } }; obj.prototype.check = function () { console.log(this === this.custom.alias); } os = []; for (let i = 1; i <= 10; i++) { let o = new obj(); o.custom(); os.push(o); } for (let o of os) { o.check(); }
这种方式虽然能实现需求,但每个实例都创建新函数,会增加内存开销,一般推荐第一种方法。
内容的提问来源于stack exchange,提问作者user24161494
相关产品推荐
相关产品推荐

