傻瓜用的吸引器

我一直试图让我的头周围获得者和设置和它没有沉入。我读过 JavaScript 的 Getters 和 Setters定义 Getters 和 Setters,就是不明白。

有没有人能明确地说:

  1. 一个取得者和设置者应该做什么
  2. 给出一些非常简单的例子?
129214 次浏览

我想你链接到的第一篇文章已经说得很清楚了:

以这种方式编写 JavaScript 的明显优势在于,您可以使用它模糊的值,而您不希望用户直接访问这些值。

这里的目标是通过仅允许通过 get()set()方法访问字段来封装和抽象这些字段。这样,您可以以任何方式在内部存储字段/数据,但是外部组件只能在已发布的接口之外。这允许您在不更改外部接口的情况下进行内部更改,在 set()方法中进行一些验证或错误检查,等等。

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

例如:

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

(CodePen)

如果您指的是访问器的概念,那么简单的目标就是隐藏底层存储,防止任意操作。最极端的机制是

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

如果您指的是实际的 JS getter/setter 特性,例如。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;

只有当您拥有类的私有属性时,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());

如果你仍然感到困惑,可以看看克罗克福德关于 Javascript 中的私有成员的文章。

除了 @ milmoose 的回答,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"

我给你们准备了一个,可能有点难看,但是可以跨平台完成

function myFunc () {


var _myAttribute = "default";


this.myAttribute = function() {
if (arguments.length > 0) _myAttribute = arguments[0];
return _myAttribute;
}
}

你打电话的时候,这边走

var test = new myFunc();
test.myAttribute(); //-> "default"
test.myAttribute("ok"); //-> "ok"
test.myAttribute(); //-> "ok"

如果你真的想让事情变得更有趣. . 你可以插入一个类型的检查:

if (arguments.length > 0 && typeof arguments[0] == "boolean") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "number") _myAttribute = arguments[0];
if (arguments.length > 0 && typeof arguments[0] == "string") _myAttribute = arguments[0];

或者更疯狂地使用高级类型的支票: 类别() codingforums.com

令人困惑的是... getter 是当你得到一个属性时调用的函数,setter,当你设置它的时候。 举个例子

obj.prop = "abc";

如果使用 getters/setter,那么将调用 setter 函数,并以“ abc”作为参数。 对象内部的 setter 函数定义理想情况下是这样的:

set prop(var) {
// do stuff with var...
}

我不确定这在不同浏览器之间的实现效果如何。Firefox 似乎还有另一种语法,即双重强调的特殊(“魔术”)方法。像往常一样,Internet Explorer 并不支持这些观点。

您可以通过构造函数的原型为 js 类定义实例方法。

下面是示例代码:

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

而且,这应该适用于任何浏览器,您也可以简单地使用 nodejs 来运行这段代码。

我也对 我看到的解释感到有些困惑,因为我试图向一个我没有编写的现有原型添加一个属性,所以替换原型似乎是错误的方法。因此,为了子孙后代,下面是我如何将 last属性添加到 Array:

Object.defineProperty(Array.prototype, "last", {
get: function() { return this[this.length - 1] }
});

比添加一个函数稍微好一点。

不好意思,重提一个老问题,但是我想我可以提供一些非常基本的例子和对于傻瓜的解释。到目前为止发布的其他答案都没有像 MDN 指南的第一个示例那样说明语法,这是我们能得到的最基本的东西。

盖特:

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


console.log(settings.fullname);

当然会记录 John SmithGetter的行为类似于可变对象属性,但是它提供了函数的灵活性,可以动态地计算返回值。这基本上是一种创建在调用时不需要()的函数的奇妙方法。

塞特:

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 类似,赛特犬的调用语法与设置对象属性的值相同,但它是另一种不使用()调用函数的花哨方法。

请参阅 这把小提琴以获得更全面、也许更实际的示例。将值传递到对象的 塞特将触发其他对象项的创建或填充。具体来说,在 jsfiddle 示例中,传递数字数组提示 setter 计算均值、中值、模式和范围; 然后为每个结果设置对象属性。

JavaScript 中的 Getters 和 Setters

概述

JavaScript 中的 Getters 和 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支持定义计算属性的 getset关键字。除了 IE8及以下的浏览器,它们可以与所有的现代浏览器兼容。

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

自定义获取器和设置器

getset不是保留字,因此可以重载它们来创建自己的自定义跨浏览器计算属性函数。这在任何浏览器中都可以工作。

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.barfoo.get( 'bar' )并获得“生的”值。根据所访问的属性的名称(通过 name参数) ,可以使用条件代码执行不同的操作。

定义属性()

使用 Object.defineProperty()是添加 getter 和 setter 的另一种方法,并且可以在对象定义之后使用它们。它还可以用来设置可配置和可枚举的行为。这种语法也适用于 IE8,但不幸的是只适用于 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;

_ _ defeGetter _ _ ()

最后,__defineGetter__()是另一种选择。虽然已经过时了,但仍然在网络上广泛使用,因此不太可能很快消失。它适用于除 IE10及以下浏览器之外的所有浏览器。尽管其他的选项在非 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 走开 准备好了, Object.defeProperty () _ _ defeGetter _ _ (),< a href = “ https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global _ Objects/Object/_ _ defeSetter _ _”rel = “ nofollow norefrer”> _ _ defeSetter _ _ ()
MSDN IE8 Getter 支持

尽管我们通常习惯于看到具有公共属性的对象而不能访问 控件,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

你也可以使用 __defineGetter__:

function Vector2(x,y) {
this.x = x;
this.y = y;
}


Vector2.prototype.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});


console.log(new Vector2(1,1).magnitude)

或者,如果你愿意的话:

function Vector2(x,y) {
this.x = x;
this.y = y;
this.__defineGetter__("magnitude", function () {
return Math.sqrt(this.x*this.x+this.y*this.y);
});
}






console.log(new Vector2(1,1).magnitude)

但是这个函数最近被标记为“遗产”,取而代之的是 Object.defineProperty()

这里没有 ES6 class的例子(它现在甚至不是‘新’的,它是标准) :

class Student {


contructor(firstName, lastName){
this.firstName = firstName
this.lastName = lastName
this.secretId = Math.random()
}
    

get fullName() {
return `${this.firstName} ${this.lastName}`; // this is backtick in js, u can check it out here: https://stackoverflow.com/a/27678299/12056841
}


set firstName(newFirstName) {
// validate that newFirstName is a string (and maybe limit length)
this.firstName = newFirstName
}


get studentId() { return this.secretId }
}

没有二传手代表 secret Id 因为我们不希望任何人改变它。

* * 如果 secretId根本不应该改变,一个好的方法是通过在它上面添加一个“ #”来将它声明为“ private” (例如: this.#secretId = Math.random()return this.#secretId

更新: 关于后台字段 您可能需要重命名您的字段-或您的 setter 函数,但更改您的字段名称对我来说更有意义。一个选项就像我上面提到的那样(使用 #将字段声明为“ private”)。另一种方法是重命名它(_firstNamefirstName_...)