Javascript和函数原型赋值

时间:2011-10-03 05:04:37

标签: javascript prototype-programming

我总是假设函数的原型在所有对象之间共享,在某种意义上是通过引用。因此,如果更改原型属性的值,则共享该原型的所有对象的值也会更改。因此,例如下面似乎不是在所有对象之间共享属性栏,而是复制它。这是正确的吗?构造函数原型的属性是在创建时简单地复制到所有类对象,还是由链接共享?

function foo()
{
     this.bar = 1;
}
function derived() { }
derived.prototype = new foo()

object1 = new derived()
object2 = new derived()

object1.bar = 2;
//but notice if I had said here derived.prototype.bar = 3, object1.bar would still equal 2 but object2.bar would equal 3
alert(object2.bar) // this prints 1;

2 个答案:

答案 0 :(得分:12)

当您指定object1.bar = 2时,您正在object1上创建自己的属性,此属性仅存在于该对象实例中,并且与其原型无关

object1上的此属性将 shadow derived.prototype上现有的值,这意味着当您查找object1.bar时,它会找到一个值直接存在于该对象上。

另一方面,如果查找object2.bar,则此对象没有自己的bar属性,因此属性查找将搜索此继承自的对象({{1} })它会找到值derived.prototype

您的对象结构如下所示:

 object1
 --------
| bar: 2 | -----------------
 --------                   |         derived.prototype
                            |        ----------
                            |------> | bar: 1  | --    foo.prototype
 object2 (no own properties)|        ----------   |   ------------------
 --------                   |                     -> | constructor: foo |
|        | -----------------                          ------------------
 --------                                                    |
                                                             v
                                                     ------------------
                                                    | Object.prototype |
                                                     ------------------
                                                             |
                                                             v
                                                            null

1行表示表示继承的内部--->链接。

答案 1 :(得分:2)

例如,您有代码:

function Animal() {
}
Animal.prototype.name="animal";

function Dog() {
}
Dog.prototype = new Animal
Dog.prototype.constructor=Dog;
Dog.prototype.name="dog";

object1 = new Animal();
object2 = new Dog();

结果你有两个对象实例,看起来像(你可以在Chrome devtools或FF firebug或者......中查看这个例子):

object1:
  __proto__: (is ref into an Animal.prototype object)
    constructor: function Animal()
    name: "animal"
    __proto__: Object (is ref into an Object.prototype object)

object2:
  __proto__: (is ref into an Dog.prototype object)
    constructor: function Dog()
    name: "dog"
    __proto__: (is ref into an Animal.prototype object)
      constructor: function Animal()
      name: "animal"
      __proto__: (is ref into an Object.prototype object)

当您运行下一个代码时(例如):

alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "dog"

发生什么事了? 1)Javascript在对象实例中查找属性名称(在object1object2中)。 2)未找到时,它在对象实例 proto 属性中查找(与类函数的原型相同)。 3)当没有找到它时,它会看到 proto proto 以及下一个和下一个,而找不到name属性和其他 proto 。如果找到搜索属性的结果,则返回值,如果未找到,则返回undefined

如果执行下一个代码会发生什么:

object2.name = "doggy";

结果你得到了object2:

object2:
  name: "doggy"
  __proto__: (is ref into an Dog.prototype object)
    constructor: function Dog()
    name: "dog"
    __proto__: (is ref into an Animal.prototype object)
      constructor: function Animal()
      name: "animal"
      __proto__: (is ref into an Object.prototype object)

属性直接分配给实例对象,但原型对象保持不变。当你执行:

alert(object1.name); // displayed "animal"
alert(object2.name); // displayed "doggy"

当您需要创建类的共享属性时,您可以使用下一个算法中的一个: 1)

Animal.prototype.secondName="aaa";
alert(object1.secondName); // displayed "aaa"
alert(object2.secondName); // displayed "aaa"
Animal.prototype.secondName="bbb";
alert(object1.secondName); // displayed "bbb"
alert(object2.secondName); // displayed "bbb"
// but
Animal.prototype.secondName="ccc";
object1.secondName="ddd";
alert(object1.secondName); // displayed "ccc"
alert(object2.secondName); // displayed "ddd"

2) 在函数类的原型中创建类型object的属性,并为该对象的属性赋值。

Animal.prototype.propObject={thirdName:"zzz"};
alert(object1.propObject.thirdName); // displayed "zzz"
alert(object2.propObject.thirdName); // displayed "zzz"
Animal.prototype.propObject.thirdName="yyy";
alert(object1.propObject.thirdName); // displayed "yyy"
alert(object2.propObject.thirdName); // displayed "yyy"
object1.propObject.thirdName="xxx";
alert(object1.propObject.thirdName); // displayed "xxx"
alert(object2.propObject.thirdName); // displayed "xxx"
object2.propObject.thirdName="www";
alert(object1.propObject.thirdName); // displayed "www"
alert(object2.propObject.thirdName); // displayed "www"