javascript原型继承

med*_*med 16 javascript inheritance prototype

这似乎不一致,但可能是因为我是javascript原型继承功能的新手.

基本上,我有两个基类属性,"列表"和"名称".我实例化两个子类并为属性赋值.当我实例化第二个子类时,它从第一个子类实例获取列表值,但仅用于"列表"而不用于"名称".这是怎么回事??当然,我希望任何后续的子类实例都不会从其他实例获取值,但如果这种情况发生,它应该是一致的!

这是一段代码:

    function A()
    {
        this.list = [];
        this.name = "A";
    }
    function B()
    {
    }
    B.prototype = new A();

    var obj1 = new B();
    obj1.list.push("From obj1");
    obj1.name = "obj1";

    var obj2 = new B();

    //output:
    //Obj2 list has 1 items and name is A
    //so, the name property of A did not get replicated, but the list did
    alert("Obj2 list has " + obj2.list.length + " items and name is "+ obj2.name);    
Run Code Online (Sandbox Code Playgroud)

Mat*_*att 13

原型的东西是,你可以整天读取它们,它不会改变指向什么的底层结构.但是,第一次执行赋值时,您将在实例上替换该属性指向的内容.

在您的情况下,您实际上没有重新分配prototyped属性,您修改了在该属性中找到的底层结构的值.

这意味着共享A原型的所有对象实际上共享 A 的实现.这意味着A中携带的任何状态都将在B的所有实例上找到.在B的实例上对该属性进行赋值的那一刻,你已经有效地替换了那个实例(并且只有那个实例)指向的东西(我相信这是因为B上有一个新的属性"name",在它到达"name"之前在范围链中被命中在A)上实施.

编辑:

为了给出一个更明确的例子:

B.prototype = new A();
var obj1 = new B();
Run Code Online (Sandbox Code Playgroud)

现在,我们第一次进行读取时,解释器会执行以下操作:

obj1.name;
Run Code Online (Sandbox Code Playgroud)

口译员:"我需要属性名称.首先,检查B. B没有'名称',所以让我们继续沿着范围链.接下来,A.Aha!A有'名字',返回那个"

但是,当您执行写操作时,解释器实际上并不关心继承的属性.

obj1.name = "Fred";
Run Code Online (Sandbox Code Playgroud)

解释器:"我需要分配属性'name'.我在B 的这个实例的范围内,所以将'Fred'分配给B.但是我将其他所有内容都放在范围链的另一端(即A)"

现在,下次你做一个阅读...

obj1.name;
Run Code Online (Sandbox Code Playgroud)

翻译:"我需要属性'名称'.啊哈!这个B的实例已经将属性'name'放在它上面.只需返回 - 我不关心范围链的其余部分(即A.name)"

所以,你写的名字第一次时,它把它作为实例第一类属性,已经不关心什么是对AAname是仍然存在,它只是进一步下跌的作用域链,和JS解释没有按在找到它想要的东西之前,要走得那么远.

如果"name"在A中有一个默认值(就像你有的那样,那就是"A"),那么你会看到这种行为:

B.prototype = new A();
var obj1 = new B();
var obj2 = new B();

obj1.name = "Fred";

alert(obj1.name); // Alerts Fred
alert(obj2.name); // Alerts "A", your original value of A.name
Run Code Online (Sandbox Code Playgroud)

现在,就您的数组而言,您实际上从未使用新数组替换作用域链上的列表.你所做的就是抓住数组本身的一个句柄,并为它添加一个元素.因此,B的所有实例都受到影响.

解释:"我需要得到'列表’属性格式,和元素添加进去检查B的这种情况下......不,没有一个'清单’属性然后在作用域链:A.是的,A有'列表',使用它.现在,按下列表"

如果您这样做,情况就不是这样了:

obj1.list = [];
obj1.push(123);
Run Code Online (Sandbox Code Playgroud)


Nic*_*sen 4

  • 您是说在此代码中 B 是 A 的实现。
  • 那么你说 obj1 是 B 的一个新实例,因此应该获取 A 的所有值。
  • 然后,将一个元素添加到 obj2 中列表的引用位置,而 obj2 又将一个元素添加到 A 中列表的引用位置(因为它们引用相同的内容)。
  • 然后更改 obj1 中名称的值。
  • 那么你说 obj2 是 B 的一个新实例,因此应该获取 A 的所有值。

您更改了 A 中引用的列表的值,但未更改引用本身。obj2.name 应该是“A”。