在JavaScript类中具有相同的方法或变量名称时,行为会有所不同。

huangapple go评论91阅读模式
英文:

same method or variable name in a javascript class behaves differently

问题

class Parent{
method(){
console.log("Parent");
}
}
class Child extends Parent{
method(){
console.log("Parent");
}
}
var child = new Child();
console.log(child.method);
// 控制台返回在子类中的方法,这是预期的行为。

class Parent{
method = "sss";
}
class Child extends Parent{
method(){
console.log("Child");
}
}
var child = new Child();
console.log(child.method);
// 为什么控制台返回父类中的方法变量 - "sss"?

英文:
class Parent{
    method(){
        console.log("Parent");
    }
}
class Child extends Parent{
    method(){
        console.log("Parent");
    }
}
var child = new Child();
console.log(child.method);

console return method in child class which is a expected behaviour.

class Parent{
    method = "sss"
}
class Child extends Parent{
    method(){
        console.log("Child")
    }
}
var child = new Child();
console.log(child.method)

why does the console return method variable - "sss" in Parent class ?

答案1

得分: 4

class Parent {
    method = "sss";
}

是下面代码的简化形式:

class Parent {
    constructor() {
        this.method = "sss";
    }
}

这意味着与以下方式存在一些重要的差异:

class Parent {
    method() {
        console.log("Parent");
    }
}
  1. method = "sss"的变体中,method将设置为创建的实例(new Child())的自有属性。

    child.hasOwnProperty("method") // => true
    

    而定义普通方法method() { console.log("Parent") }将不会设置为实例的自有属性。相反,它会设置在原型链上。

    Parent.prototype.hasOwnProperty("method") // => true
    
  2. 构造函数代码仅在初始化实例时运行。这意味着this.method = "sss"将始终在你定义ParentChild类之后运行(每当你使用new创建实例时)。

最终的Child实例结构如下:

new Child()
// 返回
Child{ // 使用对象表示法描述的Child实例
  // 自有属性
  prop: "parent value", // 由Parent构造函数设置

  // 使用__proto__(已弃用)属性描述的原型链
  __proto__: {
    // Child.prototype
    prop() { return "child Value" },
    method() { console.log("Child") },

    __proto__: {
      // Parent.prototype
      method() { console.log("Parent") },
    }
  }
}

要获取更详细的信息,建议阅读MDN上的Public class fields页面。

英文:
class Parent {
    method = "sss";
}

Is essentially a shortcut for:

class Parent {
    constructor() {
        this.method = "sss";
    }
}

Meaning that there are some important differences with:

class Parent {
    method() {
        console.log("Parent");
    }
}
  1. In the method = "sss" variant, method will be set as an own property of the created instance (new Child()).

    child.hasOwnProperty("method") //=> true
    

    Whereas defining a normal method method() { console.log("Parent") } will not be set as an own property of the instance. Instead it is set on the prototype chain.

    Parent.prototype.hasOwnProperty("method") //=> true
    
  2. The constructor code only runs whenever you initialize an instance. Meaning that this.method = "sss" will always run after you've defined the Parent and Child classes (whenever you create the instance with new).

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

class Parent {
    prop = &quot;parent value&quot;;
    // aka
    // constructor() {
    //   this.prop = &quot;parent value&quot;;
    // }
    method() {
        console.log(&quot;Parent&quot;);
    }
}

class Child extends Parent {
    prop() {
      return &quot;child Value&quot;;
    }
    method() {
        console.log(&quot;Child&quot;);
    }
}

const child = new Child();

const log = (jsString) =&gt; console.log(jsString, &#39;//=&gt;&#39;, eval(jsString));
log(`child.hasOwnProperty(&quot;prop&quot;)`);
log(`child.hasOwnProperty(&quot;method&quot;)`);
log(`Parent.prototype.hasOwnProperty(&quot;prop&quot;)`);
log(`Parent.prototype.hasOwnProperty(&quot;method&quot;)`);

<!-- end snippet -->

The final Child instance structure looks like this:

new Child()
// returns
Child{ // Child instance depicted using object notation
  // own properties
  prop: &quot;parent value&quot;, // set by the Parent constructor

  // prototype chain depicted using the __proto__ (deprecated) property
  __proto__: {
    // Child.prototype
    prop() { return &quot;child Value&quot; },
    method() { console.log(&quot;Child&quot;) },

    __proto__: {
      // Parent.prototype
      method() { console.log(&quot;Parent&quot;) },
    }
  }
}

For more detailed info I suggest reading through the MDN Public class fields page.

答案2

得分: 2

MDN

公共实例字段要么在基类的构造函数中(在构造函数体运行之前)添加到实例中,要么在子类中的super()返回后立即添加。

即它掩盖了方法,因为它是在构造函数运行时分配的。

child.method是对象本身的属性(其值为字符串),这会掩盖原型上的method,而原型上的method是一个函数。

下面的代码演示了这一点。

您可以看到,在示例a(您的代码)中,method的字符串值是child本身的属性,但您可以通过原型链来获取来自类的函数值。

在示例b中(删除了公共实例字段),该方法存在并且可以被调用,但它不在child本身上(因为它是类的实例,所以可以自动搜索原型链,因为它没有被掩盖)。

const a = () => {
  class Parent {
    method = "sss";
  }
  class Child extends Parent {
    method() {
      console.log("Child");
    }
  }
  var child = new Child();
  console.log("a: " + child.hasOwnProperty('method'));
  Object.getPrototypeOf(child).method();
};

a();

const b = () => {
  class Parent {}
  class Child extends Parent {
    method() {
      console.log("Child");
    }
  }
  var child = new Child();
  console.log("b: " + child.hasOwnProperty('method'));
  child.method();
};

b();
英文:

From MDN

> Public instance fields are added to the instance either at construction time in the base class (before the constructor body runs), or just after super() returns in a subclass.

i.e. it masks the method because it is assigned around the time the constructor runs.

child.method is a property (with a value that is a string) on the object itself. This masks the method on the prototype which is a function.


The code below demonstrates.

You can see that in example a (your code) the string value for method is a property of child itself, but you can dig through the prototype chain to get the function value from the class.

In example b (with the public instance field removed), the method exists and can be called, but isn't on the child itself (because its an instance of the class so it can search the prototype chain automatically because it isn't masked).

<!-- begin snippet: js hide: false console: true babel: false -->

<!-- language: lang-js -->

const a = () =&gt; {
  class Parent {
    method = &quot;sss&quot;
  }
  class Child extends Parent {
    method() {
      console.log(&quot;Child&quot;)
    }
  }
  var child = new Child();
  console.log(&quot;a: &quot; + child.hasOwnProperty(&#39;method&#39;));
  Object.getPrototypeOf(child).method();
};

a();

const b = () =&gt; {
  class Parent {}
  class Child extends Parent {
    method() {
      console.log(&quot;Child&quot;)
    }
  }
  var child = new Child();
  console.log(&quot;b: &quot; + child.hasOwnProperty(&#39;method&#39;));
  child.method();
};

b();

<!-- end snippet -->

huangapple
  • 本文由 发表于 2023年7月24日 19:30:08
  • 转载请务必保留本文链接:https://go.coder-hub.com/76754034.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定