Javascript setter 结果无效

Javascript setter resulting to no effect

我正在做一个项目,而我的 setter 只是拒绝工作。我尝试了多种解决方案,例如将其设为私有(但这不起作用,因为我需要访问它),将 setters 下的值重命名为不同的值,并尝试使用或不使用括号来调用它们。

class Car {
        constructor(id, image, vPosition, wins, hPosition, finishedRace) { //there is a chance I may need to remove the last 3 parms (wins,hpos and finished race)
            this.id = id;
            this.image = image;
            this.vPosition = vPosition;
            this.hPosition = hPosition;
            this.finishedRace = finishedRace;
            this.wins = wins;
        }
        get getvPosition() {
            return this.vPosition;
        }
        /**
         * @param {any} vPos
         */
        set setvPosition(vPos)  {
            this.vPosition1 = vPos;
        }
        
        get getHPosition() 
        {
            return this.hPosition;
        }

        set setHPosition(hPos) 
        {
            this.hPosition = hPos;
        } 
        move(Car)   {
        Car.setHPosition(10);
    }

这是我的车 class,我正在其中创建构造函数和 getter setter。与其他方法

const cars = [
        new Car("Classic", "images/car1.png", 150,0,0,0),
        new Car("Bug", "images/car2.png", 350,0,0,0),
        new Car("Hatchback", "images/car3.png", 550,0,0,0),
        new Car("Sedan", "images/car4.png", 750,0,0,0)
    ];

上面的对象 Car 的数组,它就在 Car 的外面 class。

看看 Car class 中的移动方法。我稍后在代码中使用它是这样的:

cars[2].move;
let str = cars[2].getHPosition;
console.log(str);

应该在 cars[2] 上调用 setter 并将其 HPosition 设置为 10 相反,它 returns 0 就好像从未调用过 setter 一样。我知道这里一定有一些愚蠢的错误,但我很生气

我想在这种情况下,我会完全删除对 getters/setters 的依赖,而只使用您通常调用的简单 class 方法。这样 move 就可以毫无问题地调用 setHPosition

class Car {

  constructor(id, image, vPosition, wins, hPosition, finishedRace) {
    this.id = id;
    this.image = image;
    this.vPosition = vPosition;
    this.hPosition = hPosition;
    this.finishedRace = finishedRace;
    this.wins = wins;
  }

  getvPosition() {
    return this.vPosition;
  }

  setvPosition(vPos) {
    this.vPosition1 = vPos;
  }

  getHPosition() {
    return this.hPosition;
  }

  setHPosition(hPos) {
    this.hPosition = hPos;
  }

  move(val) {
    this.setHPosition(val);
  }

}

const cars = [
  new Car("Classic", "images/car1.png", 150, 0, 0, 0),
  new Car("Bug", "images/car2.png", 350, 0, 0, 0),
  new Car("Hatchback", "images/car3.png", 550, 0, 0, 0),
  new Car("Sedan", "images/car4.png", 750, 0, 0, 0)
];

cars[2].move(10);
console.log(cars[2].getHPosition());

您的移动函数采用 Car 参数并移动 that 汽车而不是当前 class 实例 this。因此,您应该更改 move 函数以获取距离值,然后调用 this.setHPosition = this.getHPosition + distance,假设您希望将汽车从其当前位置移动一个位移,而不是移动到一个固定位置。即:

move(distance) {
    this.setHPosition = this.getHPosition + distance; // or just use this.hPosition directly: this.hPosition += distance
}

请注意,getters 和 setters 是像属性一样访问的函数,因此您不使用括号,而只需将 属性 分配给 setter,或阅读 属性 以获得 getter。它是语法糖,但如果你使用它,你必须正确使用它!最好不要在 setters/getters 前面加上 'get' 和 'set' 前缀,因为这会使它们看起来像函数并且可能会造成混淆。

你的错误

您的代码可能出现意外行为的多种原因:

