[javascript] 프로토 타입에서 setter / getter를 정의하는 방법

2016 년 10 월 수정 :이 질문은 2012 년에 요청되었습니다. 매달 누군가가 답변을 반박하는 새로운 답변이나 댓글을 추가하지만 질문이 오래되었을 수 있으므로 그렇게하는 것이 의미가 없습니다. Gnome Javascript 가 브라우저 항목이 아닌 그놈 쉘 확장을 작성 하는 것이 었습니다 .

Javascript에서 하위 클래스를 수행하는 방법에 대한 이전 질문 에 따라 다음 과 같이 수퍼 클래스의 하위 클래스를 만들고 있습니다.

function inherits(Child,Parent) {
    var Tmp = function {};
    Tmp.prototype = Parent.prototype;
    Child.prototype = new Tmp();
    Child.prototype.constructor = Child;
}
/* Define subclass */
function Subclass() {
    Superclass.apply(this,arguments);
    /* other initialisation */
}
/* Set up inheritance */
inherits(Subclass,Superclass);
/* Add other methods */
Subclass.prototype.method1 = function ... // and so on.

내 질문은 이 구문을 사용하여 프로토 타입에서 setter / getter를 어떻게 정의합니까?

나는 그것을 하고는했다:

Subclass.prototype = {
    __proto__: Superclass.prototype,
    /* other methods here ... */

    get myProperty() {
        // code.
    }
}

그러나 분명히 다음은 작동하지 않습니다.

Subclass.prototype.get myProperty() { /* code */ }

저는 GJS (GNOME Javascript)를 사용하고 있으며 엔진은 Mozilla Spidermonkey와 거의 동일합니다. 내 코드는 GJS에서 지원하는 한 브라우저 용이 아닙니다 (Spidermonkey를 의미합니까?). 교차 호환이되지 않아도 상관 없습니다.



답변

객체 리터럴 선언 사용 (가장 간단한 방법) :

var o = {
    a: 7,
    get b() {
        return this.a + 1;
    },
    set c(x) {
        this.a = x / 2
    }
};

사용 Object.defineProperty(ES5를 지원하는 최신 브라우저에서) :

Object.defineProperty(o, "myProperty", {
    get: function myProperty() {
        // code
    }
});

또는 __defineGetter__및 사용 __defineSetter__( DEPRECATED ) :

var d = Date.prototype;
d.__defineGetter__("year", function() { return this.getFullYear(); });
d.__defineSetter__("year", function(y) { this.setFullYear(y); });


답변

사용 Object.defineProperty()Subclass.prototype. 이 또한 __defineGetter____defineSetter__일부 브라우저에서 사용할 수 있지만,이되지 않습니다. 귀하의 예를 들면 다음과 같습니다.

Object.defineProperty(Subclass.prototype, "myProperty", {
    get: function myProperty() {
        // code
    }
});


답변

나는 당신이 이렇게하고 싶었다고 생각합니다.

function Unit() {
   	this._data; // just temp value
}
Unit.prototype = {
 	get accreation() {
   		return this._data;
   	},
   	set accreation(value) {
   		this._data = value
   	},
}
Unit.prototype.edit = function(data) {
   	this.accreation = data; // setting
   	this.out();
};

Unit.prototype.out = function() {
    alert(this.accreation); // getting
};

var unit = new Unit();
unit.edit('setting and getting');

function Field() {
    // children
}

Field.prototype = Object.create(Unit.prototype);

Field.prototype.add = function(data) {
  this.accreation = data; // setting
   	this.out();
}

var field1 = new Field();
field1.add('new value for getter&setter');

var field2 = new Field();
field2.out();// because field2 object has no setting


답변

setter와 getter를 “객체의 프로토 타입 내부에”정의하려면 다음과 같이해야합니다.

Object.defineProperties(obj.__proto__, {"property_name": {get: getfn, set: setfn}})

유틸리티 함수로 단축 할 수 있습니다.

