简体   繁体   English

使用默认值扩展 js 中的行为

[英]Extends behaviour in js with default value

I have found interesting behaviour of js extends, and do not understand the reasons of it我发现 js extends 的有趣行为,但不明白其中的原因
in case of copy values right from another value, for some reasons value will be copied from parent在从另一个值复制值的情况下,由于某些原因值将从父值复制

class parent {
  defaultValue = 1;
  value = this.defaultValue;
}
new parent() // {defaultValue: 1, value: 1}
class child extends parent {
  defaultValue = 2;
}
new child() // {defaultValue: 2, value: 1}

which is really not obvious and unclear for me这对我来说真的不明显和不清楚
but if i replace it by function or even getter the behaviour will be changed, and i get the value from child但是如果我用函数甚至 getter 替换它,行为就会改变,我从孩子那里得到价值

class parent {
  get defaultValue() { return 1; }
  value = this.defaultValue;
}
new parent() // {defaultValue: 1, value: 1}
class child extends parent {
  get defaultValue() { return 2; }
}
new child() // {defaultValue: 2, value: 2}

the main question here, is why in the moment of child creation in first case JS looking on parent class to take value, but in second case JS looking on child class to take value这里的主要问题是,为什么在第一种情况下创建子类时 JS 寻找父类取值,而在第二种情况下 JS 寻找子类取值

Can someone explain the reason of such behaviour?有人可以解释这种行为的原因吗?

EDIT See t.niese or Yury Tarabanko answers for details编辑有关详细信息,请参阅 t.niese 或 Yury Tarabanko 的答案

the short answer seems in next way简短的回答似乎是下一个方式

getters(also function) and function will be overridden in prototype which allow them to be called by parent with child changes (in real it is expected)吸气剂(也是函数)和函数将在原型中被覆盖,这允许它们被父级调用并进行子级更改(实际上是预期的)

While first example with assignee simple values will be called only in the moment of class creation (constructor or super) and it will be appear only in scope of current class (which cannot be changed by child) and prototype (which can be changed by child)虽然第一个具有受让人简单值的示例只会在类创建时调用(构造函数或超类),并且它只会出现在当前类(不能被孩子更改)和原型(可以被孩子更改)的范围内)

A related question is: how to access overridden parent class functions in parent class code .一个相关的问题是: how to access overridden parent class functions in parent class code

Getters and Setters are functions that are defined with the definition of the class, so in the constructor of the parent class (and the initiation of its instance class fields) you could call a function that only exists in child (which indeed might be a bit strange): Getters 和 Setters 是用类的定义定义的函数,所以在parent类的构造函数中(以及它的实例类字段的初始化)你可以调用一个只存在于child类中的函数(这确实可能有点奇怪的):

 class parent { value = this.test(); constructor() { this.test() } } class child extends parent { test() { console.log('test') } } new child()

So which function (or getter/setter) is called is already defined with the class definition, before the instancing is done.因此,在实例化完成之前,已经用类定义定义了调用哪个函数(或 getter/setter)。

Public instance class fields on the other hand are initialized/set during initialization phase of an instance in an particular order (the shown code might only work in chrome based browsers):另一方面,公共实例类字段在实例的初始化阶段以特定顺序初始化/设置(所示代码可能仅适用于基于 chrome 的浏览器):

 class parent { defaultValue = (() => { console.log('parent:init defaultValue') return 1; })(); value = (() => { console.log('parent:init value') return this.defaultValue; })(); constructor() { console.log('parent constructor') } } class child extends parent { defaultValue = (() => { console.log('child:init defaultValue') return 2; })(); constructor() { console.log('child constructor before super()') super() console.log('child constructor after super()') } } new child()

In your first example, the creation and initialization of the public instance field named defaultValue in Child occurs after the creation and initialization of the public instance field named value in Parent .在您的第一个示例中, Child中名为defaultValue的公共实例字段的创建和初始化发生在Parent中名为value的公共实例字段的创建和初始化之后。

So: even though the this value in the initializer of the public instance field named value in Parent will point to the instance of Child under construction, the child-local public instance field named defaultValue does not yet exist, and so the prototype chain is followed up to the property named defaultValue on the instance of Parent , yielding 1 .所以:即使Parent中名为value的公共实例字段的初始化器中的this值会指向正在构造的Child实例,但是child-local名为defaultValue的公共实例字段还不存在,所以遵循原型链直到Parent实例上名为defaultValue的属性,产生1

In your latter example, you have getter functions named defaultValue .在后一个示例中,您有名为defaultValue的 getter 函数。