  • 您引用,但未调用 car[2].move。像 car[2].move()!
  • 这样命名
  • move 中,您正在尝试调用实例方法,就好像它是静态方法一样!参考 this 而不是 Car.
  • 您正在尝试调用 JS setter!不要调用它 (setHPosition(20)),而是给 属性 (setHPosition = val) 赋值。
  • setvPosition 中,您将值分配给 属性 vPosition1(注意 1)。

错误可能来自对某些 JS 主题的误解。

JS 中的函数

JS是一种函数式编程语言,这意味着函数被视为so-called first-class citizens。因此,引用函数(此处:move)但不调用它是完全有效的。

在你的例子中,你实际上想要调用函数,这是通过在函数的括号中附加一个参数列表来完成的:move()(这里没有传递任何参数)。

测试您的函数是否已被调用的一种简单方法是在其中散布一些 console.logs,例如Chrome 还提供了一些调试工具(我个人从未使用过)。

构造函数

构造函数在调用它们时更多是例外。您可以通过在函数名称前加上关键字 new 来调用构造函数,然后可以像调用常规函数一样调用它:new SomeConstructor(1, 2, 3).

(大多数命名约定都将构造函数大写。)

或者,与常规函数不同,也可以通过省略参数列表来调用构造函数:new SomeConstructor。这等同于调用不带任何参数的构造函数:new SomeConstructor().

您的 move 函数未作为构造函数调用,因此它必须具有要调用的参数列表:move().

函数上下文

在对象上调用函数将使该对象成为函数的上下文。否则,使用周围的上下文。在顶层(全局范围),globalThisnull 是上下文,具体取决于您处于“草率”模式还是严格模式:

console.log("Global scope:");
(function sloppyMode() {
  console.log("-sloppy: this === globalThis?", this === globalThis);
})();
(function strictMode() {
  "use strict";
  console.log("-strict: this === undefined?", this === undefined);
})();
console.log(""); // Ignore; for whitespace in console

const compareThis = function(compTo) { return this === compTo; };
const obj = { compareThis };

console.log("Function scope:");
console.log("-direct call: this === globalThis?", compareThis(globalThis));
console.log("-direct call: this === obj?", compareThis(obj));
console.log("-on obj: this === globalThis?", obj.compareThis(globalThis));
console.log("-on obj: this === obj?", obj.compareThis(obj));
.as-console-wrapper{top:0;max-height:unset!important}

因此,我们不需要期望将 Car 对象传递给 move,而是可以使用 this.

此外,参数 Car 会隐藏 class Car,因为它在词法 scope-chain.

中较早找到

如果您希望在函数中保留两者的可访问性,一个好主意是将参数命名为(小写)car。一般来说,最好坚持一种命名约定,以免混淆自己。

实例与静态方法

一个class在JS中同时定义了实例方法和静态方法,但是静态方法只会在上定义 class,而实例方法只会 个实例上。

例子

考虑以下几点:

class Example {
  static staticMethod() {}
  instanceMethod() {}
}

staticMethod 仅在 class 对象 Example 上定义,但未在实例 new Example():

上定义
Example.staticMethod(); // works
new Example().staticMethod(); // fails; staticMethod is undefined on instances

对于 instanceMethod 则相反:它只在实例 new Example() 上定义,而不是在 class 对象上定义 Example:

Example.instanceMethod(); // fails; instanceMethod is undefined on the class object
new Example().instanceMethod(); // works

Getters/setters

JS 具有 get/set 关键字,使指定的 属性 仅在特定情况下起作用:

  • get 属性 类似名称的 属性 被访问(读取)时调用函数。
  • set 属性 类似名称的 属性 赋值时调用函数。

在这两种情况下,它们都像常规属性一样使用,而不是方法:

const object = {
  _name: "my name",
  get name() {
    console.log("object:", "get name");
    return this._name;
  },
  set name(v) {
    console.log("object:", "set name");
    this._name = v;
  }
};
console.log("log:", object.name); // Uses getter
object.name = "another name"; // Uses setter
console.log("log:", object.name); // Uses getter

// Complex example:
// JS assigns right-to-left, so the expression evaluates to using the string,
// not to getting the property. Because of this, it only...
console.log("log:", object.name = "third name"); // Uses setter
// See https://262.ecma-international.org/12.0/#sec-assignment-operators-runtime-semantics-evaluation

一个对象可以有一个 getter 和 setter 用于相同的 属性(如上所示,用于 name)。但是当定义了 getter 或 setter 时,不能在同一个对象上定义同名的数据条目(这就是为什么我改为使用 _name)。

如您所见,这些不是 get/set 方法。 Getters/setters 通常仅在 access/assignment 期间必须执行其他功能(例如缓存、惰性初始化)或具有不可变的 属性 引用或 ...

时才使用

结论

我看不出有理由在您的 class 中使用 getters/setters。此外,none 的属性是私有的(在 classes 中可用;示例:this.#aPrivateProperty),这就是为什么我什至不使用 get/set 方法,而是访问直接属性。

此外,我个人喜欢做的是在 class 定义中也定义属性,而不仅仅是在构造函数中。然后你的 IDE 应该自动完成属性,可能会减少像你的 vPosition1.

这样的拼写错误

下面是我将如何编写您的代码的简化示例:

class Car {
  hPosition;
  vPosition;
  
  constructor(hPos, vPos) {
    this.hPosition = hPos;
    this.vPosition = vPos;
  }
  
  move() { // We don't expect `Car`; we can use `this` instead!
    this.hPosition = 10; // Shouldn't this be "+=" ?
  }
}

const cars = [
  new Car(150, 0),
  new Car(350, 0),
  new Car(550, 0),
  new Car(750, 0)
];

cars[2].move(); // Don't forget to call!
console.log(cars[2].hPosition);

如果您仍然想使用原始代码的 getters/setters:

[=89=
class Car {
  constructor(vPosition, hPosition) {
      this.vPosition = vPosition;
      this.hPosition = hPosition;
  }

  get getVPosition() { return this.vPosition; }
  set setVPosition(vPos) { this.vPosition = vPos; } // Fixed typo vPosition1

  get getHPosition() { return this.hPosition; }
  set setHPosition(hPos) { this.hPosition = hPos; }

  /* This *instance method* doesn't use *this instance* at all, so why is it not a static method?
   * Also, instead of using *this instance*, it uses a passed-in instance. Why?
   */
  move(car) {
    car.setHPosition = 10;
  }
}

const cars = [
  new Car(150, 0),
  new Car(350, 0),
  new Car(550, 0),
  new Car(750, 0)
];

cars[2].move(cars[2]); // We need to call the instance method, and then pass it the object to mutate.

let str = cars[2].getHPosition; // str now holds a number, but name suggests it holds a string.
str = String(str); // *Now* it holds a string.
console.log(str);