简体   繁体   English

JavaScript 中是否需要 `getter` 和 `setter`?

[英]Are `getter` and `setter` necessary in 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);

Here is my code.这是我的代码。 I created a getter and setter for _name member.我为_name成员创建了一个gettersetter I did not create a getter and setter for age .我没有为age创建gettersetter

But both can update these two fields like this man.name = 'B';man.age = 20;但是两者都可以像这样更新这两个字段man.name = 'B';man.age = 20;

So I am confused, are getter and setter necessary in JavaScript?所以我很困惑,JavaScript 中是否需要gettersetter

Yes, a getter or setter can be very useful at times, but they only need to be used when their specific functionality is required - otherwise plain property access without a getter or setter can be just fine. 是的,getter或setter有时非常有用,但只需要在需要特定功能时使用它们 - 否则没有getter或setter的普通属性访问就可以了。

A getter has use when you want to run some code every time a property is requested. 如果要在每次请求属性时运行某些代码,则可以使用getter。 In your example, the getter always returns an uppercase version of the name regardless of what the case of the name is, while reserving the actual case for internal use. 在您的示例中,无论名称是什么,getter始终返回名称的大写版本,同时保留实际案例以供内部使用。

A setter has use when you want to run some code every time a property is set. 如果要在每次设置属性时运行某些代码,则可以使用setter。 In your case, it prevents the setting of a falsey name. 在您的情况下,它会阻止设置假名称。 You can't implement either of those features without a getter/setter. 没有getter / setter,您无法实现这些功能。

Direct property access is a perfectly fine way to do things when you don't need getter or setter special logic. 当您不需要getter或setter特殊逻辑时,直接属性访问是一种非常好的方法。

It's also possible that getters and setters may get and set some property that is not publicly available (so not available at all via a normal property access), either because it's stored somewhere differently (not as a property on this object) or stored privately or even that it's stored else such as in some hardware device. getter和setter也可能获取并设置一些不公开的属性(因此通过正常的属性访问根本不可用),因为它存储在某个地方(不是作为此对象的属性)或私有存储或即使它存储在其他地方,例如某些硬件设备中。 In these cases, the getter and setter simulate the value being in a property when it actually isn't. 在这些情况下,getter和setter会模拟实际不存在的属性值。 So, they simplify the interface while allowing the actual value to be stored or retrieved from anywhere. 因此,它们简化了界面,同时允许从任何地方存储或检索实际值。

Necessary? 必要? No. 没有。

Are there scenarios that would best be expressed as a getter/setter? 是否有最佳表达为getter / setter的场景? Yes. 是。 Consider "Computed Properties": 考虑“计算属性”:

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

Consider the needs of API designers - most likely they'll be hyper-sensitive about how users perceive their API. 考虑API设计人员的需求 - 他们很可能对用户如何看待他们的API过于敏感。 Every bit (or in this case, parentheses) counts towards cleaning up the interface. 每一位(或在这种情况下,括号)都计入清理界面。

Yes they are very necessary. 是的,他们是非常必要的。 Just not for every property. 只是不是每个财产。

Here are two reasons to have setters: 以下是设置者的两个理由:

1. You need to validate the incoming value. 1.您需要验证传入的值。

Let's say that you have a value that must be an integer between 0 and 100. Your setter can validate that the incoming value is of the correct type and within correct range: 假设您的值必须是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); 

2. You need to do something every time a value changes 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> 

Here are two reasons to have a getter: 以下是吸气剂的两个原因:

1. The value is computed 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. You are proxying a value from another object 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(xa); const y = new MyObj('tacos'); console.log(ya); 

Hiding private variables 隐藏私有变量

getters and setter are a great way to hide private data. getterssetter是隐藏私人数据的好方法。 Yes I know that the ES spec is introducing private variable but here is an example that works until that spec is standard. 是的,我知道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); 

Do you need getter and setters ? 你需要gettersetters吗? No. Are they necessary? 不,他们有必要吗? Yes. 是。

Getter and setter r used to access a PRIVATE PROPERTY or modify it from outside. Getter和setter用于访问PRIVATE PROPERTY或从外部修改它。 GETTER is a function that is used to read a property.if u wanna set the value of private property from outside, we define a SETTER function. GETTER是一个用于读取属性的函数。如果你想从外部设置私有属性的值,我们定义一个SETTER函数。 here is an example: 这是一个例子:

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}

