Value Object (VO) is an object that is an attribute of another object without any identity relative to the domain and that can be interchangeable between objects that use the same attribute.
I have a Person and a Person has an Address. I have a Company and a Company has an address. The database may have a PersonAddress table and a CompanyAddress table. However, there is no need to create a PersonAddress object and a CompanyAddress object. A single Address value object can be shared by both the Person and the Company. All the logic related to an Address would be in that one place and can be tested without having a Person or a Company.
A value object is an object that often is used as an attribute of another object. For example, a Name object (value object) might be an attribute of a Person. More examples are Money, Point, Ranges like DateRange, Price/Quantity/Volume/Size Range etc.
A value object has no changing state and has no domain identity, it is not an Entity Object. In other words, their lifecycle is not tracked in permanent storage. For example, an address does not change, a person might change addresses, but the address remains the same. In other words, the person gets a new address.
A car might have the attribute color. Color is a value object. The system does not track colors. The car’s color may change from Red to Blue, but Red never changes into a different color, it will always be Red
Whether or not an object is a value object can depend on the domain.
Identifying that an object is not an Entity Object can simplify a design by making objects that are easily testable and not tied to what is ultimately a database that assigns identity.
Understanding VO can help us see objects where at first we just saw primitive data types: e.g. Person with Zip code value object instead of type string