인형 용 게터 \ 세터


133

나는 getters와 setter 주위에 머리를 갖기 위해 노력하고 있었고 그것의 침몰하지 않았다. 나는 JavaScript Getters and SettersGetters and Setters 정의하고 그것을 얻지 못했다.

누군가가 명확하게 진술 할 수 있습니까?

  1. 게터와 세터가해야 할 일
  2. 아주 간단한 예를 들어보십시오.

12
개인적으로, 나는 당신이 John 's보다 더 명확한 설명을 얻는 방법을 모르겠습니다.
Jason Bunting

OO의 세계, getter 및 setter 도움을 쓰기 제대로 캡슐화하는 클래스에서
overexchange

기본적으로 다음과 같이 보입니다. 속성을 가져오고 설정하기 위해 과부하를 정의하고 있으며 이러한 과부하는 함수입니다. 하지만 전화 할 필요는 없습니다. 당신이 대체 할 수있는이 방법 a = setValue(5);으로 a = 5;하고 setValue()따라서 당신이 원하는대로 할 후드를 호출 할 것이다.
Andrew

답변:


102

@ millimoose '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];
    }
};

지금, 당신은 설정할 수 있습니다 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"

2
@Akash : 아니요. 그러나 Internet Explorer 9는 Object.defineProperty게터와 세터를 정의 할 수 있는 최신 기능을 지원합니다 .
Matthew Crumley

9
MS가 JS를 올바르게 지원하지 않고 실버 라이트를 어느 곳에서나 실행하지 않는 것이 정말 고통스럽지 않습니다. 따라서 SL과 세계를 위해 하나씩 두 번 모두 프로그래밍해야합니다.)
Akash Kava

2
@Martin : John 's answer 과 동일한 기술을 사용하여 비공개로 만들 수 있습니다 . 실제 게터 / 세터를 사용하려면 this.__defineGetter__또는 최신 Object.defineProperty기능 을 사용해야 합니다.
Matthew Crumley

1
위에 나열된 접근 방식의 한 가지 문제 만 이미 기존 클래스에 대한 게터 및 세터를 추가하려는 경우 프로토 타입을 재정의하고 원래 메서드에 액세스 할 수 없습니다.
xchg.ca

1
이 방법은 덮어 쓰지 Name.prototype.constructor않습니까? millimoose 's Answer의 나쁜 대안처럼 보입니다 .
r0estir0bbe

62

JavaScript의 게터와 세터

개요

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'

이는 범위에 숫자를 유지하거나 문자열을 다시 포맷하거나 변경된 이벤트를 트리거하거나 관계형 데이터를 업데이트하고 개인 속성에 대한 액세스를 제공하는 등 속성에 액세스 할 때 배후에서 자동으로 작업을 수행하는 데 유용합니다.

아래 예제는 기본 구문을 보여 주지만 특별한 작업을 수행하지 않고 내부 객체 값을 가져오고 설정합니다. 실제 상황에서는 위에서 언급 한대로 필요에 맞게 입력 및 / 또는 출력 값을 수정합니다.

키워드 가져 오기 / 설정

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;

커스텀 게터와 세터

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

사용 Object.defineProperty()은 게터와 세터를 추가하는 또 다른 방법이며 정의 된 객체에 사용할 수 있습니다. 또한 구성 가능하고 열거 가능한 동작을 설정하는 데 사용될 수 있습니다. 이 구문은 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 지원


1
에서 컴팩트 접근 , this[ '_' + name ] = value;this[ '_' + name ] = arguments[1];및 지정할 필요가 없을 것이다 value인수는.
Redhart

1
예 : var foo = { bar : 123, get bar(){ return bar; }, set bar( value ){ this.bar = value; } }; foo.bar = 456; 예외 발생 : Uncaught RangeError : Object.set bar [as bar] (<anonymous> : 4 : 32)에서 Object.set bar [as bar] (<anonymous> : 4 : 32)에서 최대 호출 스택 크기를 초과했습니다. ) Object.set 막대 [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)
nevf