One of the main reason the getter and setter feature was implemented was to close a feature gap that required people to hack a js interpreter/browser to achieve one feature that browsers could do: 实现getter和setter功能的一个主要原因是关闭一个功能差距,需要人们破解js解释器/浏览器以实现浏览器可以执行的一项功能:

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

Now, innerHTML may look like a property but it actually behaves more like a function. 现在, innerHTML可能看起来像一个属性,但它实际上更像是一个函数。 It's actually an HTML compiler. 它实际上是一个HTML编译器。

You can see this by trying to do: 你可以通过尝试做到这一点:

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

This is because the first "call" to innerHTML compiles the html to: 这是因为对innerHTML的第一次“调用”将html编译为:

<table></table>

The second line will fail because <tr> outside of a table is invalid HTML. 第二行将失败,因为表外的<tr>是无效的HTML。

With getter and setter you can finally implement a feature like this in pure javascript - make property access trigger a function call. 使用getter和setter,你最终可以在纯javascript中实现这样的功能 - 使属性访问触发函数调用。

Of course, innerHTML is just one example of getters and setters and a very bad example of an API at that. 当然, innerHTML只是getter和setter的一个例子,也是API的一个非常糟糕的例子。 It's up to your creativity what you can actually do with getters and setters. 这取决于你的创造力,你可以用吸气剂和制定者实际做什么。

Now, for my personal opinion (and it's only my opinion so take it for what it's worth): I think innerHTML provides a good example for why getter and setters should not normally be used. 现在,根据我个人的意见(这只是我的观点,所以把它当作它的价值):我认为innerHTML提供了一个很好的例子,说明为什么通常不应该使用getter和setter。 The confusion over <table> is one good example of breaking user's expectation. <table>的困惑是打破用户期望的一个很好的例子。 If innerHTML was implemented as element.appendHTML() it's behavior would be less surprising. 如果innerHTML被实现为element.appendHTML()那么它的行为就不那么令人惊讶了。 As a programmer I'd be very surprised if a property access does something I don't expect. 作为程序员,如果属性访问做了我不期望的事情,我会感到非常惊讶。

That said, I am glad that getters and setters exist to make language library features self-implementable without needing to resort to hacking in C/C++. 也就是说,我高兴存在getter和setter,使语言库功能可以自行实现,而无需诉诸于C / C ++中的黑客攻击。

Using getter and setter methods depends on your property in class, if you want make an property just to be read-only its true to use getter method as follow: 使用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()); 

The reason why we use the class is that holds all properties of a single a entity.But you can get accomplished just by creating an object and can append properties to that when ever you need. 我们使用该类的原因是保存单个实体的所有属性。但是您可以通过创建对象来完成,并且可以在需要时将属性附加到该对象。

When the code grows bigger you cannot be able to debug where your code fails.If you follow the structure you can be easily able to dubug.Because every entity will be in separate file and logic will be separate. 当代码变大时,您无法调试代码失败的位置。如果您遵循结构,您可以轻松地dubug.Because因为每个实体将在单独的文件中,逻辑将是分开的。

But JavaScript is an object oriented programming language.the reason why we use classes instead of objects, that is the same for getters and setters.It's not like where you can use where you don't need.It's a good practice to set and get all properties via setters and getters. 但是JavaScript是一种面向对象的编程语言。我们之所以使用类而不是对象,这对于getter和setter来说是一样的。它不像你可以在哪里使用你不需要的地方。这是一个很好的做法来设置和获取所有属性通过setter和getters。

After some point of time you may face adding some condition while setting a property, like if a persons age is greater than 100 you should not set in the property.At that point of time you need to change in your base class, and also in your child classes.That will be the hardest part of our life(code refactoring).So avoid these kind of problems and make your variables safe, from my point of view we should use getters and setters.sorry for the long answer 在某个时间点之后,您可能会在设置属性时添加一些条件,例如,如果一个人的年龄大于100,则不应该在该属性中设置。在那个时间点,您需要更改基类,以及你的孩子班。这将是我们生活中最艰难的部分(代码重构)。为了避免这些问题并使你的变量安全,从我的观点来看,我们应该使用getter和setters.sorry来获得长期答案

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

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