js原型问题,在循环中创建对象出了些问题

题目描述

我在map中创建对象输出结果和我想象的不同求大佬解答,谢谢了

相关代码

// 请把代码文本粘贴到下方(请勿用图片代替代码)
function Test(num, func) {

 let _num = num
 Test.prototype.num = 0
 Test.prototype.test = () => {
     console.log(this)
     console.log(_num)
     func()
 }

}
test_list = [1, 2, 3, 4].map((x, i)=>{

return new Test(i, function(){
      console.log(this)
})

})

test_list[0].test() => 3
test_list[1].test() => 3
test_list[2].test() => 3
test_list[3].test() => 3
为什么list中的Test实列的_num都是3啊

你期待的结果是什么?实际看到的错误信息又是什么?

为什么都是最后一个index, 而不是0,1,2, 但在循环中输出又是正常的了, 最后列表中又不正常。

后续测试的确是这样的

function Test() {

let _num = 0;
Test.prototype.show = () =>{
   console.log(_num)
};
Test.prototype.add = (num) =>{
   _num = _num + num
   this.number = num
};
Test.prototype.number = 0

}

t1 = new Test()
t2 = new Test()
t1.add(12)
t1.show => 12
t2.show => 12
t1.number => 12
t2.number => 0

_num在同个栈中??? 1.问题1
number是在不同对象中的???,所以这样保存子对象数据???2.问题2
this的指向问题3.问题3
待解决

阅读 2.3k
3 个回答

原型上的属性和方法是公用的。
路线如下:

// x = 1, i = 0
Test.prototype.num = 0

// x = 2, i = 1
Test.prototype.num = 1

// x = 3, i = 2
Test.prototype.num = 2

// x = 4, i = 3
Test.prototype.num = 3

然后你调用test的时候,这时候num已经被修改成3了,所以结果都是3
然后你执行的回调func,this指向丢失,所以指向Window

现在回答下你的后续测试问题
其实你的后续测试的代码让我想了蛮久, 你的后续测试结果是错误的

function Test() {

let _num = 0;
Test.prototype.show = () =>{
   console.log(_num)
};
Test.prototype.add = (num) =>{
   _num = _num + num
   this.number = num
};
Test.prototype.number = 0
}

t1 = new Test()
t2 = new Test()
t1.add(12)
t1.show => 12
t2.show => 12
t1.number => 12
t2.number => 0

这个代码简化下可以变成

function Test() {
    Test.prototype.add = num => {
      this.number = num
    }
    Test.prototype.number = 0
  }

t1 = new Test()
t2 = new Test()
t1.add(12)
var a = t1.number
var b = t2.number
console.log(a, b) // => 0,12

结果应该是0,12。 这个问题答案详见一个黑科技版的this指向问题

好了,回答你的问题

1._num在同个栈中???

_num是Test构造函数里的变量,构造函数也是函数,你就可以把它看成函数中的变量。

var t1 = new Test() // 这时候执行Test函数,把_num赋值为0
var t2 = new Test() // 这时候再次执行Test函数,把_num重新赋值为0
t1.add(12)  // 这时候把Test的_num 变为12, 改的是Test函数中的变量_num
t1.show() // 打印Test函数中的变量_num, 即12
t2.show() // 打印Test函数中的变量_num, 即12

2. number是在不同对象中的???,所以这样保存子对象数据???

这里的用法有点不对,其实number都是在最后的实例对象中。并不会给每个实例对象赋值上一个number(add函数重新赋值和箭头函数改变this执行)

正确点的写法

function Test(number){
    this.number = number;
 }
Test.prototype.add = function(num){
    this.number += num;
 }
Test.prototype.show = function(){
    console.log(this.number)
}

var t1 = new Test(1)
var t2 = new Test(2)
t1.add(12)
t1.show() // 13
t2.show() // 2
console.log(t1.number) // 13
console.log(t2.number) // 2

3.this的指向问题

自己多看书,推荐《你不知道的JavaScript上》

prototype内定义的属性或方法是所有实例间共享的,所以你map的时候,每次都覆盖了之前定义的test()方法

谢谢各位的答案,查阅了信息得到
1.问题1和问题2
_num类似于Test.prototype.num是所有子对象共有的
要子对象私有的话可以用this取代详情看下(动态原型模式)
this.num是子对象中单独创建的详情看下方代码
function Test() {

this.num1 = 123
Test.prototype.num2 = 123

}

t1 = new Test() => Test {num: 123}
t1有单独的num1 123
t1.num2 ==> 123
t2 = new Test() => Test {num: 123}
t1.num2 = 234 => Test {num1: 123, nun2: 234} //不可以是指向类型的
t2.num2 => 123

问题3 是来源我之前写了个vue的加载包装器莫名奇妙的写对了分享给大家吧(this指向问题还是建议参考其他答案的)
import { createDecorator } from 'vue-class-component';
export function AxiosMounted(request: string): any {

return createDecorator(function (componentOptions: any, target) {
    let mountedList:Function[] = []
    if (componentOptions.mounted) {
        mountedList.push(componentOptions.mounted)
    }
    let requestPath: any = API
    componentOptions.mounted = async function () {
      //...异步方法 可以换成created
    }
    mountedList.push(componentOptions.mounted)
    componentOptions.mounted = mountedList //ps: 不光可以是函数哦list也可以哦有bug
    })

}

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题