0

我对原型继承的理解是每个对象都有一个原型属性。如果对象上不存在属性,则检查其原型对象,依此类推。

在这个例子中,我的原型对象是一个带有计数器属性的简单对象。

我希望每个实例都共享相同的原型,但它们似乎获得了新实例。这段代码的输出是 00,我期待的是 01。

我错过了一些明显的东西吗?

"use strict";

var ConstructorFunction = function () {};

ConstructorFunction.prototype = {
    counter: 0,
    count: function () {
        return this.counter++;
    }
};

var a = new ConstructorFunction();
var b = new ConstructorFunction();

$("#output").append(a.count());
$("#output").append(b.count());

这是jsfiddle:http: //jsfiddle.net/hdA6G/5/

4

5 回答 5

4

确实,原型属性是所有实例共享的。问题是您永远不会更改原型属性。用一些额外的日志看看你的小提琴:

"use strict";

var ConstructorFunction = function () {};

ConstructorFunction.prototype = {
    counter: 0,
    count: function () {
        return ++this.counter;
    }
};

var a = new ConstructorFunction();
var b = new ConstructorFunction();

$("#output").append(a.hasOwnProperty("counter") + " "); //false
a.count();
$("#output").append(a.hasOwnProperty("counter") + " "); //true

如您所见,只要您调用++this.counter,就会创建一个本地属性,该属性将从该属性开始使用。

假设这就是发生的事情:

++this.counter被解释为this.counter = this.counter + 1。首先,计算等号的右部分,并且由于您的实例没有counter属性,因此使用原型的 counter 属性。此属性的值将加到 1,然后分配给this.counter,它现在创建一个本地属性,就像分配一个根本不存在的属性时一样,例如a.xy = 1. xy在这种情况下,将是实例的本地属性。

编辑

有两种解决方法仍然可以让您使用原型属性:

1)在方法内部显式设置原型属性count

ConstructorFunction.prototype.count = function() {
    return ++this.constructor.prototype.counter;
};

2) 调用 count 方法apply并将原型用作上下文:

a.count.apply(a.constructor.prototype);

但是,如果您prototype按照自己的方式设置属性,这两种方法都会出现问题。

 ConstructorFunction.prototype = {
     //...
 };

这会覆盖完整的原型对象,因此也会覆盖它的构造函数属性。构造函数属性现在将指向原型链中的下一个更高的对象,即Object对象。要解决这个问题,您可以在分配原型对象后手动设置构造函数:

ConstructorFunction.prototype.constructor = ConstructorFunction;

或分别分配原型对象的每个属性:

ConstructorFunction.prototype.counter = 0;
ConstructorFunction.prototype.count = function () {
    return ++this.counter;
};
于 2013-06-04T07:13:51.460 回答
3

考虑使用闭包,这样您就可以将该变量保持为私有并在实例之间共享:

var Class = (function ClassModule() {

  var counter = 0;

  function Class() {}

  Class.prototype = {

    count: function() {
      return counter++;
    }
  };

  return Class;
}());

var class1 = new Class();
var class2 = new Class();

console.log(class1.count()); //=> 0
console.log(class2.count()); //=> 1

counter变量与闭包(模块模式)保持在上下文中,并且不会与每个新实例重复。

于 2013-06-04T06:47:43.947 回答
1

在基于原型的 OOD 中,共享意味着共享相同的定义并将其用于不同的上下文。如果您需要在上下文之间共享静态属性,您可以执行以下操作

var ConstructorFunction = function (context) {
    this.count = function () {
        return context + "," + (++this.counter) + "," + (++ConstructorFunction.staticCounter);
    };
};

ConstructorFunction.prototype.counter = 0;

ConstructorFunction.staticCounter = 0;

var context1 = new ConstructorFunction("context1");
var context2 = new ConstructorFunction("context2");

$("#output").append(context1.count());
$("#output").append(" ");
$("#output").append(context2.count());

http://jsfiddle.net/hdA6G/1/

以及更好的定义方式

var ConstructorFunction = function (context) {
    this.context = context;
    this.counter = 0;
};
ConstructorFunction.staticCounter = 0;

ConstructorFunction.prototype.count = function () {
    return this.context + "," + (++this.counter) + "," + (++ConstructorFunction.staticCounter);
};

http://jsfiddle.net/hdA6G/3/

于 2013-06-04T06:37:56.193 回答
0

你有你的继承,原型继承自基础对象。我认为这与您要完成的工作更相似。

function MyObject () {
    this.count = 0;
};

ConstructorFunction.prototype = {
    counter: function () {
        return this.count++;
    },
    print: function () {
        return this.count;
    }
};


Var Foo = new MyObject();

console.log(Foo.counter()); // 1
console.log(Foo.counter()); // 2
console.log(Foo.print()); // 2

我希望这有帮助。

编辑

如果您希望在所有实例之间共享您的计数器,那么它应该进入您的基础对象。

function MyObject () {
    this.count = 0;
    this.counter = function () {
        return this.count++; //may not need the this
    }
};
于 2013-06-04T06:35:08.983 回答
0

我知道这是一篇旧帖子,但我是 Javascrpt 的新手,在试验时我遇到了类似的东西,所以想投入我的 2 美分。

似乎每个对象在使用new. 从那时起,访问 usingthis将进行通常的查找并找到被操作的私有副本。

但是,如果您在创建所有对象创建原型变量,则该变量将被共享并且行为类似于静态。我认为这很容易解释为什么会发生这种情况,但是,尽管如此,我发现这是一个有趣的 hack。我不确定这是否是可能在未来版本中解决的技术规范中的错误,或者标准行为的副作用,所以不知道这是否可靠。我什至不确定这是否是该语言更高版本中新引入的“功能”。实际上,我开始在谷歌上搜索这个事实并发现了这篇文章。

试试这个代码。

var Worker = function (name) {
    this.name = name;
}
Worker.prototype.jobs = 0;
Worker.prototype.Work = function () {
    console.log("jobs finished", this.name, ++this.jobs);
}
Worker.prototype.WorkCount = function () {
    console.log("work count", this.name, this.workCount);
}
var ca = new Worker("ca");
var cb = new Worker("cb");
ca.Work();// shows 1
cb.Work();// shows 1
ca.WorkCount();// shows undefined
cb.WorkCount();// shows undefined
Worker.prototype.workCount = 2;
ca.WorkCount();// shows 2
cb.WorkCount();// shows 2
于 2016-06-12T08:22:28.150 回答