1
설정 / 가져 오기 이름은 속성 이름과 달라야합니다. 예를 들어 bar: 123this.bar = value등 대신에 이를 변경하십시오 _bar . 참조 : hongkiat.com/blog/getters-setters-javascript
nevf

@nevf 정정 주셔서 감사합니다! 예, 일반적으로 계산 된 속성의 경우 "실제"내부 이름은 _fooor 와 같습니다 mFoo. getter / setter와 동일하면 재귀로 인해 무한 루프가 발생하고 스택 오버플로 ™ ;-)가 발생하므로 a = b라고 말하면 a.get (b)를 호출하고 자체적으로 a = b를 호출하므로 a.get (b), ...
Beejor

58

예를 들어 계산 된 속성을 구현하는 데 사용합니다.

예를 들면 다음과 같습니다.

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 속성에 게터를 할당하려고하는데 오류가 발생합니다. "var length의 선언"그리고 코드는 다음과 같습니다. obj = []; obj .__ defineGetter __ ( 'length', function () {return this.length;});

1
배열 객체에는 이미 길이 속성이 내장되어 있기 때문입니다. 재 선언이 허용 된 경우 새 길이를 호출하면 무한정 반복됩니다. "my_length"속성 또는 이와 유사한 것을 호출하십시오.
millimoose가

하나 개의 문장에 모두 게터를 정의하기 위해 사용합니다 Object.defineProperties.
r0estir0bbe

{ "area": ​​function () {return ...}} 만 만들 수 없습니까? 간단히 객체 속성으로 할당
RegarBoy

@developer 언어로 정의 된 자바 스크립트 게터가 아니라 함수일뿐입니다. 값을 얻기 위해 호출해야하며 속성에 대한 액세스를 과부하하지 않습니다. 또한 이미 존재하는 시스템을 구축하는 대신 JS에서 자체 깨진 객체 시스템을 발명 한 사람들을 위해 특별한 지옥이 있습니다.
millimoose

16

오래된 질문을 부활 시켜서 미안하지만, 몇 가지 매우 기본적인 예와 모형 설명에 기여할 수 있다고 생각했습니다. 지금까지 게시 된 다른 답변 중 어느 것도 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가 평균, 중앙값, 모드 및 범위를 계산하도록 프롬프트합니다. 그런 다음 각 결과에 대한 객체 속성을 설정합니다.


getMethod 또는 setMethod를 만드는 것과 get 및 set을 사용하는 것의 이점을 여전히 이해하지 못합니다. ()없이 호출 할 수있는 유일한 이점은 무엇입니까? 자바 스크립트에 추가 된 또 다른 이유가 있어야합니다.
Andreas

@Andreas Getter 및 Setter는 호출 될 때 속성처럼 동작하므로 의도 한 목적을 명확하게 설명 할 수 있습니다. 그렇지 않으면 빠진 능력의 잠금을 해제하지는 않지만 생각을 정리하는 데 도움이 될 수 있습니다. 이것이 진정한 이점입니다. 실용적인 예로, getter를 사용하여 Google Maps 객체를 확장했습니다. 카메라 타일 각도를 계산해야 맵 타일을 수평선으로 평평하게 회전 할 수있었습니다. Google은 이제 백엔드에서이를 자동으로 수행합니다. 그러나 당시에는 반환 값 maps.roll대신 속성 으로 검색하는 것이 도움이되었습니다 maps.roll(). 단지 환경 ​​설정입니다.
rojo

()없이 코드를 더 깨끗하게 보이게하는 것은 구문 설탕 일뿐입니다. 나는 당신이 왜 당신의 모범을 보여주지 못했는지maps.roll()
안드레아스

@Andreas 누가 내가 할 수 없다고 말합니까? 내가 말했듯이, 그것은 내 생각을 정리하는 데 도움이되는 방법 일뿐입니다. 코딩은 예술입니다. 밥 로스에게 오렌지를 사용할 수있을 때 왜 황토를 사용해야했는지 묻지 않아도됩니다. 당신은 지금 필요하지 않을지 모르지만, 언젠가 그림에 약간의 불이 붙을 필요가 있다고 결정할 때, 그것은 팔레트 위에있을 것입니다.
rojo

