source

Javascript 클래스 인스턴스를 일반 개체 보존 메서드로 변환

ittop 2023. 7. 6. 22:35
반응형

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와 클래스 상속을 사용하려고 하는데 안타깝게도 개체 입력으로만 허용되는 프레임워크를 사용하고 있기 때문에 이것이 필요합니다.

또한 위의 변환을 한 번 하고 있기 때문에 성능은 고려할 문제가 아닙니다.

컴파일러의 대상 옵션이 다음과 같이 설정되어 있으면 객체 속성을 통해 반복되는 솔루션이 작동하지 않습니다.es6es5객체 속성을 통해 반복하여 기존 구현(사용)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
  }, {})
}

enter image description here

좋아요, 그래서 제 작전의 실행은 잘못되었고, 실수는 단순히 어리석었습니다.

사용 시 올바른 구현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

반응형