傻瓜的吸气剂\设定者

时间:2009-05-01 19:52:59

标签: javascript setter getter

我一直在努力让自己的目标围绕着吸气剂和二传手而不是沉没。我已经阅读了JavaScript Getters and SettersDefining Getters and Setters并且没有得到它。

有人可以明确说明:

  1. getter和setter的目的是什么,
  2. 举几个非常简单的例子?

14 个答案:

答案 0 :(得分:91)

除了@Sii's answer之外,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];
    }
};

现在,您可以设置fullNamefirstlast将会更新,反之亦然。

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"

答案 1 :(得分:57)

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

例如:

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)

答案 2 :(得分:53)

JavaScript中的Getters和Setter

概述

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关键字来定义计算属性。它们适用于除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

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.bar; },
    getB : ..., getC : ..., setA : ..., setB : ..., setC : ...
};

对于上面的示例,内部属性名称是用下划线抽象的,以阻止用户简单地执行foo.barfoo.get( 'bar' )并获得&#34;未烹饪&#34;值。您可以使用条件代码执行不同的操作,具体取决于所访问属性的名称(通过name参数)。

Object.defineProperty()

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

var foo = { bar : 123 };
Object.defineProperty( foo, 'bar', {
    get : function(){ return 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; } );

另见

MDN getsetObject.defineProperty()__defineGetter__()__defineSetter__()
MSDN IE8 Getter Support

答案 3 :(得分:14)

很抱歉重新提出一个旧问题,但我想我可能会提供一些非常基本的例子和假人解释。所发布的其他答案都没有说明像MDN guide的第一个例子那样的语法,它与人们可以得到的基本一样。

<强>吸气剂:

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

console.log(settings.fullname);

...当然会记录John Smith getter 的行为类似于变量对象属性,但提供了函数的灵活性,可以动态计算其返回值。在调用时,创建一个不需要()的函数基本上是一种奇特的方式。

<强>设置器:

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 ,但这是另一种在没有()的情况下调用函数的奇特方式。

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

答案 4 :(得分:11)

当你拥有类的私有属性时,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的文章。

答案 5 :(得分:6)

我认为您链接的第一篇文章非常明确地说明了这一点:

  

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

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

答案 6 :(得分:6)

虽然我们经常习惯于看到具有公共属性的对象而没有任何访问权限 控制,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

答案 7 :(得分:2)

令人困惑的是...... getter是当你设置一个属性,setter时调用的函数。 例如,如果你这样做

obj.prop = "abc";

你正在设置属性prop,如果你使用getter / setter,那么将调用setter函数,并以“abc”作为参数。 对象内部的setter函数定义理想情况如下:

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

我不确定在各种浏览器中实现的效果如何。似乎Firefox也有一种替代语法,使用双重下划线特殊(“魔术”)方法。像往常一样,Internet Explorer不支持任何此类功能。

答案 8 :(得分:2)

您可以通过构造函数的原型为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来运行此代码。

答案 9 :(得分:2)

我也对explanation I read感到有些困惑,因为我试图将一个属性添加到我没写过的现有原型中,所以替换原型似乎是错误的方法。因此,对于子孙后代,我在last添加Array属性的方式如下:

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

比添加函数恕我直言更好。

答案 10 :(得分:1)

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

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

VS

var a = { get value(){ return 5; }; }
for (var i = 0; i < 100000; i++)
    a.value;

答案 11 :(得分:0)

您也可以使用__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()

答案 12 :(得分:0)

这里没有 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 }
}

并且 没有 setter 用于 secretId,因为我们不希望任何人更改它。

** if secretId 根本不应该改变,一个很好的方法是通过向它添加一个“#”来将它声明为这个的“私有” (例如:this.#secretId = Math.random()return this.#secretId

答案 13 :(得分:-1)

我有一个可能有点丑陋的人,但它确实可以跨平台完成

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

或使用高级类型检查更加疯狂:type.of() code at codingforums.com