:) get 및 set 구문에서 볼 수있는 한 가지는 속성의 속성으로 사용되는 경우 자동 실행되는 것입니다.
Andreas

11

게터와 세터는 클래스의 전용 속성이있을 때만 의미가 있습니다. 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의 Javascript 개인 멤버에 대한 기사를 살펴보십시오 .


39
동의하지 않습니다. 게터와 세터는 그 정의가 단순한 변수가 아닌 정보를 캡슐화하는 데 매우 유용합니다. 이전에 간단한 속성을 사용했던 시스템의 동작과 다른 것들에 의존 할 수있는 시스템의 동작을 변경해야하는 경우 편리 할 수 ​​있습니다. 또한 예제는 단지 함수 인 "의사 게터"만 보여줍니다. 실제 JavaScript 게터 는 간단한 값으로 표시 되며 함수 표기법없이 액세스되므로 실제 힘을 얻을 수 있습니다.
devios1

내가 그렇게 강력하게 부를지 모르겠다. 뭔가 등장 하지만 X로는 Y가 반드시 명확하지 않다 정말이다. 나는 var baz = foo.bar그 뒤에 숨겨져있는 숨겨져있는 행동을 완전히 기대하지 않을 것 입니다. 나는 것입니다 으로부터 기대 foo.getBar()하지만,.
AgmLauncher

8

나는 당신이 연결하는 첫 번째 기사가 그것을 명확하게 밝힌다 고 생각합니다.

이러한 방식으로 JavaScript를 작성할 때의 분명한 이점은 사용자가 직접 액세스하기를 원하지 않는 값을 모호하게 사용할 수 있다는 것입니다.

여기서 목표는 get()또는 set()방법을 통해 필드에 대한 액세스 만 허용하여 필드를 캡슐화하고 추상화하는 것 입니다. 이런 방식으로 필드 / 데이터를 원하는 방식으로 내부에 저장할 수 있지만 외부 구성 요소는 게시 된 인터페이스에서 멀리 떨어져 있습니다. 이를 통해 외부 인터페이스를 변경하지 않고 내부 변경을 수행하거나 set()메소드 내에서 일부 유효성 검증 또는 오류 점검을 수행 할 수 있습니다 .


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

2

그것에 대해 혼란스러워하는 것은 ... getter는 속성을 얻을 때 설정되는 setter입니다. 예를 들어

obj.prop = "abc";

getters / setters를 사용하는 경우 속성 prop를 설정하고 "abc"를 인수로 사용하여 setter 함수가 호출됩니다. 객체 내부의 setter 함수 정의는 이상적으로 다음과 같습니다.

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

브라우저에서 얼마나 잘 구현되었는지 잘 모르겠습니다. Firefox에는 밑줄이 그어진 특수 ( "magic") 방법으로 대체 구문이있는 것 같습니다. 평소와 같이 Internet Explorer는이를 지원하지 않습니다.


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를 사용 하여이 코드를 실행할 수도 있습니다.


1
이것은 단지 새로운 getName 및 setName 메소드를 작성하는 것입니다. 이들은 속성 만들기와 관련이 없습니다!
uzay95

2

필자가 작성하지 않은 기존 프로토 타입에 속성을 추가하려고했기 때문에 내가 읽은 설명에 다소 혼란스러워서 프로토 타입을 교체하는 것이 잘못된 접근법처럼 보였습니다. 따라서 후손 last을 위해 Array다음에 속성을 추가하는 방법 은 다음과 같습니다.

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

IMHO 기능을 추가하는 것보다 약간 더 좋습니다.


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;

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

또는 codeforums.com 의 고급 typeof check : type.of () 코드를 사용하면 더 열광적입니다.


요점은 공용 인터페이스를 변경하지 않고도 속성을 더 멋진 것으로 변경할 수 있다는 것입니다. 통화 () 태그를 추가하면 변경됩니다.
마이클 스캇 커스버트
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.