인형 용 게터 \ 세터


133

나는 getters와 setter 주위에 머리를 갖기 위해 노력하고 있었고 그것의 침몰하지 않았다. 나는 JavaScript Getters and Setters 와 Getters 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, 그리고 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"

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는 계산 된 속성을 정의하기위한 키워드 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.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: 123및 this.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.