我一直在尝试理解getter和setter,但是没有领会。我已经阅读了JavaScript Getters and Setters和Defining Getters and Setters,但还是无法理解。
可以有人清楚地说明:
- getter和setter的目的是什么,以及
- 给出一些非常简单的示例吗?
我一直在尝试理解getter和setter,但是没有领会。我已经阅读了JavaScript Getters and Setters和Defining Getters and Setters,但还是无法理解。
可以有人清楚地说明:
除了@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
,然后first
和last
将被更新,反之亦然。
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"
Object.defineProperty
函数来定义getter和setter。 - Matthew Crumleythis.__defineGetter__
或者较新的Object.defineProperty
函数。 - Matthew CrumleyJavaScript中的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'
当访问属性时,自动执行某些操作非常有用,比如保持数字在范围内,重新格式化字符串,触发值已更改事件,更新关联数据,提供对私有属性的访问等等。
以下示例展示了基本语法,尽管它们只是获取和设置内部对象的值,而没有做任何特殊处理。在实际情况中,您需要修改输入和/或输出值,以满足您的需求,如上所述。
ECMAScript 5 支持 get
和 set
关键字来定义计算属性。它们适用于除IE 8及以下之外的所有现代浏览器。
var foo = {
bar : 123,
get bar(){ return bar; },
set bar( value ){ this.bar = value; }
};
foo.bar = 456;
var gaz = foo.bar;
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.bar
而获取一个“未经处理”的值,上述示例中的内部属性名称是用下划线抽象的。您可以使用条件代码根据所访问的属性名称(通过name
参数)来执行不同的操作。
使用Object.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__()
是另外一种选择。虽然它已经被弃用,但仍然广泛用于网络,因此不太可能很快消失。它适用于除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 Support
this[ '_' + name ] = value;
可以改为 this[ '_' + name ] = arguments[1];
,这样就不需要指定 value
参数了。 - dystopiandev 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)
at 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)
at Object.set bar [as bar] (<anonymous>:4:32) - nevfbar: 123
和this.bar=value
更改为例如_bar
。详情请见:https://www.hongkiat.com/blog/getters-setters-javascript/ - nevf_foo
或 mFoo
。如果与 getter/setter 相同,它将由于递归而导致无限循环,然后出现 Stack Overflow™;-) 因为当您说 a = b 时,它调用 a.get(b),它本身又调用 a = b,这又调用 a.get(b),... - Beejor你可以使用它们来实现计算属性。
例如:
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
“变量length的重新声明”
代码看起来像这样:obj = [];
obj.__defineGetter__('length',function(){
return this.length;
});
- oksf抱歉搬起老问题,但我想提供一些非常基本的例子和白痴式的解释。到目前为止,没有其他答案展示了像MDN指南第一个例子那样的语法,这是最基本的。
Getter:
var settings = {
firstname: 'John',
lastname: 'Smith',
get fullname() { return this.firstname + ' ' + this.lastname; }
};
console.log(settings.fullname);
当然会记录 John Smith
。一个getter类似于变量对象属性,但提供了像函数一样实时计算其返回值的灵活性。它基本上是创建一个在调用时不需要()的函数的花哨方式。
Setter:
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一样,setters的语法与设置对象属性值的语法相同,但是这是另一种不需要使用()调用函数的花式方法。
请参见此jsfiddle,以获取更详细、更实用的示例。将值传递到对象的setter中会触发其他对象项的创建或填充。具体来说,在jsfiddle示例中,传递一个数字数组会提示setter计算平均数、中位数、众数和范围;然后为每个结果设置对象属性。
maps.roll
作为属性而不是maps.roll()
的返回值是有帮助的。这只是一种偏好。 - rojomaps.roll()
来举例。 - Andreas只有在类的私有属性存在时,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());
var baz = foo.bar
背后有一整套隐藏的行为。然而,我会期望foo.getBar()
有这样的行为。 - AgmLauncher虽然我们经常看到具有公共属性且没有任何访问控制的对象,但JavaScript允许我们准确地描述属性。实际上,我们可以使用描述符来控制属性的访问方式以及可以应用哪些逻辑。考虑以下示例:
var employee = {
first: "Boris",
last: "Sergeev",
get fullName() {
return this.first + " " + this.last;
},
set fullName(value) {
var parts = value.toString().split(" ");
this.first = parts[0] || "";
this.last = parts[1] || "";
},
email: "boris.sergeev@example.com"
};
console.log(employee.fullName); //Boris Sergeev
employee.fullName = "Alex Makarenko";
console.log(employee.first);//Alex
console.log(employee.last);//Makarenko
console.log(employee.fullName);//Alex Makarenko
// BaseClass
var BaseClass = function(name) {
// instance property
this.name = name;
};
// instance method
BaseClass.prototype.getName = function() {
return this.name;
};
BaseClass.prototype.setName = function(name) {
return this.name = name;
};
// test - start
function test() {
var b1 = new BaseClass("b1");
var b2 = new BaseClass("b2");
console.log(b1.getName());
console.log(b2.getName());
b1.setName("b1_new");
console.log(b1.getName());
console.log(b2.getName());
}
test();
// test - end
而且,这适用于任何浏览器,您还可以使用Node.js来运行此代码。
这有什么难懂的... getters 是在获取属性时调用的函数,setters 是在设置属性时调用的函数。 例如,如果你执行以下代码:
obj.prop = "abc";
如果你正在使用getter/setter,那么你正在设置属性prop,setter函数将被调用,并传入"abc"作为参数。对象内的setter函数定义应该像这样:
set prop(var) {
// do stuff with var...
}
我不确定这在不同浏览器上的实现效果如何。似乎Firefox也有一种替代语法,使用双下划线特殊(“魔术”)方法。像往常一样,Internet Explorer不支持这些。
function Foo(someValue) {
this.getValue = function() { return someValue; }
return this;
}
var myFoo = new Foo(5);
/* We can read someValue through getValue(), but there is no mechanism
* to modify it -- hurrah, we have achieved encapsulation!
*/
myFoo.getValue();
defineGetter
/defineSetter
或{ get Foo() { /* code */ } }
,那么值得注意的是,在大多数现代引擎中,这些属性的后续使用速度会比其他方式要慢得多。例如,比较以下性能:var a = { getValue: function(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.getValue();
对比。
var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
a.value;
a = 5;
替换a = setValue(5);
,并且setValue()
将在幕后被调用以执行任何你想要的操作。 - Andrew