JavaScript中需要`getter`和`setter`吗?

Bla*_*mba 13 javascript

class Employee {

    constructor(name, age) {
        this._name = name;
        this.age = age;
    }

    doWork() {
        return `${this._name} is working`;
    }

    get name() {
        return this._name.toUpperCase();
    }

    set name(newName){
        if(newName){ 
            this._name = newName;
        }
    }
}

let man = new Employee('A', 10);
console.log(man.name, man.age);
man.name = 'B';
man.age = 20;
console.log(man.name, man.age);
Run Code Online (Sandbox Code Playgroud)

这是我的代码.我创建了一个gettersetter_name成员.我没有创建一个gettersetterfor age.

但两者都可以像这样更新这两个字段 man.name = 'B';man.age = 20;

所以,我很困惑,是gettersetter必要在JavaScript?

jfr*_*d00 26

是的,getter或setter有时非常有用,但只需要在需要特定功能时使用它们 - 否则没有getter或setter的普通属性访问就可以了.

如果要在每次请求属性时运行某些代码,则可以使用getter.在您的示例中,无论名称是什么,getter始终返回名称的大写版本,同时保留实际案例以供内部使用.

如果要在每次设置属性时运行某些代码,则可以使用setter.在您的情况下,它会阻止设置假名称.没有getter/setter,您无法实现这些功能.

当您不需要getter或setter特殊逻辑时,直接属性访问是一种非常好的方法.

getter和setter也可能获取并设置一些不公开的属性(因此通过正常的属性访问根本不可用),因为它存储在某个地方(不是作为此对象的属性)或私有存储或即使它存储在其他地方,例如某些硬件设备中.在这些情况下,getter和setter会模拟实际不存在的属性值.因此,它们简化了界面,同时允许从任何地方存储或检索实际值.


jon*_*sam 6

必要的?不。

是否有最适合表示为 getter/setter 的场景?是的。考虑“计算属性”:

//declare an object
rectangle = {
   x: 10,
   y: 20,
   get area() { return this.x * this.y }  //won't occupy storage
}

//usage
log('the area is', rectangle.area)        //=> 'the area is 200'.
                                          //   cleaner syntax (no parentheses)
Run Code Online (Sandbox Code Playgroud)

考虑 API 设计者的需求——他们很可能对用户如何看待他们的 API 非常敏感。每一位(或在这种情况下,括号)都计入清理接口。

  • 在您的示例中,除了需要调用括号之外,此方法是否与 getter 相同?`area: () => { return this.x * this.y }` (2认同)

Int*_*lia 5

是的,它们是非常必要的。只是不是每个属性。

这里有两个使用 setter 的原因:

1. 您需要验证传入的值。

假设您有一个值必须是 0 到 100 之间的整数。您的 setter 可以验证传入值的类型是否正确并且在正确的范围内:

class Range {
  set value(newVal) {
    let val = Number(newVal);
    
    if( newVal == null || typeof newVal === 'string' || !Number.isInteger(val) || val < 0 || val > 100 ) {
      const err = `'value' must be an integer from 0 to 100 and not ${newVal}`;
      console.error(err);
      //throw new TypeError(err);
    }
    
    // save newVal
  }
}

const x = new Range();
x.value = 200;
x.value = 10;
x.value = "10";
x.value = new Number(22);
Run Code Online (Sandbox Code Playgroud)

2. 每次值改变时你都需要做一些事情

class ValOutput {
  constructor(el) {
    this._el = el;
  }

  set value(newVal) {
    this._el.innerHTML = `The value is ${newVal}`;
  }
}

const output = document.getElementById('output');
const x = new ValOutput(output);
x.value = 100;
setTimeout(() => {
  x.value="after timeout";
}, 2000);
Run Code Online (Sandbox Code Playgroud)
<div id="output"></div>
Run Code Online (Sandbox Code Playgroud)

这里有两个使用 getter 的原因:

1. 计算值

class Rect {
  constructor(l = 0,t = 0,r = 0,b = 0) {
    this.left = l;
    this.top = t;
    this.right = r;
    this.bottom = b;
  }
  
  get height() {
    return this.bottom - this.top;
  }

  get width() {
    return this.right - this.left;
  }
}

let a = new Rect(0, 10, 33, 55);
console.log(a.width, a.height);

 a = new Rect(35, 50, 200, 200);
console.log(a.width, a.height);
Run Code Online (Sandbox Code Playgroud)

2. 你从另一个对象代理一个值

class OtherThing {
  constructor(a) {
    this.a = a;
  }
}

class MyObj {
  constructor(oVal = 0) {
    this._otherThing = new OtherThing(oVal);
  }
  
  get a() {
    return this._otherThing.a;
  }
}

const x = new MyObj();
console.log(x.a);

const y = new MyObj('tacos');
console.log(y.a);
Run Code Online (Sandbox Code Playgroud)

隐藏私有变量

getters并且setter是隐藏私人数据的好方法。是的,我知道 ES 规范正在引入私有变量,但这里有一个示例,该示例在该规范成为标准之前一直有效。

const privateVars = new WeakMap();

class MyObj {
  constructor(inVal) {
    const pVars = {
      age: inVal,
      dog: ''
    }
    
    privateVars.set(this, pVars);
  }
  
  get dog() {
    return privateVars.get(this).dog;
  }
  set dog(newVal) {
    privateVars.get(this).dog = newVal;
  }
}

const x = new MyObj(10);
const y = new MyObj(20);


x.dog = "woof";
y.dog = "bark";

console.log(x.dog);
console.log(y.dog);
Run Code Online (Sandbox Code Playgroud)

你需要gettersetters吗?没有。它们有必要吗?是的。