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

时间:2016-01-15 05:51:44

标签: 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);

这是我的代码。我为getter成员创建了setter_name。我没有为getter创建setterage

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

所以我很困惑,JavaScript中需要gettersetter吗?

7 个答案:

答案 0 :(得分:20)

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

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

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

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

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

答案 1 :(得分:4)

必要吗?否。

是否有最佳表现为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)

考虑API设计人员的需求 - 他们很可能对用户如何看待他们的API过于敏感。每一点(或在这种情况下,括号)都会计入清理界面的程度。

答案 2 :(得分:0)

字母和字母r用于访问私有财产或从外部进行修改。 GETTER是用于读取属性的函数。如果要从外部设置私有属性的值,则定义一个SETTER函数。这是一个例子:

function Circle(radius){
this.radius=radius;
let originPoint={x:0,y:0};  //originPoint is a private property.
this.area=function(){console.log("area")};

Object.defineProperty(this,originPoint,{
    get:function(){
return originPoint;
};
set:function(value){
originPoint=value;}
}
}
const circle=new Circle(10);
circle.originPoint  //will call "get" function
circle.originPoint={x:2,y:3}

答案 3 :(得分:0)

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

这是有二传手的两个原因:

1。您需要验证输入值。

假设您的值必须为0到100之间的整数。设置程序可以验证输入值的类型正确且在正确范围内:

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);

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);
<div id="output"></div>

这是有吸气剂的两个原因:

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);

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);

隐藏私有变量

getterssetter是隐藏私人数据的好方法。是的,我知道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);

您需要gettersetters吗?不,有必要吗?是的。

答案 4 :(得分:0)

实施getter和setter功能的主要原因之一是缩小功能差距,这需要人们破解js解释器/浏览器才能实现浏览器可以实现的一项功能:

element.innerHTML = "<div> some HTML string </dif>";

现在,innerHTML可能 看起来 像一个属性,但实际上它的行为更像一个函数。它实际上是HTML编译器。

您可以尝试这样做:

element.innerHTML += "<table>";
element.innerHTML += "<tr><td>test</td></tr>"; // does not work

这是因为对innerHTML的第一个“调用”将html编译为:

<table></table>

第二行将失败,因为表外的<tr>是无效的HTML。

使用getter和setter,您最终可以在纯JavaScript中实现这样的功能-使属性访问触发函数调用。

当然,innerHTML只是getter和setter的一个示例,并且是API的非常糟糕的示例。实际使用吸气剂和吸气剂的能力取决于您的创造力。

现在,就我个人的观点(这只是我的观点,因此请考虑是否有价值):我认为innerHTML提供了一个很好的示例,说明了通常不应该使用getter和setter的原因。对<table>的困惑是打破用户期望的一个很好的例子。如果将innerHTML实现为element.appendHTML(),它的行为就不会那么令人惊讶了。作为一名程序员,如果属性访问实现了我意料之外的事情,我会感到非常惊讶。

也就是说,我,我很高兴使用getter和setter来使语言库功能可自我实现,而无需借助C / C ++进行黑客攻击。

答案 5 :(得分:-1)

使用gettersetter方法取决于您在课堂上的属性,如果您想将属性设置为只读,则使用getter方法如下:

function Person(name, age){
  var _name = name;
  this.age = age;
  
  this.getName = function(){
    return _name;
  }
}

var teacher = new Person('Sara', 24);

//now you can just get the name of teacher 
alert(teacher.getName());
  

答案 6 :(得分:-2)

我们使用该类的原因是保存单个实体的所有属性。但是您可以通过创建对象来完成,并且可以在需要时附加属性。

当代码变大时,您无法调试代码失败的位置。如果您遵循该结构,您可以轻松地dubug.Because因为每个实体将在单独的文件中,逻辑将是独立的。

但JavaScript是一种面向对象的编程语言。我们使用类而不是对象的原因,对于getter和setter来说是相同的。它不像你可以在哪里使用你不需要的地方。这是一个很好的做法通过setter和getter设置并获取所有属性。

在某个时间点之后,您可能会在设置属性时添加一些条件,例如,如果一个人的年龄大于100,则不应该在该属性中设置。在那个时间点,您需要更改基类,这也是你孩子的课程。这将是我们生活中最难的部分(代码重构)。为了避免这些问题并使你的变量安全,从我的角度来看,我们应该使用getter和setters.sorry来获得长期答案