javascript Object.defineProperty를 사용하는 방법
그 방법을 어떻게 사용해야 하는지 둘러보았지만, 괜찮은 것을 찾을 수 없었습니다.
누군가가 나에게 코드 조각을 주었습니다.
Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
})
하지만 이해가 안 돼요.주로,get
내가 얻을 수 없는 것입니다(펀 의도).어떻게 작동합니까?
비슷한 질문을 하셨으니 차근차근 해보도록 하겠습니다.시간이 좀 더 걸리지만, 제가 이 글을 쓰는 데 쓴 시간보다 훨씬 더 많은 시간을 절약할 수 있을 것입니다.
속성은 클라이언트 코드를 깨끗하게 분리하도록 설계된 OOP 기능입니다.예를 들어 일부 e-shop에는 다음과 같은 개체가 있을 수 있습니다.
function Product(name,price) {
this.name = name;
this.price = price;
this.discount = 0;
}
var sneakers = new Product("Sneakers",20); // {name:"Sneakers",price:20,discount:0}
var tshirt = new Product("T-shirt",10); // {name:"T-shirt",price:10,discount:0}
그런 다음 고객 코드(e-shop)에서 제품에 할인을 추가할 수 있습니다.
function badProduct(obj) { obj.discount+= 20; ... }
function generalDiscount(obj) { obj.discount+= 10; ... }
function distributorDiscount(obj) { obj.discount+= 15; ... }
나중에 e-shop 소유자는 할인율이 80%보다 클 수 없다는 것을 알게 될 것입니다.이제 고객 코드에서 할인 수정 사항이 발생할 때마다 찾아 라인을 추가해야 합니다.
if(obj.discount>80) obj.discount = 80;
그러면 e-shop 소유자는 "고객이 리셀러인 경우 최대 90% 할인이 가능합니다"와 같은 전략을 추가로 변경할 수 있습니다.그리고 여러 장소에서 변경을 다시 해야 하고, 전략이 변경될 때마다 이러한 선을 변경해야 한다는 것을 기억해야 합니다.이것은 나쁜 디자인입니다.그래서 캡슐화가 OOP의 기본 원리입니다.생성자가 다음과 같은 경우:
function Product(name,price) {
var _name=name, _price=price, _discount=0;
this.getName = function() { return _name; }
this.setName = function(value) { _name = value; }
this.getPrice = function() { return _price; }
this.setPrice = function(value) { _price = value; }
this.getDiscount = function() { return _discount; }
this.setDiscount = function(value) { _discount = value; }
}
그러면 당신은 그냥 변경할 수 있습니다.getDiscount
(액세스) 및setDiscount
(변광자) 방법문제는 대부분의 회원들이 공통 변수처럼 행동하는데, 단지 할인은 여기서 특별한 주의가 필요하다는 것입니다.그러나 좋은 설계를 위해서는 코드 확장성을 유지하기 위해 모든 데이터 구성원의 캡슐화가 필요합니다.그래서 당신은 아무것도 하지 않는 많은 코드를 추가해야 합니다.이것은 또한 나쁜 디자인, 보일러 플레이트 반대 패턴입니다.때때로 나중에 필드를 메소드로 리팩터링할 수 없습니다(eshop 코드가 커지거나 일부 타사 코드가 이전 버전에 따라 달라질 수 있음). 따라서 여기서 상용판은 덜 악의적입니다.하지만 여전히, 그것은 사악합니다.그것이 부동산이 많은 언어로 소개된 이유입니다.당신은 원래 코드를 유지할 수 있습니다, 단지 할인 회원을 부동산으로 바꿀 수 있습니다.get
그리고.set
블록:
function Product(name,price) {
this.name = name;
this.price = price;
//this.discount = 0; // <- remove this line and refactor with the code below
var _discount; // private member
Object.defineProperty(this,"discount",{
get: function() { return _discount; },
set: function(value) { _discount = value; if(_discount>80) _discount = 80; }
});
}
// the client code
var sneakers = new Product("Sneakers",20);
sneakers.discount = 50; // 50, setter is called
sneakers.discount+= 20; // 70, setter is called
sneakers.discount+= 20; // 80, not 90!
alert(sneakers.discount); // getter is called
마지막 한 줄만 주의하십시오. 올바른 할인 가치에 대한 책임이 고객 코드(e-shop 정의)에서 제품 정의로 이동되었습니다.제품은 데이터 구성원의 일관성을 유지할 책임이 있습니다.코드가 우리의 생각과 같은 방식으로 작동한다면 좋은 디자인은 (대략적으로) 말합니다.
부동산에 대한 것이 많습니다.그러나 Javascript는 C#과 같은 순수 객체 지향 언어와는 다르며 기능을 다르게 코딩합니다.
C#에서 필드를 속성으로 변환하는 것은 획기적인 변경이므로 코드가 별도로 컴파일된 클라이언트에서 사용될 수 있는 경우 공용 필드를 자동 구현 속성으로 코딩해야 합니다.
Javascript에서 표준 속성(위에서 설명한 getter와 setter가 있는 데이터 멤버)은 접근자 설명자(질문에 있는 링크)에 의해 정의됩니다.데이터 설명자를 단독으로 사용할 수 있습니다(따라서 동일한 속성에 값과 설정을 사용할 수 없음).
- accessor descriptor = get + set (위 예제 참조)
- get은 함수여야 합니다. 반환 값은 속성을 읽는 데 사용됩니다. 지정하지 않으면 기본값이 정의되지 않았습니다. 이 기본값은 정의되지 않았습니다. 정의되지 않은 값을 반환하는 함수처럼 동작합니다.
- 집합은 함수여야 합니다. 속성에 값을 할당할 때 매개 변수가 RHS로 채워집니다. 지정하지 않으면 기본값이 정의되지 않으며 빈 함수처럼 동작합니다.
- 데이터 설명자 = 값 + 쓰기 가능(아래 예 참조)
- 값 기본값이 정의되지 않았습니다. 쓰기 가능, 구성 가능 및 열거 가능(아래 참조)이 참이면 속성이 일반 데이터 필드처럼 작동합니다.
- 쓰기 가능 - 기본값은 false이고, true가 아닐 경우 속성은 읽기 전용이며, 쓰기 시도는 오류 없이 무시됩니다*!
두 설명자 모두 다음 구성원을 가질 수 있습니다.
- 구성 가능 - 기본값은 false입니다. true가 아닐 경우 속성을 삭제할 수 없습니다. 삭제 시도는 오류 없이 무시됩니다.*!
- 열거 가능 - 기본값은 false입니다. true이면 에서 반복됩니다.
for(var i in theObject)
거짓이면 반복되지 않지만 여전히 공개적으로 액세스할 수 있습니다.
엄격한 모드가 아닌 경우 - 이 경우 JS는 TypeError를 사용하여 실행을 중지합니다(Try-catch 블록에 걸리지 않는 한).
이 설정을 읽으려면 다음을 사용합니다.Object.getOwnPropertyDescriptor()
.
예를 들어 알아보기:
var o = {};
Object.defineProperty(o,"test",{
value: "a",
configurable: true
});
console.log(Object.getOwnPropertyDescriptor(o,"test")); // check the settings
for(var i in o) console.log(o[i]); // nothing, o.test is not enumerable
console.log(o.test); // "a"
o.test = "b"; // o.test is still "a", (is not writable, no error)
delete(o.test); // bye bye, o.test (was configurable)
o.test = "b"; // o.test is "b"
for(var i in o) console.log(o[i]); // "b", default fields are enumerable
클라이언트가 이러한 부정행위를 코드화하는 것을 허용하지 않으려면 다음과 같은 세 가지 수준의 제한으로 개체를 제한할 수 있습니다.
- Object.preventExtensions(사용자의 Object)는 새 속성이 사용자의 Object에 추가되지 않도록 합니다. 사용
Object.isExtensible(<yourObject>)
메서드가 개체에 사용되었는지 확인합니다.예방은 얕습니다(아래 참조). - Object.seal(yourObject)은 위와 동일하며 속성은 제거할 수 없습니다(유효하게 설정됨).
configurable: false
모든 속성에 적용됩니다.Object.isSealed(<yourObject>)
개체에서 이 기능을 탐지합니다.씰이 얕습니다(아래 참조). - Object.freeze(yourObject)는 위와 동일하며 속성은 변경할 수 없습니다(유효하게 설정됨).
writable: false
모든 속성(데이터 설명자 포함)에 적용됩니다.Setter의 쓰기 가능한 속성은 해당 속성이 없으므로 영향을 받지 않습니다.동결은 얕다: 속성이 Object이면 속성이 동결되지 않는다는 것을 의미합니다. (만약 당신이 원한다면, 딥 프리즈와 같은 것을 수행해야 합니다, 딥 카피 클로닝Object.isFrozen(<yourObject>)
그것을 감지하기 위해.
몇 줄만 재미있게 쓰면 이런 거 신경 안 써도 돼요.그러나 연결된 질문에서 언급한 것처럼 게임을 코딩하려면 좋은 디자인에 신경을 써야 합니다.안티패턴과 코드 냄새에 대한 구글 검색을 시도해보세요."오, 코드를 완전히 다시 써야 해요!"와 같은 상황을 피하는 데 도움이 될 것입니다. 코드를 많이 작성하고 싶다면 몇 달 동안의 절망을 덜어줄 수 있습니다.행운을 빌어요.
get
는 값을 읽으려고 할때입니다.player.health
과 같은 위치 예:
console.log(player.health);
효과적으로 다음과 크게 다르지 않습니다.
player.getHealth = function(){
return 10 + this.level*15;
}
console.log(player.getHealth());
get의 반대 방향이 설정되어 있으며, 이는 값을 할당할 때 사용됩니다.세터가 없기 때문에 플레이어의 상태를 할당하는 것은 의도되지 않은 것 같습니다.
player.health = 5; // Doesn't do anything, since there is no set function defined
매우 간단한 예:
var player = {
level: 5
};
Object.defineProperty(player, "health", {
get: function() {
return 10 + (player.level * 15);
}
});
console.log(player.health); // 85
player.level++;
console.log(player.health); // 100
player.health = 5; // Does nothing
console.log(player.health); // 100
defineProperty는 일부 기준을 충족하도록 속성을 구성할 수 있는 Object의 메서드입니다.다음은 firstName 및 lastName 두 속성을 가진 직원 개체에 대한 간단한 예로, 개체에서 toString 메서드를 재정의하여 두 속성을 추가합니다.
var employee = {
firstName: "Jameel",
lastName: "Moideen"
};
employee.toString=function () {
return this.firstName + " " + this.lastName;
};
console.log(employee.toString());
출력은 다음과 같이 표시됩니다: Jameel Moideen
개체에 대한 defineProperty를 사용하여 동일한 코드를 변경합니다.
var employee = {
firstName: "Jameel",
lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
value: function () {
return this.firstName + " " + this.lastName;
},
writable: true,
enumerable: true,
configurable: true
});
console.log(employee.toString());
첫 번째 매개 변수는 개체의 이름이고 두 번째 매개 변수는 추가할 속성의 이름입니다. 이 경우 문자열에 해당하고 마지막 매개 변수는 함수가 될 값과 쓰기 가능하고 열거 가능하며 구성 가능한 세 개의 매개 변수가 있는 json 개체입니다.지금 저는 모든 것이 사실이라고 선언했습니다.
예제를 실행하면 출력이 Jameel Moideen으로 표시됩니다.
쓰기 가능, 열거 및 구성 가능과 같은 세 가지 속성이 필요한 이유에 대해 알아보겠습니다.
쓰기 가능한
Javascript의 매우 성가신 부분 중 하나는 예를 들어 toString 속성을 다른 속성으로 변경하는 경우입니다.
이걸 다시 실행하면, 모든 것이 깨집니다.쓰기 가능을 거짓으로 변경합니다.동일하게 다시 실행하면 'Jameel Moideen'이라는 올바른 출력이 표시됩니다.이 속성은 나중에 이 속성을 덮어쓰지 못하게 합니다.
열거할 수 있는
객체 내부의 모든 키를 인쇄하면 toString을 포함한 모든 속성을 볼 수 있습니다.
console.log(Object.keys(employee));
열거형을 false로 설정하면 다른 모든 사용자로부터 String 속성을 숨길 수 있습니다.다시 실행하면 이름, 성이 표시됩니다.
구성 가능한
나중에 예를 들어 true로 열거할 수 있는 개체를 재정의하고 실행하는 경우.ToString 속성이 다시 온 것을 확인할 수 있습니다.
var employee = {
firstName: "Jameel",
lastName: "Moideen"
};
Object.defineProperty(employee, 'toString', {
value: function () {
return this.firstName + " " + this.lastName;
},
writable: false,
enumerable: false,
configurable: true
});
//change enumerable to false
Object.defineProperty(employee, 'toString', {
enumerable: true
});
employee.toString="changed";
console.log(Object.keys(employee));
구성 가능을 false로 설정하여 이 동작을 제한할 수 있습니다.
이 정보의 원래 참조는 제 개인 블로그에서 나온 것입니다.
기적으로본,defineProperty
는 개체, 속성 및 설명자의 세 가지 매개 변수를 사용하는 메서드입니다.은 이특한서일있고것는입니다."health"
의 player
개체가 플레이어 개체 레벨의 10+15배에 할당됩니다.
네, setter & getter를 위해 확장하는 더 이상의 함수가 없습니다. 이것은 제 예입니다. Object.defineProperty(obj,name,func)
var obj = {};
['data', 'name'].forEach(function(name) {
Object.defineProperty(obj, name, {
get : function() {
return 'setter & getter';
}
});
});
console.log(obj.data);
console.log(obj.name);
Object.defineProperty()는 글로벌 함수입니다.그렇지 않으면 개체를 선언하는 함수 내에서는 사용할 수 없습니다.정적으로 사용해야 할 것입니다.
요약:.
Object.defineProperty(player, "health", {
get: function () {
return 10 + ( player.level * 15 );
}
});
Object.defineProperty
플레이어 개체에 새 속성을 만드는 데 사용됩니다.Object.defineProperty
인수를 합니다.
Object.defineProperty(obj, prop, descriptor)
- 새 속성을 정의할 개체
- 정의할 새 속성의 이름
- 설명자 개체
설명자 객체는 흥미로운 부분입니다.여기서 우리는 다음과 같은 것들을 정의할 수 있습니다.
- 가능
<boolean>
만약true
속성 설명자가 변경되고 속성이 개체에서 삭제될 수 있습니다.한 경우는 성구가경우한입니다.false
는 속자성으로Object.defineProperty
변경할 수 없습니다. - 가능
<boolean>
만약true
할당 연산자를 사용하여 속성을 덮어쓸 수 있습니다. -
<boolean>
만약true
은 성은다같반수있습다니될복이로 할 수 .for...in
프루를 입니다. 또한 사용할 때Object.keys
기능 키가 존재합니다.이 속이다같은경인false
▁a다▁▁will▁▁not를 사용하는 것은 되지 않습니다.for..in
시않음지되표시루프▁and를 사용할 때 되지 않음Object.keys
. - 을 받다, 벌을 받다, 벌을 받다, 벌을 받다, 벌을 보다
<function>
속성일 때마다 호출되는 함수가 필요합니다. 값을 대신 이된 값을 합니다. -
<function>
속성이 할당될 때마다 호출되는 함수입니다.직접 값을 설정하는 대신 이 함수를 호출하고 반환된 값을 사용하여 속성 값을 설정합니다.
예:
const player = {
level: 10
};
Object.defineProperty(player, "health", {
configurable: true,
enumerable: false,
get: function() {
console.log('Inside the get function');
return 10 + (player.level * 15);
}
});
console.log(player.health);
// the get function is called and the return value is returned as a value
for (let prop in player) {
console.log(prop);
// only prop is logged here, health is not logged because is not an iterable property.
// This is because we set the enumerable to false when defining the property
}
import { CSSProperties } from 'react'
import { BLACK, BLUE, GREY_DARK, WHITE } from '../colours'
export const COLOR_ACCENT = BLUE
export const COLOR_DEFAULT = BLACK
export const FAMILY = "'Segoe UI', sans-serif"
export const SIZE_LARGE = '26px'
export const SIZE_MEDIUM = '20px'
export const WEIGHT = 400
type Font = {
color: string,
size: string,
accent: Font,
default: Font,
light: Font,
neutral: Font,
xsmall: Font,
small: Font,
medium: Font,
large: Font,
xlarge: Font,
xxlarge: Font
} & (() => CSSProperties)
function font (this: Font): CSSProperties {
const css = {
color: this.color,
fontFamily: FAMILY,
fontSize: this.size,
fontWeight: WEIGHT
}
delete this.color
delete this.size
return css
}
const dp = (type: 'color' | 'size', name: string, value: string) => {
Object.defineProperty(font, name, { get () {
this[type] = value
return this
}})
}
dp('color', 'accent', COLOR_ACCENT)
dp('color', 'default', COLOR_DEFAULT)
dp('color', 'light', COLOR_LIGHT)
dp('color', 'neutral', COLOR_NEUTRAL)
dp('size', 'xsmall', SIZE_XSMALL)
dp('size', 'small', SIZE_SMALL)
dp('size', 'medium', SIZE_MEDIUM)
export default font as Font
개체에 직접 새 속성을 정의하거나 개체의 기존 속성을 수정한 후 개체를 반환합니다.
참고: 이 메서드는 Object 유형의 인스턴스가 아닌 Object 생성자에서 직접 호출합니다.
const object1 = {};
Object.defineProperty(object1, 'property1', {
value: 42,
writable: false, //If its false can't modify value using equal symbol
enumerable: false, // If its false can't able to get value in Object.keys and for in loop
configurable: false //if its false, can't able to modify value using defineproperty while writable in false
});
속성 정의에 대한 간단한 설명입니다.
코드 예제: https://jsfiddle.net/manoj_antony32/pu5n61fs/
Object.defineProperty(Array.prototype, "last", {
get: function() {
if (this[this.length -1] == undefined) { return [] }
else { return this[this.length -1] }
}
});
console.log([1,2,3,4].last) //returns 4
언급URL : https://stackoverflow.com/questions/18524652/how-to-use-javascript-object-defineproperty
'source' 카테고리의 다른 글
Angular에서 .subscribe는 무엇입니까? (0) | 2023.08.19 |
---|---|
Logcat에서 안무가 메시지의 의미 (0) | 2023.08.19 |
Android:Enum을 번들에 넣는 방법? (0) | 2023.08.19 |
도커 파일 이름 지정 방법 (0) | 2023.08.19 |
Python 하위 프로세스."OSError: [Errno 12] 메모리를 할당할 수 없습니다"를 엽니다. (0) | 2023.08.19 |