//creates get/set properties inside an object's proto
function prop (propname, getfn, setfn) {
    var obj = {};
    obj[propname] = { get: getfn, set: setfn };
    Object.defineProperties(this, obj);
}

function Product () {
     this.name =  "Product";
     this.amount =  10;
     this.price =  1;
     this.discount =  0;
}

//how to use prop function
prop.apply(Product.prototype, ["total", function(){ return this.amount * this.price}]);

pr = new Product();
console.log(pr.total);

여기서는 prop.apply를 사용하여 Product.prototype을 호출 할 때 컨텍스트를 “this”로 설정합니다.

이 코드를 사용하면 질문에서 물었 듯이 인스턴스가 아닌 객체의 프로토 타입 내부에서 get / set 속성으로 끝납니다.

(테스트 된 Firefox 42, Chrome 45)


답변

Object.defineProperty () 메서드를 사용하여 생성자에서 getter 또는 setter를 지정합니다. 이 메서드는 세 가지 인수를 사용합니다. 첫 번째 인수는 속성을 추가 할 개체이고 두 번째 인수는 속성 이름이며 세 번째 인수는 속성 설명자입니다. 예를 들어 다음과 같이 person 객체의 생성자를 정의 할 수 있습니다.

var Employee = (function() {
    function EmployeeConstructor() {
        this.first = "";
        this.last = "";
        Object.defineProperty(
            this,
            "fullName", {
                get: function() {
                    return this.first + " " +
                        this.last;
                },
                set: function(value) {
                    var parts = value.toString().split(" ");
                    this.name = parts[0] || "";
                    this.last = parts[1] || "";
                }
            });
    }
    return
    EmployeeConstructor;
}());

Object.defineProperty ()를 사용하면 속성 정의를 더 잘 제어 할 수 있습니다. 예를 들어, 설명하는 속성을 동적으로 삭제하거나 재정의 할 수 있는지, 값을 변경할 수 있는지 등을 지정할 수 있습니다.

설명자 객체의 다음 속성을 설정하여 이러한 제약을 적용 할 수 있습니다.

  • 쓰기 가능 : 속성 값을 변경할 수 있는지 여부를 나타내는 부울입니다. 기본값은 false입니다.
  • configurable : 속성의 설명자를 변경할 수 있는지 또는 속성 자체를 삭제할 수 있는지 여부를 나타내는 부울입니다. 기본값은 false입니다.
  • enumerable : 객체의 속성에 대한 루프에서 속성에 액세스 할 수 있는지 여부를 나타내는 부울입니다. 기본값은 false입니다.
  • value : 속성과 관련된 값을 나타냅니다. 기본값은 정의되지 않음


답변

다음 은 gettersetter 가있는 간단한 Animal → Dog상속의 예입니다 .Animal

//////////////////////////////////////////
// General Animal constructor
function Animal({age, name}) {
  // if-statements prevent triggering the setter on initialization
  if(name) this.name = name
  if(age) this.age = age
}

// an alias "age" must be used, so the setter & getter can use an
// alternative variable, to avoid using "this.age", which will cause
// a stack overflow of "infinite" call stack when setting the value.
Object.defineProperty(Animal.prototype, "age", {
  get(){
    console.log("Get age:", this.name, this._age) // getting
    return this._age
  },
  set(value){
    this._age = value
    console.log("Set age:", this.name, this._age) // setting
  }
})




//////////////////////////////////////////
// Specific Animal (Dog) constructor
function Dog({age = 0, name = 'dog'}) {
  this.name = name
  this.age = age
}

// first, defined inheritance
Dog.prototype = new Animal({});

// add whatever additional methods to the prototype of Dog
Object.assign(Dog.prototype, {
  bark(woff){
    console.log(woff)
  }
})


//////////////////////////////////////////
// Instanciating
var koko = new Animal({age:300, name:'koko'})
var dog1 = new Dog({age:1, name:'blacky'})
var dog2 = new Dog({age:5, name:'shorty'})

console.log(dog1)
koko.age
dog1.age = 3;
dog1.age
dog2.age


답변