Существует ли "небезопасная публикация" в Javascript?
Я только что написал следующий код Javascript...
class Team {
constructor(id, eventHandler) {
this.id = id;
this._eventHandler = eventHandler;
this._eventHandler.trigger("NewTeam", this); // my concerning line
}
}
У меня есть опыт Java. В Java считается опасным для объекта делиться ссылкой на себя из своего конструктора ("небезопасная публикация"). Это связано с тем, что другие потоки могут работать с объектом до того, как он окажется в допустимом состоянии.
Это также рискованно в Javascript? Это считается плохой практикой?
Я могу думать только об одной проблеме: если мы хотим расширить Team
тогда было бы сложно сделать дополнительные свойства видимыми для eventHandler.trigger("NewTeam",__)
,
1 ответ
Поскольку Javascript является однопоточным (за исключением webWorkers, которые здесь не используются), проблема, о которой вы упоминаете для Java, здесь не касается Javascript. Никакой другой код не будет запущен одновременно с конструктором. Это одно из самых больших упрощений однопоточной и управляемой событиями природы Javascript.
Если вы синхронно инициируете событие или делаете вызов функции и передаете незавершенный объект этому обработчику события или вызову функции, то вы, конечно, напрашиваетесь на неприятности, потому что вы будете передавать ссылку на незавершенный объект в другой код, который будет выполняться раньше Вы заканчиваете свой конструктор.
Пока объект, который вы передаете, находится в действительном состоянии, когда вы передаете его, это не проблема, но если вы пропустили незавершенный объект, то вы действительно напрашиваетесь на неприятности, но на самом деле это просто программирование на основе здравого смысла, ничего делать с потоками или параллелизмом.
В вашем конкретном случае:
class Team {
constructor(id, eventHandler) {
this.id = id;
this._eventHandler = eventHandler;
this._eventHandler.trigger("NewTeam", this); // my concerning line
}
}
Вы создали уязвимость. Если Team
находится в подклассе, тогда вы позвоните this._eventHandler.trigger("NewTeam", this);
и передать его this
до того, как подкласс обязательно закончил свой конструктор. В зависимости от конкретной реализации это может быть проблемой, так что практика не всегда безопасна. Если .trigger()
можно вызвать на следующем тике (используя что-то вроде setImmediate()
или же nextTick()
, тогда это всегда будет безопасно, потому что объект и любые подклассы всегда будут создаваться до его вызова.