breezejs: reject changes to specific property - javascript

Is it possible to reject the changes to a single property of a breeze object without rejecting ALL the changes to that object?
Say I have
// assume manager is an EntityManager containing a number of preexisting entities.
var person = manager.createEntity("Person");
// assume Name and House are valid properties of a Person object
person.Name("Jon Snow");
person.House("Lannister");
But I ONLY want to discard the changes made to the objects House property.
Is this possible, if so, how would I go about doing it?
Note: I would rather not iterate of the originalValues property and just replace them like that. I guess, I'm looking for a more graceful solution like...
person.House.rejectChanges();
where rejectChanges() is called on the property itself or something like that.

For the lack of a better solution I came up with the following code which seems to serve my purposes:
function RevertChangesToProperty(entity, propertyName) {
if (entity.entityAspect.originalValues.hasOwnProperty(propertyName)) {
var origValue = entity.entityAspect.originalValues[propertyName];
entity.setProperty(propertyName, origValue);
delete entity.entityAspect.originalValues[propertyName];
if (Object.getOwnPropertyNames(entity.entityAspect.originalValues).length === 0) {
entity.entityAspect.setUnchanged();
}
}
}

If person.House property has an entityAspect, you can call rejectChanges() on this property's entityAspect. Property has an entityAspect if it is an object, that has other properties. Simple type like string or Int does not have entityAspect, properties of simple type just belong to another object
person.House.entityAspect.rejectChanges()

Related

Can object hold value by itself and return it

Let assume we have object like this:
let person = {name: 'Ken', doSometing: ()=>{}, data:{}}
or this:
let Person = function(name) {
this.name = name;
this.data = {};
this.doSometing = ()=>{};
};
let person = new Person('Ken');
And i was intresting, is there a way to make objects like this, but get name propery when calling object by itself (name can be string, number, object and so on):
console.log(person) //Ken
instead:
console.log(person.name) //Ken
The mechanical problem with this design is that primitives (like strings, numbers, and booleans) cannot have their own properties. You could add a property to the primitive's associated prototype, like String.prototype.doSomething = function() { ... }, which would allow you to do "foo".doSomething(). (This is discouraged, though, since you should not modify objects you don't own.) However, you cannot attach a value to a specific primitive string value, which means you cannot implement data and name how you'd like.
Instead, the best option is likely to use an object with a toString method that will allow you to stringify the object to a string of your desired form. This won't show in console.log form, but it would if you added an empty string to it, like console.log(""+person).
If you want to give nightmares to anyone who maintains your code in the future, you could achieve this by having your object include RegExp.prototype in its prototype chain. I strongly, actively discourage you from doing so, but suppose I'm not legally capable of stopping you, either; whether or not it should be, (ab)using RegExp.prototype in this way is not (yet) a crime in any jurisdiction.

Prototypal inheritance with nested objects

I'm trying to get my head around prototype inheritance in Javascript. I think I got the basic concept, but when I was playing around with this I ran into the following which still has me puzzled.
There is a very similar question and answer here but it doesn't fully answer why this is happening, at least not for me.
I create a new object like this:
var User = {
username: "",
name: {
first: "",
last: ""
}
}
Next I create two "instances" of that object:
var user1 = Object.create(User);
var user2 = Object.create(User);
Now I set the name property like so:
user1.name = { first: "John", last: "Jackson"}
user2.name = { first: "James", last: "Jameson"}
Now I do
alert(user1.name.first) \\ -> John
alert(user2.name.first) \\ -> James
All as expected. So far so good.
However, if I set the name.first property like this:
user1.name.first = "John";
user2.name.first = "James";
and I get
alert(user1.name.first) \\ -> James
alert(user2.name.first) \\ -> James
Clearly now the property is being set on the prototype object User (or rather the contained name object) instead of overriding it in the current object user1. Why does that occur?
Further if I do
user1.name.middle = "Mortimer"
I can now do
alert(User.name.middle) // -> Mortimer
which is not what I would expect. Generally, whenever a property is set on a derived object, that object either already has that property as an ownProperty in which case the value is simply assigned, or the property is newly created as an ownProperty on the derived object, overriding the prototype property. Just like happens when I assign to user1.name.
So why does assigning to an object contained in the prototype object cause such (at least to me) unexpected and counter-intuitive behavior?
The way I understand it, when the assignment is made the first check is to see if user1 has an ownProperty called name, which it doesn't. If this were a read operation the prototype property would now be looked up and User checked to see if it has ownProperty name. But since this is a set operation why walk the prototype chain when usually a missing ownProperty is simply created?
But since this is a set operation why walk the prototype chain when usually a missing ownProperty is simply created?
When you say user1.name.first = "John", the user1.name part has to be resolved before the .first property can be retrieved or set. And in your example the user1.name part only exists on the prototype object, so it is that object whose .first property you are setting.
Similarly, when you say user1.name.middle = "Mortimer", again the user1.name part resolves to the nested object from the prototype, so then you create a .middle property on that object, which is why User.name.middle also returns "Mortimer".
If you said user1.name.first and user1.name could not be resolved (on the current object or in its prototype chain) then you'd have a TypeError: Cannot set property 'first' of undefined. (You can try that concept with your existing code by saying user1.address.street = "something" - you'd get the TypeError, because user1.address doesn't exist on user1 or its prototype chain.)
Since you've already read over similar questions and answers and still seem to be having trouble understanding the behavior, I'll try to make my explanation as clear as possible. Here is where I think you are going wrong (emphasis mine):
Generally, whenever a property is set on a derived object, that object either already has that property as an ownProperty in which case the value is simply assigned, or the property is newly created as an ownProperty on the derived object, overriding the prototype property. Just like happens when I assign to user1.name.
The problem here is that you assume that user.name.first counts as "a property . . . set on a derived object" (an instance of User). However, this is simply not the case. In JavaScript, inheritance of properties is only shallow (a single layer deep). user.name is just an object value shared by reference through the prototype, so modifications to it from one place are reflected everywhere.
Think of user1.name and user2.name like firstReference and secondReference in the following example snippet, and hopefully the behavior will seem a bit clearer to you.
var User = {
username: "",
name: {
first: "",
last: ""
}
}
var firstReference = User.name
var secondReference = User.name
firstReference.name.first = 'First!'
console.log(secondReference.name) //=> 'First!' (logical and expected result)
The Object.create method creates an object using the first parameter as a prototype, and the second, optional, parameter is an additional object of own properties.
I think the problem here is that name is, by definition, in the prototype, and so not an own property.
If you want separate properties, then you should use the second parameter. The prototype is where you store methods and shared properties.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/create
has more details.
The key is that you want both prototype and own properties.

Prototyping the accessors of ALL POSSIBLE sub-properties

This is the code I'm starting with to prototype goal into the Creep class:
Object.defineProperty(
Creep.prototype,"goal",{
set :function(value){
this.memory.goal= value.id;
},
get :function() {
return Game.getObjectById(this.memory.goal);
},
}
)
Now let's suppose I want Creep.goal not to contain a single value, but multiple values instead, and let every single sub-properties of Creep.goal have the foresaid accessors.
(So I can easily store multiple game objects into the creep's memory)
These properties are meant to be added at runtime, so I do not know how many there will be nor their names, thus I can't simply copy-paste this code once for every property I'd like there to be.
How should I proceed in order to define the accessors of all possible properties-to-be of an object ?
----- SOLUTION -----
So I was suggested to use a Proxy for this. It was a completely new concept to me and I've hit a lot of walls, but I got something to work like I wanted !
// Prototyping goal as a proxy
Object.defineProperty(
Creep.prototype,"goal",{
get :function()
{return new Proxy(this.memory.goal, objectInMemory) }
}
)
// Proxy's Handler (my previous accessors)
const objectInMemory= {
set(goal, property, value){
goal[property] = value.id;
return true;
},
get(goal, property){
return Game.getObjectById(goal[property]);
},
}
Not exactly sure what you're aiming for, but if the properties are truly dynamic and have to be evaluated at runtime there are Proxy objects that are supported by Screeps' runtime.
What this does is it allows you to programmatically intercept all of the messages for an object, including accessing properties.

Best practice for a simple object literal: using "that" or the object's name?

Let's say there is a simple object literal which name will never change:
var car = {
wheels : 4,
construct : function() {
var that = this;
setTimeout(function() {
console.log(that.wheels);
console.log(car.wheels);
}, 500);
}
};
My question is: Which way is better? Referencing by the object's name or creating a new variable (which may take some time and memory and probbaly must be done in multiple functions)?
Within the object, you should always refer to the object via this (or a copy of it, e.g. that, if required) to prevent the following breakage:
var car = ...
// do stuff
car = undefined; // or anything else, perhaps by a code hacker in the JS console
// class is now broken
You should treat the variable name that happens to have been given to your object on the outside as unknown to you, and subject to change.
Someone else might call it something else, there might be multiple names, the name might suddenly point at some other object altogether. Such variables are for the benefit of the "owners" of references to the object, and not for the object itself.

Can a javascript object have a property which is a collection of another type of object?

I have decided (whether bravely or foolishly remains to be seen) decided to increase my javascript skills beyond the use of alerts and I've
been looking at using javascript business objects with the hope of creating a useful library of objects that I can then manipulate with JSON or XML
further on down the line.
The basic concepts are straightforward enough but I can't seem to find an example anywhere of how to expose a property of an object that is a collection of
a different type of object.
For instance if I have a "Department" object I would like to have an "Employees" property which is a collection of "Employee" objects.
I'm from a .Net background so I might be coming at this with the completely wrong mindset here but if I am I'd like to learn the right way to approach this.
Is the concept still applicable in javascript, can a property of a javascript object be a collection of another type of object? Does the concept of a collection even exist (I'd like to be able to enumerate through the collection too) or should I be thinking in terms of arrays or something else?
Here is some pseudo code which should illustrate what I'm aiming for:
function Department (Name)
{
this.DepartmentName=Name;
this.Employees = null; // How do I initialise a property to be a collection of Employee objects?
}
function Employee(FirstName, Surname)
{
this.EmployeeName = Firstname + ' ' + Surname;
}
Department.prototype.addEmployee = function (Firstname, Surname)
{
//In here I want to create an Employee object and add it to an
//'Employees' property of the department object
}
There is no real "list of objects of a specific type" in JavaScript. You seem to just want an array, which is a "collection" (basically an object) with numeric keys and values which can be everything (JavaScript is dynamic, so there is no easy way to force a collection to contain only items of one type, but you should never need to anyway):
function Department (Name)
{
this.DepartmentName = Name;
this.Employees = []; // empty array
}
Then in the prototype function, you can:
create a new instance (object) of type Employee
add it to this.Employees
Like:
Department.prototype.addEmployee = function (Firstname, Surname)
{
// adds to the end of the array
this.Employees.push(new Employee(Firstname, Surname));
};
You can access the Employee objects like this.Employees[0], etc.
Don't forget the semicolon at the end of the prototype function. It's a function expression, and it's good practice to terminate function expressions with a semicolon. Function declarations (like for Department and Employee), on the other hand, do not need those. The difference is that the prototype function is used as an expression in the assignment statement.
Moreover, CapitalCase is usually used for constructors (Employee); regular variable names are usually names in camelCase.

Categories