繁体   English   中英

我们应该在 JavaScript 的类定义中声明构造函数内部还是外部的方法?

[英]Should we declare methods inside or outside the constructor in a class definition in JavaScript?

我很困惑我应该在类定义中声明构造方法内部还是外部的方法?

在类定义的构造函数中声明方法有什么帮助?

在构造函数之外声明方法有什么缺点?

class animal {
    constructor(name, type, color){
        this.name = name;
        this.type = type;
        this.color = color;
        this.sound = () => {console.log(this.name,this.type,this.color)}
    }
    
}

class animal {
    constructor(name, type, color){
        this.name = name;
        this.type = type;
        this.color = color;
    }
    sound = () => {console.log(this.name,this.type,this.color)}
}

以任何一种方式创建对象都会产生相似的对象。 我错过了什么?

构造函数内部的函数定义主要用于在调用中存储和访问私有变量,如下所示:

function MyClass() {
  let privateVar = { something: "usefull" };
  this.getPrivateVar = function getPrivateVar() { return privateVar; };
}
new MyClass().getPrivateVar(); // { something: "usefull" }

仅仅因为调用产生相似的结果,并不意味着它们具有相同的行为。 根据调用方式或定义方式,它们的行为可能完全不同。

这尤其适用于箭头函数,因为它们没有 this 绑定。 当定义时,它们访问最接近的这个提供环境。

class MyClass {}
MyClass.prototype.arrow = () => this;
console.log(new MyClass().arrow() == globalThis); // true

JavaScript .prototype 如何工作的答案? 很好地解释原型是如何工作的,对于类,其中定义的每个属性和函数都将存储在constructor.prototype上,但有一些例外,例如静态和 #private 属性。

  • 私有属性仅在类内部可用和可访问,而不是在继承或扩展类中,并且不能被经典原型访问。
     class MyClass { #private = "example"; doSomethingWithMyPrivate() { return this.#private } } MyClass.prototype.getThePrivate = function() { return this.#private }; new MyClass().doSomethingWithMyPrivate(); // example // Both produce the same SyntaxError: // Private field '#private' must be declared in an enclosing class new MyClass().#private; new MyClass().getThePrivate();
  • 静态属性将直接放在构造函数上。
     class MyClass { static doSomething() { console.log("Okay!") } } MyClass.doSomething(); // Okay! new MyClass().doSomething(); // TypeError: doSomething is not a function

类的每个实例都将访问原型引用或继承对象原型,直到任何对象与属性名称匹配,如果不匹配,则返回未定义或根据情况抛出更具体的错误。

这个答案

Javascript 在查找对象的属性时有一种称为“原型继承”的机制,基本上是这样的:

  • 首先检查属性是否位于对象本身上。 如果是这样,则返回此属性。
  • 如果该属性不在对象本身上,它将“爬上原型链”。 它基本上着眼于由 proto 属性引用的对象。 它在那里检查该属性是否在 proto 引用的对象上可用
  • 如果属性不在 proto 对象上,它将沿着 proto 链一直向上爬到 Object 对象。
  • 如果它在对象及其原型链上找不到属性,它将返回未定义。

因此,如果您在构造函数中定义函数,每个实例都会分配一个新函数(它们不会有相同的引用)。 这意味着,根据类(new animal).sound == (new animal).sound ,该语句将返回true (您的第二个示例)或false (您的第一个示例),并且原型继承将发生或不发生。

 // the old way function Foo() { if (this instanceof Foo) { this.fx = () => {}; } else throw new TypeError(`Constructor Foo cannot be invoked without 'new'`); } Foo.prototype.pfx = function() {}; console.log((new Foo).fx, (new Foo).fx == (new Foo).fx); // arrow ƒ, false console.log((new Foo).pfx, (new Foo).pfx == (new Foo).pfx); // ƒ, true // the class way class Bar { constructor() { // similar too "ƒ Foo() {}" with the addition of super ƒ this.fx = () => {}; } // this is almost like Bar.prototype.pfx = ... pfx() {} } // works like before Bar.prototype.moo = function moo() {}; console.log((new Bar).fx, (new Bar).fx == (new Bar).fx); // arrow ƒ, false console.log((new Bar).pfx, (new Bar).pfx == (new Bar).pfx); // ƒ, true console.log((new Bar).moo, (new Bar).moo == (new Bar).moo); // ƒ, true

如果您在示例 #1 中定义属性,则可以“覆盖”其他方法,这可能会导致上面提到的私有属性出现问题。

 class Foo { constructor() { // just for the example this.fx = Foo.prototype.fx; } fx() { console.log("I am broken"); }; } class Bar extends Foo { fx() { console.log("I fix something"); } } class Moo extends Bar { constructor() { super(); delete this.fx; } } /* * If instance has no own property called fx the default * behavior will take place: * Test the construtor.prototype if it has one and execute this. * If not, look at the inheriting classes in descending order * (Moo > Bar > Foo > Object) * But bar.fx() => has an own property called fx which takes place */ let bar = new Bar(); bar.fx(); // I am broken // none of the inheriting classes has a toJSON ƒ, // so Object.prototype.toJSON will be called. console.log(bar.toJSON == Object.prototype.toJSON) // true // the Moo constructor deletes the own property after the Foo constructor was evaluated, so Bar.prototype.fx takes place new Moo().fx() // I fix something

暂无
暂无

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM