다음과 같은 방법으로 이름이 이미 알려진 속성에 대해 getter 및 setter를 만드는 방법을 알고 있습니다.
// A trivial example:
function MyObject(val){
this.count = 0;
this.value = val;
}
MyObject.prototype = {
get value(){
return this.count < 2 ? "Go away" : this._value;
},
set value(val){
this._value = val + (++this.count);
}
};
var a = new MyObject('foo');
alert(a.value); // --> "Go away"
a.value = 'bar';
alert(a.value); // --> "bar2"
이제 제 질문은 이런 종류의 잡동사니와 세터를 정의 할 수 있습니까? 즉, 아직 정의 되지 않은 속성 이름에 대한 getter 및 setter를 만듭니다 .
개념은 PHP에서 __get()
and __set()
magic 메소드를 사용하여 가능 합니다 (이에 대한 정보 는 PHP 문서 를 참조하십시오 ). 이것과 동등한 JavaScript가 실제로 있습니까?
말할 필요도없이, 크로스 브라우저와 호환되는 솔루션이 이상적입니다.
답변
2013 및 2015 업데이트 (2011 년의 원래 답변은 아래 참조) :
이것은 ES2015 (일명 “ES6”) 사양으로 변경되었습니다 . 이제 JavaScript에 프록시가 있습니다. 프록시를 사용하면 다른 객체에 대한 실제 프록시 인 객체를 만들 수 있습니다. 다음은 검색시 모든 대문자로 문자열 인 속성 값을 바꾸는 간단한 예입니다.
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let original = {
"foo": "bar"
};
let proxy = new Proxy(original, {
get(target, name, receiver) {
let rv = Reflect.get(target, name, receiver);
if (typeof rv === "string") {
rv = rv.toUpperCase();
}
return rv;
}
});
console.log(`original.foo = ${original.foo}`); // "original.foo = bar"
console.log(`proxy.foo = ${proxy.foo}`); // "proxy.foo = BAR"
재정의하지 않은 작업에는 기본 동작이 있습니다. 위에서 우리가 재정의하는 것은 모두 get
이지만 연결할 수있는 전체 작업 목록이 있습니다.
에서 get
핸들러 함수의 인수 목록 :
target
프록시되는 객체입니다 (이original
경우에는).name
(물론) 검색되는 속성의 이름으로, 일반적으로 문자열이지만 기호 일 수도 있습니다.receiver
this
속성이 데이터 속성이 아닌 접근자인 경우 getter 함수에서와 같이 사용해야하는 객체입니다 . 일반적인 경우 프록시 또는 프록시에서 상속되는 것이지만 트랩이에 의해 트리거 될 수 있으므로 무엇이든 될 수 있습니다Reflect.get
.
이를 통해 원하는 범용 게터 및 세터 기능을 사용하여 객체를 만들 수 있습니다.
"use strict";
if (typeof Proxy == "undefined") {
throw new Error("This browser doesn't support Proxy");
}
let obj = new Proxy({}, {
get(target, name, receiver) {
if (!Reflect.has(target, name)) {
console.log("Getting non-existent property '" + name + "'");
return undefined;
}
return Reflect.get(target, name, receiver);
},
set(target, name, value, receiver) {
if (!Reflect.has(target, name)) {
console.log(`Setting non-existent property '${name}', initial value: ${value}`);
}
return Reflect.set(target, name, value, receiver);
}
});
console.log(`[before] obj.foo = ${obj.foo}`);
obj.foo = "bar";
console.log(`[after] obj.foo = ${obj.foo}`);
위의 결과는 다음과 같습니다.
존재하지 않는 속성 'foo'가져 오기 [이전] obj.foo = 정의되지 않음 존재하지 않는 속성 'foo'설정, 초기 값 : bar [후] obj.foo = 바
foo
아직 존재하지 않을 때 검색을 시도 할 때 그리고 존재하지 않을 때 다시 검색 할 때 “존재하지 않는”메시지를받는 방법에 주목 하십시오.
2011 년 답변 (2013 및 2015 업데이트는 위 참조) :
아니요, JavaScript에는 포괄적 인 속성 기능이 없습니다. 사용하는 접근 자 구문 은 사양의 11.1.5 절에서 다루며 와일드 카드 또는 이와 유사한 것을 제공하지 않습니다.
당신은 물론, 그것을 할 수있는 기능을 구현할 수 있습니다,하지만 난 당신이 아마 사용하지 않을 같은데요 f = obj.prop("foo");
보다는 f = obj.foo;
및 obj.prop("foo", value);
보다는 obj.foo = value;
(함수가 알 수없는 속성을 처리 할 필요가있을 것이다).
FWIW, getter 함수 (세터 로직을 신경 쓰지 않았습니다)는 다음과 같습니다.
MyObject.prototype.prop = function(propName) {
if (propName in this) {
// This object or its prototype already has this property,
// return the existing value.
return this[propName];
}
// ...Catch-all, deal with undefined property here...
};
그러나 다시 한 번 말하지만, 객체 사용 방식이 어떻게 바뀌는 지에 따라 실제로 그렇게하고 싶다고 상상할 수 없습니다.
답변
이 문제에 대한 독창적 인 접근 방식은 다음과 같습니다.
var obj = {
emptyValue: null,
get: function(prop){
if(typeof this[prop] == "undefined")
return this.emptyValue;
else
return this[prop];
},
set: function(prop,value){
this[prop] = value;
}
}
이를 사용하려면 속성을 문자열로 전달해야합니다. 작동 방식의 예는 다음과 같습니다.
//To set a property
obj.set('myProperty','myValue');
//To get a property
var myVar = obj.get('myProperty');
편집 :
내가 제안한 것을 기반으로 개선 된보다 객체 지향적 인 접근 방식은 다음과 같습니다.
function MyObject() {
var emptyValue = null;
var obj = {};
this.get = function(prop){
return (typeof obj[prop] == "undefined") ? emptyValue : obj[prop];
};
this.set = function(prop,value){
obj[prop] = value;
};
}
var newObj = new MyObject();
newObj.set('myProperty','MyValue');
alert(newObj.get('myProperty'));
여기서 작동하는 것을 볼 수 있습니다 .
답변
머리말:
TJ Crowder의 답변Proxy
은 OP가 요구 한대로 존재하지 않는 속성에 대한 포괄적 인 getter / setter에 필요한 a를 언급합니다 . 동적 게터 / 세터에서 실제로 원하는 동작에 따라 실제로는 Proxy
필요하지 않을 수도 있습니다. 또는 Proxy
아래에 표시 할 내용과 의 조합을 사용하고 싶을 수도 있습니다.
(PS 필자는 Proxy
최근 Linux의 Firefox에서 철저히 실험 해 보았으며 매우 유능한 것으로 나타 났지만 다소 혼란스럽고 어려워서 작업하고 올바르게 사용할 수 있음을 발견했습니다. 더 중요한 것은 (최소한 요즘에는 최적화 된 JavaScript가 어떻게 사용되는지와 관련이 있습니다)-나는 데카-다중의 영역에서 느리게 이야기하고 있습니다.)
동적으로 생성 된 게터 및 세터를 구체적으로 구현하려면 Object.defineProperty()
또는 을 사용할 수 있습니다 Object.defineProperties()
. 이것은 또한 매우 빠릅니다.
요점은 다음과 같이 객체에 getter 및 / 또는 setter를 정의 할 수 있다는 것입니다.
let obj = {};
let val = 0;
Object.defineProperty(obj, 'prop', { //<- This object is called a "property descriptor".
//Alternatively, use: `get() {}`
get: function() {
return val;
},
//Alternatively, use: `set(newValue) {}`
set: function(newValue) {
val = newValue;
}
});
//Calls the getter function.
console.log(obj.prop);
let copy = obj.prop;
//Etc.
//Calls the setter function.
obj.prop = 10;
++obj.prop;
//Etc.
여기에 몇 가지주의 할 사항이 있습니다.
value
속성 설명자 ( 위에 표시 되지 않음) 에서 속성 을get
및 / 또는 동시에 사용할 수 없습니다set
. 문서에서 :
객체에 존재하는 속성 디스크립터는 데이터 디스크립터와 접근 자 디스크립터의 두 가지 주요 특징이 있습니다. 데이터 디스크립터 또는 기록 가능하지 않을 수있는 값을 갖는 속성이다. 접근 디스크립터 기능 게터 세터 쌍 설명 속성이다. 설명자는이 두 가지 특징 중 하나 여야합니다. 둘 다 될 수는 없습니다.
- 따라서, 당신은 내가 만든 알게 될 것이다
val
속성 외부 의Object.defineProperty()
전화 / 속성 설명을. 이것은 표준 동작입니다. - 오류에 따라 여기에서 설정하지
writable
에true
당신이 사용하는 경우 속성 기술자get
또는set
. - 당신은 설정을 고려하는 것이 좋습니다
configurable
그리고enumerable
, 그러나, 당신이 계신에 따라; 문서에서 :
구성 가능
-
true
이 프로퍼티 디스크립터의 타입이 변경 될 수 있고 프로퍼티가 대응하는 객체로부터 삭제 될 수있는 경우에만. -
기본값은 false입니다.
열거 할 수있는
-
true
해당 객체의 속성을 열거하는 동안이 속성이 표시되는 경우에만 -
기본값은 false입니다.
-
이 메모에서 다음 사항도 관심이있을 수 있습니다.
Object.getOwnPropertyNames(obj)
: 열거 할 수없는 객체조차도 객체의 모든 속성을 가져옵니다 (AFAIK이 유일한 방법입니다!).Object.getOwnPropertyDescriptor(obj, prop)
: 객체가 전달 된 객체의 속성 설명자를 가져옵니다Object.defineProperty()
.obj.propertyIsEnumerable(prop);
: 특정 객체 인스턴스의 개별 속성에 대해 객체 인스턴스에서이 함수를 호출하여 특정 속성을 열거 할 수 있는지 여부를 결정합니다.
답변
var x={}
var propName = 'value'
var get = Function("return this['" + propName + "']")
var set = Function("newValue", "this['" + propName + "'] = newValue")
var handler = { 'get': get, 'set': set, enumerable: true, configurable: true }
Object.defineProperty(x, propName, handler)
이것은 나를 위해 작동