Javascript 클래스 인스턴스를 일반 개체 보존 메서드로 변환
메서드 및/또는 상속된 속성을 잃지 않고 인스턴스 클래스를 일반 개체로 변환합니다.예를 들어 다음과 같습니다.
class Human {
height: number;
weight: number;
constructor() {
this.height = 180;
this.weight = 180;
}
getWeight() { return this.weight; }
// I want this function to convert the child instance
// accordingly
toJSON() {
// ???
return {};
}
}
class Person extends Human {
public name: string;
constructor() {
super();
this.name = 'Doe';
}
public getName() {
return this.name;
}
}
class PersonWorker extends Person {
constructor() {
super();
}
public report() {
console.log('I am Working');
}
public test() {
console.log('something');
}
}
let p = new PersonWorker;
let jsoned = p.toJSON();
jsoned
다음과 같이 표시됩니다.
{
// from Human class
height: 180,
weight: 180,
// when called should return this object's value of weight property
getWeight: function() {return this.weight},
// from Person class
name: 'Doe'
getName(): function() {return this.name},
// and from PersonWorker class
report: function() { console.log('I am Working'); },
test: function() { console.log('something'); }
}
이를 달성하는 것이 가능하며, 가능하다면 어떻게 달성할 것인가요?
궁금하실 경우를 대비해서 TypeScript와 클래스 상속을 사용하려고 하는데 안타깝게도 개체 입력으로만 허용되는 프레임워크를 사용하고 있기 때문에 이것이 필요합니다.
또한 위의 변환을 한 번 하고 있기 때문에 성능은 고려할 문제가 아닙니다.
컴파일러의 대상 옵션이 다음과 같이 설정되어 있으면 객체 속성을 통해 반복되는 솔루션이 작동하지 않습니다.es6
온es5
객체 속성을 통해 반복하여 기존 구현(사용)Object.keys(instance)
) 작동합니다.
지금까지 저는 다음과 같은 구현을 했습니다.
toJSON(proto?: any) {
// ???
let jsoned: any = {};
let toConvert = <any>proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(this);
return;
}
jsoned[prop] = val;
const proto = Object.getPrototypeOf(toConvert);
if (proto !== null) {
Object.keys(this.toJSON(proto)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON') return;
if (typeof proto[key] === 'function') {
jsoned[key] = proto[key].bind(this);
return;
}
jsoned[key] = proto[key];
});
}
});
return jsoned;
}
하지만 이것은 여전히 작동하지 않습니다.결과 개체는 모든 클래스의 모든 속성만 포함하고 다음의 메서드만 포함합니다.PersonWorker
내가 여기서 뭘 놓쳤지요?
이미 많은 답이 있지만, 이것은 확산 구문을 사용하고 객체의 구조를 해제함으로써 가장 간단합니다.
const {...object} = classInstance
이것이 저에게 효과가 있는 것입니다.
업데이트된 응답(재귀 포함)
const keys = x => Object.getOwnPropertyNames(x).concat(Object.getOwnPropertyNames(x?.__proto__))
const isObject = v => Object.prototype.toString.call(v) === '[object Object]'
const classToObject = clss => keys(clss ?? {}).reduce((object, key) => {
const [val, arr, obj] = [clss[key], Array.isArray(clss[key]), isObject(clss[key])]
object[key] = arr ? val.map(classToObject) : obj ? classToObject(val) : val
return object
}, {})
var classs = new Response()
var obj = classToObject(classs)
console.log({ obj, classs })
원답
const classToObject = theClass => {
const originalClass = theClass || {}
const keys = Object.getOwnPropertyNames(Object.getPrototypeOf(originalClass))
return keys.reduce((classAsObj, key) => {
classAsObj[key] = originalClass[key]
return classAsObj
}, {})
}
좋아요, 그래서 제 작전의 실행은 잘못되었고, 실수는 단순히 어리석었습니다.
사용 시 올바른 구현es6
다음과 같습니다.
toJSON(proto) {
let jsoned = {};
let toConvert = proto || this;
Object.getOwnPropertyNames(toConvert).forEach((prop) => {
const val = toConvert[prop];
// don't include those
if (prop === 'toJSON' || prop === 'constructor') {
return;
}
if (typeof val === 'function') {
jsoned[prop] = val.bind(jsoned);
return;
}
jsoned[prop] = val;
});
const inherited = Object.getPrototypeOf(toConvert);
if (inherited !== null) {
Object.keys(this.toJSON(inherited)).forEach(key => {
if (!!jsoned[key] || key === 'constructor' || key === 'toJSON')
return;
if (typeof inherited[key] === 'function') {
jsoned[key] = inherited[key].bind(jsoned);
return;
}
jsoned[key] = inherited[key];
});
}
return jsoned;
}
다음은 toJSON() 메서드에 대한 구현입니다.현재 인스턴스에서 새 개체로 속성과 메서드를 복사하고 원하지 않는 메서드, 즉 JSON 및 생성자는 제외합니다.
toJSON() {
var jsonedObject = {};
for (var x in this) {
if (x === "toJSON" || x === "constructor") {
continue;
}
jsonedObject[x] = this[x];
}
return jsonedObject;
}
Chrome에서 JSON()으로 반송된 객체를 테스트해보니 객체가 예상과 동일하게 작동하는 것으로 보입니다.
저는 알렉스 코리의 해결책에 대해 많이 검토하고 있지만, 이것이 제가 생각해 낸 것입니다.클래스에 해당 바인딩이 있는 함수로 할당되어야 합니다.this
.
const toObject = function() {
const original = this || {};
const keys = Object.keys(this);
return keys.reduce((classAsObj, key) => {
if (typeof original[key] === 'object' && original[key].hasOwnProperty('toObject') )
classAsObj[key] = original[key].toObject();
else if (typeof original[key] === 'object' && original[key].hasOwnProperty('length')) {
classAsObj[key] = [];
for (var i = 0; i < original[key].length; i++) {
if (typeof original[key][i] === 'object' && original[key][i].hasOwnProperty('toObject')) {
classAsObj[key].push(original[key][i].toObject());
} else {
classAsObj[key].push(original[key][i]);
}
}
}
else if (typeof original[key] === 'function') { } //do nothing
else
classAsObj[key] = original[key];
return classAsObj;
}, {})
}
그런 다음 TypeScript를 사용하는 경우 객체로 변환해야 하는 모든 클래스에 이 인터페이스를 배치할 수 있습니다.
export interface ToObject {
toObject: Function;
}
그리고 나서 수업에서, 묶는 것을 잊지 마세요.this
class TestClass implements ToObject {
toObject = toObject.bind(this);
}
이 솔루션은 메서드를 잃게 되지만 클래스 인스턴스를 개체로 변환하는 매우 간단한 솔루션입니다.
obj = JSON.parse(JSON.stringify(classInstance))
Lodash 사용
이 메서드는 재귀적이지 않습니다.
toPlainObject() {
return _.pickBy(this, item => {
return (
!item ||
_.isString(item) ||
_.isArray(item) ||
_.isNumber(item) ||
_.isPlainObject(item)
);
});
}
언급URL : https://stackoverflow.com/questions/34699529/convert-javascript-class-instance-to-plain-object-preserving-methods
'source' 카테고리의 다른 글
MongoDB 잘못된 문서: 개체를 인코딩할 수 없습니다. (0) | 2023.07.06 |
---|---|
PL/SQL에 대한 단위 테스트 (0) | 2023.07.06 |
Java에서 Oracle 함수 호출 (0) | 2023.07.06 |
Savefig 출력 빈 이미지 (0) | 2023.07.06 |
SQL 서버에서 저장 프로시저의 예약된 실행 (0) | 2023.07.06 |