Typescript: object.hasOwnProperty() показывает true для унаследованного свойства. Зачем?

Если я правильно понимаю, object.hasOwnProperty() должен возвращать false на унаследованных свойствах родительского класса. Однако следующий код возвращает true как для собственных, так и для унаследованных свойств.

Мое понимание / код неверен или hasOwnPropery() неправильно? Если это я, как мне различать собственные и унаследованные свойства?

Изменить: я добавил свой вариант использования в пример кода.

Я бы ожидал ребенка fromDb() будет заботиться только о своих собственных свойствах, вместо этого он переопределяет свойства, установленные родителем fromDb(),

class Parent {
    parentProp = '';
    fromDb(row: {}) {
        for (const key of Object.keys(row)) {
            if (this.hasOwnProperty(key)) {
                if (key === 'parentProp') {
                    // Do some required data cleansing
                    this[key] = row[key].toUpperCase()
                } else {
                    this[key] = row[key];
                }
            }
        };
        return this;
    }
}

class Child extends Parent {
    childProp = '';
    fromDb(row: {}) {
        super.fromDb(row);
        for (const key of Object.keys(row)) {
            if (this.hasOwnProperty(key)) {
                this[key] = row[key];
            }
        };
        return this;
    }
}

let row = {
    parentProp: 'parent',
    childProp: 'child',
}

let childObj = new Child().fromDb(row);
console.log(childObj);

Приставка:

Child:
    childProp: "child"
    parentProp: "parent"

2 ответа

Решение

В сгенерированном extends код, свойства копируются в подкласс следующим образом:

function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };

Что означает, что ваш подкласс (d) предоставляется собственное имущество.

На самом деле это ничем не отличается от использования простого наследования JavaScript:

function Parent() {
    this.parentProp = `I'm defined by Parent`;
}

function Child() {
  Parent.call(this);
  this.childProp = `I'm defined by Child`;
}

let childObj = new Child();

for (const key of Object.keys(childObj)) {
    console.log(key, childObj.hasOwnProperty(key));
}

Если вы дадите нам направление относительно того, чего вам нужно достичь, я уверен, мы найдем подходящий для вас механизм, который преодолеет это препятствие.

Конкретный вариант использования

Для вашего конкретного случая использования вы можете установить прецедент для того, кто "выигрывает", когда вы называете суперкласс.

Чтобы получить выход

childProp: "child"
parentProp: "PARENT"

Пусть родитель запускает "второй", а не "первый":

class Child extends Parent {
    childProp = '';
    fromDb(row: {}) {
        for (const key of Object.keys(row)) {
            if (this.hasOwnProperty(key)) {
                this[key] = row[key];
            }
        };

        super.fromDb(row); // <-- last update wins
        return this;
    }
}

Супер Динамическое Свойство Материал

Это будет динамически исключать родительские ключи из дочерних и дочерние ключи из родительских... добавить console.log заявления, чтобы увидеть внутренности...

class Parent {
    parentProp = '';
    fromDb(row: {}) {

        const ownKeys = Object.keys(new Parent());

        for (const key of Object.keys(row)) {
            if (ownKeys.indexOf(key) > -1) {
                if (key === 'parentProp') {
                    // Do some required data cleansing
                    this[key] = row[key].toUpperCase()
                } else {
                    this[key] = row[key];
                }
            }
        };
        return this;
    }
}

class Child extends Parent {
    childProp = '';
    fromDb(row: {}) {
        super.fromDb(row);

        const ownKeys = this.getKeys();

        for (const key of Object.keys(row)) {
            if (ownKeys.indexOf(key) > -1) {
                this[key] = row[key];
            }
        };
        return this;
    }

    getKeys() {
        const childKeys = Object.keys(this);
        const parentKeys = Object.keys(new Parent());

        return childKeys.filter( function( el ) {
             return parentKeys.indexOf( el ) < 0;
        });
    }
}

let row = {
    parentProp: 'parent',
    childProp: 'child',
}

let childObj = new Child().fromDb(row);
console.log(childObj);

Классы являются просто синтаксическим сахаром для старого доброго синтаксиса функции конструктора. Свойства, определенные в классе, всегда являются свойствами экземпляра, скомпилированными со значениями, установленными в функции конструктора:

function Parent() {
    this.parentProp = "I'm defined by Parent";
}

Свойство не берется из прототипа, это свойство экземпляра, установленное на this в конструкторе. Только методы являются общими для прототипа. Если вы хотите общие свойства, они должны быть объявлены static; но тогда они являются свойством класса, а не прототипом.

Другие вопросы по тегам