Как я могу проверить, является ли объект в Typescript простым объектом или экземпляром класса? - PullRequest
0 голосов
/ 03 августа 2020

Чтобы быть более точным: мне нужно отделить все примитивные типы + простые объекты от всех экземпляров класса.

let x = {y:5} // is OK

class X {
y = 5;
}
let x = new X(); // is not OK

1 Ответ

2 голосов
/ 03 августа 2020

Не существует надежного способа отличить простые объекты от классов. Лучшее, что вы можете сделать, это проверить, соответствует ли его прототип прототипу простого объекта. Для полноты вы также можете проверить, является ли прототип null, поскольку это допустимый простой объект при создании с помощью Object.create(null)

function isPlainObject(obj) {
  const prototype = Object.getPrototypeOf(obj);
  return  prototype === Object.getPrototypeOf({}) ||
    prototype === null;
}

class X {
  y = 5;
}

let classInstance = new X();
let plainObject = {y: 5};
let noPrototypeObject = Object.create(null);

console.log(isPlainObject(classInstance));     //false
console.log(isPlainObject(plainObject));       //true
console.log(isPlainObject(noPrototypeObject)); //true

Это будет работать до тех пор, пока не будут внесены чрезмерные изменения в прототипы. Если код каким-либо образом вмешивается в них, вы можете получить ложноотрицательные результаты:

function isPlainObject(obj) {
  const prototype = Object.getPrototypeOf(obj);
  return  prototype === Object.getPrototypeOf({}) ||
    prototype === null;
}

let plainObject = {y: 5};
let objectCreatedWithNonDefaultPrototype = Object.create({foo: 1});
let objectWithChangedPrototype = Object.create(plainObject);
Object.setPrototypeOf(objectWithChangedPrototype, {bar: 2}) //change the prototype

console.log(isPlainObject(objectCreatedWithNonDefaultPrototype)); //false
console.log(isPlainObject(objectWithChangedPrototype));           //false

или ложных срабатываний:

function isPlainObject(obj) {
  const prototype = Object.getPrototypeOf(obj);
  return  prototype === Object.getPrototypeOf({}) ||
    prototype === null;
}

class X {
  y = 5;
}

let classInstance = new X();
let classInstanceWithChangedPrototype = new X();
Object.setPrototypeOf(classInstanceWithChangedPrototype, null);

console.log(isPlainObject(classInstance));                     //false
console.log(isPlainObject(classInstanceWithChangedPrototype)); //true

Вы также можете проверить свойство constructor из прототипа. Он может лучше работать для обнаружения obj = Object.create({foo: 1}), где obj будет простым объектом с другим простым объектом в качестве прототипа.

function isPlainObject(obj) {
  const prototype = Object.getPrototypeOf(obj);
  return  prototype === null || prototype.constructor === Object;
}

class X {
  y = 5;
}

let classInstance = new X();
let plainObject = {y: 5};
let noPrototypeObject = Object.create(null);
let objectCreatedWithNonDefaultPrototype = Object.create({foo: 1});
let objectWithChangedPrototype = Object.create(plainObject);
Object.setPrototypeOf(objectWithChangedPrototype, {bar: 2}) //change the prototype

console.log(isPlainObject(classInstance));                        //false
console.log(isPlainObject(plainObject));                          //true
console.log(isPlainObject(noPrototypeObject));                    //true
console.log(isPlainObject(objectCreatedWithNonDefaultPrototype)); //true
console.log(isPlainObject(objectWithChangedPrototype));           //true

Это все еще не пуленепробиваемое, поскольку конструктор все еще можно переопределить. Однако, скорее всего, это будет код, который активно пытается спрятаться. Большинство объектов должно быть обнаружено любым из двух методов.

Чтобы найти все примитивы и простые объекты, вы можете использовать typeof, поскольку он сообщает о типах. Обратите внимание, что typeof null это "object", поэтому требуется дополнительная проверка:

function isPlainObject(obj) {
  const prototype = Object.getPrototypeOf(obj);
  return  prototype === null || prototype.constructor === Object;
}

function isPrimitive(x) {
  return x === null || (typeof x !== "function" && typeof x !== "object")
}

function filter(x) {
  return isPrimitive(x) || isPlainObject(x);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...