傻瓜的吸气剂\二传手

IT技术 javascript setter getter
2021-01-26 22:51:12

我一直在尝试解决 getter 和 setter 问题,但并没有深入了解。我已经阅读了JavaScript Getter 和 Setter以及Defining Getter 和 Setter,但没有得到它。

有人可以明确说明:

  1. getter 和 setter 的作用是什么,以及
  2. 举一些非常简单的例子?
6个回答

除了@millimoose 的回答之外,setter 也可用于更新其他值。

function Name(first, last) {
    this.first = first;
    this.last = last;
}

Name.prototype = {
    get fullName() {
        return this.first + " " + this.last;
    },

    set fullName(name) {
        var names = name.split(" ");
        this.first = names[0];
        this.last = names[1];
    }
};

现在,您可以设置fullName,并firstlast将被更新,反之亦然,副。

n = new Name('Claude', 'Monet')
n.first # "Claude"
n.last # "Monet"
n.fullName # "Claude Monet"
n.fullName = "Gustav Klimt"
n.first # "Gustav"
n.last # "Klimt"
@Martin:您可以使用与John's answer相同的技术将它们设为私有如果您想使用真正的 getter/setter,则必须使用this.__defineGetter__或 较新的Object.defineProperty函数。
2021-03-26 22:51:12
上面列出的方法只有一个问题,如果您想为已经存在的类添加 getter 和 setter,它将覆盖原型,并且原始方法将无法访问。
2021-03-30 22:51:12
MS 不正确支持 JS 并且他们没有让他们的 Silverlight 到处运行,这真的很痛苦,所以我必须对所有内容进行两次编程,一次用于 SL,另一次用于世界其他地方:)
2021-04-01 22:51:12
这种方法不会覆盖Name.prototype.constructor吗?似乎是Milloose's Answer的糟糕替代品
2021-04-06 22:51:12
@Akash:不,尽管如此,Internet Explorer 9 确实支持Object.defineProperty可以定义 getter 和 setter的较新函数。
2021-04-07 22:51:12

JavaScript 中的 Getter 和 Setter

概述

JavaScript 中的 getter 和 setter 用于定义计算属性访问器计算属性是使用函数来获取或设置对象值的属性。基本理论是做这样的事情:

var user = { /* ... object with getters and setters ... */ };
user.phone = '+1 (123) 456-7890'; // updates a database
console.log( user.areaCode ); // displays '123'
console.log( user.area ); // displays 'Anytown, USA'

这对于在访问属性时自动执行幕后操作非常有用,例如将数字保持在范围内、重新格式化字符串、触发 value-has-changed 事件、更新关系数据、提供对私有属性的访问等等。

下面的示例显示了基本语法,尽管它们只是简单地获取和设置内部对象值,而没有做任何特殊的事情。在实际情况下,您可以修改输入和/或输出值以满足您的需要,如上所述。

获取/设置关键字

ECMAScript 5 支持getset关键字来定义计算属性。它们适用于除 IE 8 及更低版本之外的所有现代浏览器。

var foo = {
    bar : 123,
    get bar(){ return bar; },
    set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;

自定义 Getter 和 Setter

get并且set不是保留字,因此可以重载它们以创建您自己的自定义跨浏览器计算属性函数。这将适用于任何浏览器。

var foo = {
    _bar : 123,
    get : function( name ){ return this[ '_' + name ]; },
    set : function( name, value ){ this[ '_' + name ] = value; }
};
foo.set( 'bar', 456 );
var gaz = foo.get( 'bar' );

或者对于更紧凑的方法,可以使用单个函数。

var foo = {
    _bar : 123,
    value : function( name /*, value */ ){
        if( arguments.length < 2 ){ return this[ '_' + name ]; }
        this[ '_' + name ] = value;
    }
};
foo.value( 'bar', 456 );
var gaz = foo.value( 'bar' );

避免做这样的事情,这会导致代码膨胀。

var foo = {
    _a : 123, _b : 456, _c : 789,
    getA : function(){ return this._a; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

对于上面的例子,内部属性名称用下划线抽象,以阻止用户简单地做foo.barvs.foo.get( 'bar' )并获得“未煮过的”值。您可以根据正在访问的属性的名称(通过name参数)使用条件代码执行不同的操作

Object.defineProperty()

UsingObject.defineProperty()是另一种添加 getter 和 setter 的方法,可以在对象定义后使用。它还可以用于设置可配置和可枚举的行为。此语法也适用于 IE 8,但不幸的是仅适用于 DOM 对象。

var foo = { _bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return this._bar; },
    set : function( value ){ this._bar = value; }
} );
foo.bar = 456;
var gaz = foo.bar;

__defineGetter__()

最后,__defineGetter__()是另一种选择。它已被弃用,但仍在网络上广泛使用,因此不太可能很快消失。它适用于除 IE 10 及更低版本之外的所有浏览器。尽管其他选项在非 IE 上也能很好地工作,但这个选项并不是那么有用。

var foo = { _bar : 123; }
foo.__defineGetter__( 'bar', function(){ return this._bar; } );
foo.__defineSetter__( 'bar', function( value ){ this._bar = value; } );

另外值得注意的是,在后者的例子中,内部名称必须比存取名,以避免递归(即不同的foo.bar呼叫foo.get(bar)呼叫foo.bar呼叫foo.get(bar)...)。

也可以看看

MDN get , set , Object.defineProperty() , __defineGetter__() , __defineSetter__()
MSDN IE8 Getter 支持

设置/获取名称必须与属性名称不同。因此,而不是bar: 123this.bar = value等改变这些来_bar 的例子。参见:hongkiat.com/blog/getters-setters-javascript
2021-03-14 22:51:12
更紧凑的方法中this[ '_' + name ] = value;可以this[ '_' + name ] = arguments[1];并且不需要指定valuearg。
2021-03-21 22:51:12
示例: var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456; 引发异常:Uncaught RangeError: Maximum call stack size exceeded at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) ) 在 Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous>:4:32) at Object.set bar [as bar] (<anonymous> :4:32) 在 Object.set bar [as bar] (<匿名>:4:32)
2021-03-28 22:51:12
@nevf 感谢您的更正!是的,通常对于计算属性,“真正的”内部属性​​被命名为_foomFoo如果它与 getter/setter 相同,它将因递归而导致无限循环,然后是 Stack Overflow™ ;-) 因为当你说 a = b 时,它调用 a.get(b) 而它本身调用 a = b , 调用 a.get(b), ...
2021-03-31 22:51:12

例如,您可以使用它们来实现计算属性。

例如:

function Circle(radius) {
    this.radius = radius;
}

Object.defineProperty(Circle.prototype, 'circumference', {
    get: function() { return 2*Math.PI*this.radius; }
});

Object.defineProperty(Circle.prototype, 'area', {
    get: function() { return Math.PI*this.radius*this.radius; }
});

c = new Circle(10);
console.log(c.area); // Should output 314.159
console.log(c.circumference); // Should output 62.832

(代码笔)

@developer 这不是语言定义的 Javascript getter,它只是一个函数。您必须调用它来获取值,它不会重载对属性的访问。还有一个特殊的地狱圈是为那些在 JS 中发明自己的损坏对象系统而不是建立在已有的对象系统上的人保留的。
2021-03-14 22:51:12
好的,我想我开始明白了。我正在尝试为数组对象的长度属性分配一个 getter,但出现错误:“重新声明 var 长度”代码如下所示:obj = []; obj.__defineGetter__('length',function(){ return this.length; });
2021-03-21 22:51:12
那是因为 Array 对象已经有一个内置的 length 属性。如果允许重新声明,则调用新长度将无限递归。尝试调用属性“my_length”或诸如此类。
2021-03-24 22:51:12
你不能只制作 { "area": function () {return ...} } 吗?只需将其分配为对象属性
2021-04-02 22:51:12
为了在一个语句中定义两个 getter,请使用Object.defineProperties.
2021-04-08 22:51:12

很抱歉重新提出一个老问题,但我想我可能会贡献一些非常基本的例子和傻瓜解释。迄今为止发布的其他答案都没有像MDN 指南的第一个示例那样说明语法,这与人们所能获得的基本一样。

吸气剂:

var settings = {
    firstname: 'John',
    lastname: 'Smith',
    get fullname() { return this.firstname + ' ' + this.lastname; }
};

console.log(settings.fullname);

...John Smith当然会记录吸气表现得像可变对象的属性,但提供的功能,实时计算其返回值的灵活性。它基本上是一种创建调用时不需要 () 的函数的奇特方式。

二传手:

var address = {
    set raw(what) {
        var loc = what.split(/\s*;\s*/),
        area = loc[1].split(/,?\s+(\w{2})\s+(?=\d{5})/);

        this.street = loc[0];
        this.city = area[0];
        this.state = area[1];
        this.zip = area[2];
    }
};

address.raw = '123 Lexington Ave; New York NY  10001';
console.log(address.city);

...将登录New York到控制台。与 getter 一样,setter的调用语法与设置对象属性的值相同,但它是另一种不使用 () 调用函数的奇特方式。

请参阅此 jsfiddle以获得更全面、更实用的示例。将值传递到对象的setter会触发其他对象项的创建或填充。具体来说,在jsfiddle的例子中,传递一个数字数组会提示setter计算均值、中位数、众数和范围;然后为每个结果设置对象属性。

@Andreas 谁说我不能?就像我说的,这只是一种帮助我保持思想井井有条的方式。编码是一门艺术。你不会问鲍勃·罗斯,为什么他可以使用橙色,但他必须使用烧焦的赭石。你现在可能看不到需要,但有一天当你决定你的画需要一点烧焦的赭石时,它就会出现在你的调色板上。
2021-03-15 22:51:12
:) 我看到 get 和 set 语法所做的一件事是,如果将其用作属性的属性,则它会自动运行。
2021-03-22 22:51:12
我仍然不明白使用 get 和 set 与创建 getMethod 或 setMethod 的好处。是没有 () 可以调用它的唯一好处吗?一定有另一个原因将它添加到 javascript 中。
2021-03-25 22:51:12
所以它只是语法糖,让代码在没有 () 的情况下看起来更干净。我不明白为什么你不能用你的例子maps.roll()
2021-03-31 22:51:12
@Andreas Getters 和 setters 在调用时表现得像属性,这有助于阐明它们的预期目的。它们不会解锁原本缺失的能力,但它们的使用可以帮助您整理您的想法。这才是真正的好处。作为一个实际示例,我曾经使用 getter 来扩展 Google Maps 对象。我需要计算相机滚动角度,以便我可以将地图图块平地旋转到地平线。Google 现在会在后端自动执行此操作;但当时maps.roll作为属性而不是maps.roll()返回值来检索对我很有帮助这只是一种偏好。
2021-04-04 22:51:12

只有当您拥有类的私有属性时,getter 和 setter 才真正有意义。由于 Javascript 并不像您通常从面向对象语言中想到的那样真正具有私有类属性,因此可能难以理解。这是私有计数器对象的一个​​示例。这个对象的好处是不能从对象外部访问内部变量“count”。

var counter = function() {
    var count = 0;

    this.inc = function() {
        count++;
    };

    this.getCount = function() {
        return count;
    };
};

var i = new Counter();
i.inc();
i.inc();
// writes "2" to the document
document.write( i.getCount());

如果您仍然感到困惑,请查看 Crockford 关于Private Members in Javascript的文章

我不同意。getter 和 setter 对于封装信息也非常有用,这些信息的定义可能不仅仅是一个简单的变量。如果您需要更改以前使用简单属性以及其他可能依赖的系统的行为,它会很方便。此外,您的示例仅演示了只是函数的“伪 getter”。真正的 JavaScript getter显示为简单的值(并且可以在没有函数符号的情况下访问),因此它们具有真正的威力。
2021-03-13 22:51:12
不确定我是否会称之为强大。一些看起来像 X 但实际上是 Y 的东西不一定清楚。我绝对不会期望var baz = foo.bar在其背后有一套完整的隐藏行为。想到的是从foo.getBar(),但是。
2021-04-01 22:51:12