H5W3
当前位置:H5W3 > 其他技术问题 > 正文

【Web前端问题】js 构造函数私有变量的问题

示例代码如下:

function foo () {
  var bar = 0;
  this.set_one = function (x) { 
    bar = x; 
  }
  this.get_one = function () { 
    return bar; 
  }
  foo.prototype.set_all = function (x) { 
    bar = x; 
  }
  foo.prototype.get_all = function () { 
    return bar; 
  }
}

var a = new foo()
var b = new foo()
var c = new foo()

// 以下代码每次打开一条,测试返回结果
// a.set_one(1)  - 返回 1 0 0 0 0 0
// a.set_all(1)  - 返回 0 1 0 1 1 1
// b.set_one(1)  - 返回 0 0 1 0 0 0
// b.set_all(1)  - 返回 0 1 0 1 1 1
// c.set_one(1)  - 返回 0 1 0 1 1 1
// c.set_all(1)  - 返回 0 1 0 1 1 1

console.log(a.get_one(), a.get_all(), b.get_one(), b.get_all(), c.get_one(), c.get_all())

问题:解释这种结果出现的原因。
我对这个问题比较不解,主要困惑在于这个私有变量bar,如果说在这里这个bar在foo的实例和prototype上都创建了一个,并且互不相干,可以解释a和b的结果,但是这个实例c里的bar和foo的prototype是完全同步的,感觉又像是同一个变量。
我测试了下,如果把c去掉,那么b的表现就和被去掉之前的c一样了,也就是说,最后一个创建的实例就会和前面所有的实例表现相背。
希望各位高手能给解释下其中的原理。

感谢回答的同学,我试着用自己对该回答的理解解释一下这个问题:
当创建第一个对象a时,设a的bar存储于地址1,a.get/set_one和a.get/set_all都是访问地址1的bar.
当再创建一个对象b时,设b的bar存储于地址2,那么b.get/set_one和b.get/set_all是访问地址2的bar,但由于get/set_all是原型方法,所以a.get/set_all也变成了访问地址2的bar
依次类推,当创建对象c时,c.get/set_one是访问地址3的bar,而所有对象的get/set_all也都变成了访问地址3的bar。
用一个表来表示,就是:

操作 a.get_one() a.get_all() b.get_one() b.get_all() c.get_one() c.get_all()
bar内存地址 1 3 2 3 3 3
a.set_one(修改地址1) 1 0 0 0 0 0
a.set_all(修改地址3) 0 1 0 1 1 1
b.set_one(修改地址2) 0 0 1 0 0 0
b.set_all(修改地址3) 0 1 0 1 1 1
c.set_one(修改地址3) 0 1 0 1 1 1
c.set_all(修改地址3) 0 1 0 1 1 1

ps: sf你这个markdown有问题啊,为什么居中对表头无效啊。。

回答:

当你只new一个实例的时候,显而易见,foo.prototype函数中引用的bar和实例中函数引用的bar是同一个。当你继续new一个函数的时候,实例中的属性会重新开一个新的内存地址,但是prototype中的不会,都是指向同一个对象,但是新new出来对象后,foo.prototype函数引用的bar其实是你最后一个bar。所以你调用前面的set_all其实都是修改最后一个实例中的bar。反之你修改最后的bar也会影响前面对象的get_all

回答:

js高程3第145页
用new操作符创建一个新实例,会经历4个步骤
1、创建一个新对象;
2、将构造函数的作用域赋给新对象;
3、执行构造函数代码;
4、返回新对象。

      foo.prototype.set_all = function (x) { 
        bar = x; 
      }
      foo.prototype.get_all = function () { 
        return bar; 

这段代码每次new新实例都会执行,对同1变量重复声明,会执行后续声明中的初始化。

function Foo(){
    var bar = "a";
    this.setone = function(x){
        bar = x;
    };
    this.getone = function(){
        return bar;
    };
    if(typeof this.setall !="function")
    {
        Foo.prototype.setall = function(x){
            bar = x;
        }
    };
    if(typeof this.getall !="function")
    {
        Foo.prototype.getall = function(){
            return bar;
        };
    }
}
var a = new Foo();
var b = new Foo();
var c = new Foo();
a.setone("b");
console.log(a.getone(),a.getall(),b.getone(),b.getall(),c.getone(),c.getall());

如果换成上面的代码输出b b a b a b,也就是110101

本文地址:H5W3 » 【Web前端问题】js 构造函数私有变量的问题

评论 0

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址