Getter functions specified in this way, even though their API deliberately looks like that of public instance fields, will end-up as functions on the [[Prototype]] of any instance under construction.以这种方式指定的 Getter 函数,即使它们的 API 故意看起来像公共实例字段的 API,最终也将作为正在构建的任何实例的[[Prototype]]上的函数。

The [[Prototype]] objects of instances are created at the time of class declaration (ie. always before anything triggered by instance construction), as the .prototype property of the class (or constructor function);实例的[[Prototype]]对象是在类声明时创建的(即总是在实例构造触发的任何事情之前),作为类(或构造函数)的.prototype属性; references to these objects are then copied to the [[Prototype]] of any instance under construction as the first step in object construction (think Object.create(class.prototype)) .然后将对这些对象的引用复制到正在构建的任何实例的[[Prototype]]作为对象构建的第一步(想想Object.create(class.prototype))

And so this.defaultValue from the Parent public instance initializer for value resolves to the getter on the [[Prototype]] of the instance of Child under construction, which is a function that returns 2 .因此,来自Parent公共实例初始化器的this.defaultValue value解析为正在构造的Child实例的[[Prototype]]上的 getter,这是一个返回2的函数。

It is happening because getters are defined on prototypes while instance properties are defined on instance (as the name imply)这是因为 getter 是在原型上定义的,而实例属性是在实例上定义的(顾名思义)

So, when Child1 instance is created it first defines properties from Parent1 and you get defaultValue = 1因此,当创建Child1实例时,它首先定义Parent1的属性,然后得到defaultValue = 1

On contrary when Child2 instance is created the Child2.prototype will already have property defaultValue overriden.相反,当创建Child2实例时, Child2.prototype将已经覆盖属性defaultValue

 class Parent1 { defaultValue = 1; value = this.defaultValue; } class Child1 extends Parent1 { defaultValue = 2; } class Parent2 { get defaultValue() { return 1; } value = this.defaultValue; } class Child2 extends Parent2 { get defaultValue() { return 2; } } console.log(Object.hasOwn(new Child1(), 'defaultValue')) console.log(Object.hasOwn(new Child2(), 'defaultValue'))

类型错误:Class 扩展值 #<object> 不是反应js中的构造函数或null<div id="text_translate"><p> 我试图超越一些主要反应按钮组件的 function,但是在扩展主要反应按钮组件 class 时出现此错误。 这是我的代码:</p><pre> import { Button } from "primereact/button"; class BtnBox extends Button { constructor(props) { super(props); this.renderLabel = this.renderLabel.bind(this); } renderLabel() { return &lt;span&gt;icon&lt;/span&gt;; } } class IconButton extends React.Component { render() { return ( &lt;div className="icon-button"&gt; &lt;BtnBox {...this.props} /&gt; &lt;/div&gt; ); } } export default IconButton;</pre></div></object> - TypeError: Class extends value #<Object> is not a constructor or null in react js

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 JS:类扩展值不是函数或null - JS: Class extends value is not a function or null Javascript自定义滚动js与默认行为相同 - Javascript custom scroll js with same behaviour as default 更改Chrome的JS默认行为 - Change Chrome's JS default behaviour Hammer.js和默认的子div行为 - Hammer.js and default child div behaviour Angular JS-具有默认行为的动态指令 - Angular JS - Dynamic directive with default behaviour JS-具有默认值的参数 - JS - Argument with default value JS:TypeError:Class 扩展值<classname>不是构造函数或 null</classname> - JS: TypeError: Class extends value <ClassName> is not a constructor or null 类型错误:Class 扩展值 #<object> 不是反应js中的构造函数或null<div id="text_translate"><p> 我试图超越一些主要反应按钮组件的 function,但是在扩展主要反应按钮组件 class 时出现此错误。 这是我的代码:</p><pre> import { Button } from "primereact/button"; class BtnBox extends Button { constructor(props) { super(props); this.renderLabel = this.renderLabel.bind(this); } renderLabel() { return &lt;span&gt;icon&lt;/span&gt;; } } class IconButton extends React.Component { render() { return ( &lt;div className="icon-button"&gt; &lt;BtnBox {...this.props} /&gt; &lt;/div&gt; ); } } export default IconButton;</pre></div></object> - TypeError: Class extends value #<Object> is not a constructor or null in react js TypeError: Class extends value 命令不是构造函数或 null - node.js - TypeError: Class extends value Command is not a constructor or null - node.js 类型错误:Class extends value undefined is not a constructor or null in react js - TypeError: Class extends value undefined is not a constructor or null in react js
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM