Где-то по пути я добавил конструктор в свой класс Todo
:
export class Todo {
id: number;
title: string;
complete: boolean = false;
editMode: boolean = false;
constructor(values: Object = {}) {
Object.assign(this, values);
}
}
Я не понимаю назначение кода в конструкторе.
Мое приложение работает как с ним, так и без него, но я не решаюсь удалить код
Какова цель Object.assign(...) в этом конструкторе?
Это просто объединение двух объектов this
и values
. Согласно МДН
The
Object.assign()
method is used to copy the values of all enumerable own properties from one or more source objects to a target object. It will return the target object.
Он используется для создания мелкой копии объекта и объединения его свойств с this
, который является экземпляром Todo
. В заданном вами коде this
целевой объект. Рассмотрим приведенный ниже пример
let target = {a:1,b:2};
Object.assign(target,{x:"new prop 1",y:"new prop 2"});
console.info(target)
is equivalent to
это может быть эквивалент, но вы не можете сделать это с this
, и это не совсем эквивалент для других объектов
как я уже сказал, вы не можете так присваивать this
, так что это вообще не сработает - но даже при работе с другими объектами это совсем не результат такой же...
@JaromandaX Я получил часть this
. Но все еще не могу понять, почему оба не работают одинаково для другого объекта. Не могли бы вы привести пример?
@MaheerAli вы потеряете неисчислимые свойства
есть еще разница это... (смотрите в консоли)
Я думаю, что точка zerkms, вероятно, более важна @MaheerAli, но вы можете видеть, что есть разница (изначально вы сказали эквивалентно, и это нормально, но если кто-то не знает, что делает Object.assign, то нотация {...x}
, вероятно, запутает их еще больше :р
Это метод простого добавления значений параметров класса в соответствующие поля класса, где класс реализует этот интерфейс или, по крайней мере, имеет частичную имплантацию этого интерфейса.
interface IPerson {
firtName: string;
lastName: string;
}
class Person implements IPerson {
public firtName!: string;
public lastName!: string;
constructor(params: IPerson) {
Object.assign(this, params);
}
}
Ваше приложение работает, потому что вы, кажется, реализовали это таким образом, что значения обратного вызова values
также достаточно.
Основная проблема с этим взломом заключается в том, что Object.assign не является типобезопасным. Таким образом, использование его таким образом противоречит сути TypeScript.
Если вы хотите сделать это безопасным способом, вам лучше использовать пользовательскую реализацию, в которой тип правильно проверяется. Что-то вроде этого:
type PDM = PropertyDescriptorMap;
export class ClassSAssign<T> {
constructor(private objectToSpread: T, private klass: T) {}
private propertyDescriptorOptions = {
enumerable: true,
writable: true
};
public apply(): void {
const map = this.getPropertiesDescriptorMap();
Object.defineProperties(this.klass, map);
}
private getPropertiesDescriptorMap(): PDM {
return Object.entries(this.objectToSpread).reduce(
(obj: PDM, entry) => this.getPropertyDescriptorMap(obj, entry),
{}
);
}
private getPropertyDescriptorMap(obj: PDM, [key, value]: [string, any]): PDM {
return {
...obj,
[key]: {
value,
...this.propertyDescriptorOptions
}
};
}
}
и вы можете использовать эту утилиту следующим образом:
class Person implements IPerson {
public firtName!: string;
public lastName!: string;
constructor(params: IPerson) {
new ClassSAssign(params, this).apply();
}
}
Если вы не хотите/не хотите использовать вышеизложенное, я предлагаю вам, по крайней мере, добавить некоторую строгость типов, чтобы защитить ваш класс от того, какие значения могут быть переданы в него.
interface IToDo {
id?: number;
title?: string;
}
export class Todo implements IToDo {
public id?: number;
public title?: string;
public complete: boolean = false;
public editMode: boolean = false;
constructor(values?: IToDo) {
Object.assign(this, values);
}
}
Object.assign
присваивает все свойства второго аргумента первому аргументу.
Что делает код, так это то, что если вы передаете объект в конструктор, он присваивает эти свойства создаваемому объекту. Так, например:
const todo = new Todo({ id: 1, title: 'hello' });
console.info(todo.title); // 'hello'
Редактировать:
Поскольку Object.assign
не является типобезопасным, вам, вероятно, следует заставить конструктор принимать что-то более конкретное, чем просто Object
. Я бы предложил создать для него интерфейс.
Object.assign
не имеет проверки типов. Альтернативой может быть:
const assign = <T, K extends keyof T>(...args: T[]): T =>
args.reduce( (result, current) =>
(Object.keys(current) as K[]).reduce((target, key) => {
target[key] = current[key];
return target;
}, result)
, args[0])
;
Обратите внимание, что если свойства T не являются необязательными, каждый переданный объект должен включать каждое свойство. Если вы можете гарантировать наличие каждого свойства после возврата функции, вы можете передать аргументы как Partial<T>
, а затем принудить результат, когда закончите.
Можно утверждать, что, поскольку Object.keys
также не имеет проверки типов, вы действительно не приблизились к нирване типов. Вы только что добавили некоторый код, чтобы лучше скрыть приведение, и добавили ограничения, которые могут не соответствовать проблемам, для решения которых часто используется Object.assign
.
Не уверен, почему ответ был удален, единственная неверная часть ответа была очевидным «эквивалентным» кодом.