In my main template file i have this
var Product = function(){
this.is_active = true,
this.is_bom_enabled = false;
};
Now later i need to modify the Product, mainly i need to add more properties.
I tried
Product.someOtherThing = value; // only work for `Product` and not for new instances
after all
var SONY = new Product();
SONY.is_active; // true;
SONY.someOtherThing; //undefined
How can i change properties of Product later ?
Product is being used as a constructor function. When you use a function as a constructor function (via the new operator), it does this:
new creates a new, blank object, and assigns FunctionName.prototype as the object's prototype.
new calls your constructor function with this referring to that new object.
(In the normal case.) The result of the new expression is a reference to that new object.
So what your code is doing in the Product function is assigning properties to the object created via new. If you want to add to that object, you simply add to it:
var p = new Product();
p.someOtherThing = "some value";
If you want to create properties on the prototype, you assign those to the Product.prototype object.
Product.prototype.someCommonProperty = "some value";
When you refer to a property on an object, the JavaScript engine first looks at the object itself to see if it has the property. If it doesn't, the engine looks at the object's prototype to see if it has the property (and then the prototype's prototype, etc.). So adding properties to the prototype makes them available via the instances that use that prototype.
So let's look at your Product:
var Product = function(){
this.is_active = true,
this.is_bom_enabled = false;
};
var p = new Product();
The object that p refers to has it's own properties is_active and is_bom_enabled. They don't come from its prototype. If we do this:
Product.prototype.someCommonProperty = "some value";
...then if you do p.someCommonProperty, the engine first looks to see if p has its own property someCommonProperty and, since it doesn't, the engine looks to the prototype. Since the prototype has it, it gets the value from there.
Note that use of properties from prototypes is assymmetrical: Getting a property value from an object will use the prototype's version, but setting a property value will always set it on the actual object. So:
console.log(p.someCommonProperty); // "some value" -- from the prototype
p.someCommonProperty = "foo"; // Adds the property to `p`, doesn't change the prototype
console.log(p.someCommonProperty); // "foo" -- from `p`, not the prototype
var Product = function(){
this.is_active = true,
this.is_bom_enabled = false;
};
Product.prototype.someOtherThing = value;
var SONY = new Product();
SONY.is_active; // true;
SONY.someOtherThing; //value
Related
Situation:
I have multiple JS-Objects with the same structure.
In all of those Objects there's a property called console.
I'd like to assign a value (the same value) to each of these properties.
Please find below the structure of my code:
NameOfMyObject = function() {
return {
actions: null,
console: null,
init: function() {},
//object specific functions
}
};
My Problem:
Currently I'm assigning the value manual, but I want do do it generic.
Code snippet
this.console = console;
this.actions.console = console;
this.fixtures.console = console;
How can I access the properties of my objects?
I hope I asked my question clear enough.
Here is how you would share a property across objects:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
Object.getPrototypeOf(obj1).console.id = 13; // Assign a value once...
console.log(obj1.console.id); // ... and it exists on both instances
console.log(obj2.console.id);
The shared property is on the prototype object.
Instead of Object.getPrototypeOf(obj1) you can of course use MyClass.prototype, since you know that obj1 was created by MyClass. They give the same prototype object.
If your property always has an object as value and you don't need to replace that value, only mutate it by setting properties on that object, then you don't need to explicitly reference the prototype to set a new value.
So this works:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
obj1.console.id = 13; // Assign a value once... (getting console from the prototype)
console.log(obj1.console.id); // ... and it exists on both instances
console.log(obj2.console.id);
But if you change console itself, you'll be setting it on the instance, not on the prototype:
function MyClass() {};
MyClass.prototype.console = {}; // Define a "common" property on the prototype
var obj1 = new MyClass(); // Create two instances
var obj2 = new MyClass();
obj1.console = { id: 13}; // Setting an instance property now
console.log(obj1.console.id); // ... and it does not exist on both instances
console.log(obj2.console.id); // == undefined
So if that kind of assignment should still work on the prototype, you need to use the first code block with Object.getPrototypeOf or MyClass.prototype.
please help solve the problem.
i make 3 objects:
level:
var Level = function() {
self = this;
this.cellsObserver = new CellsObserver();
console.log('co from level ' + this.cellsObserver);
this.fieldObj = new Field();
}
field:
var Field = function() {
self = this;
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
observer:
var CellsObserver = function(){
.............
}
in result console output follow:
co from level [object Object] co from field undefined
I do not understand why in the second case output 'undefined'. because I have appointed a parent:
Field.prototype = Object.create(Level.prototype);
tl;dr: there is no field cellsObserver neither in Field or Level.prototype object. And there is no such thing as a classical 'self' in Javascript.
The long story.
When you're trying to fetch object.property, the Javascript will look at the object trying to find property, then to the object.prototype (which is another object) and so on until it get to the null prototype in the Object.prototype reference.
So, when you're calling second time the this.cellsObserver in Level constructor function, it goes like this:
this is a just new constructed object (if it called with the new keyword), and there is cellsObserver in the property list, so it'll be fetched without any deep lookup.
Then,
Field.prototype = Object.create(Level.prototype);
This only means that Field.prototype now will refer to a new object, which properties are the same as in Level.prototype in that moment.
From your code, there are no non-standard properties in Level.prototype object (you didn't provide any).
Then,
self = this;
Here you just assigning a global variable called self a reference to the just created object or window object (it depends). If you wish to store a reference to the this object, you should var: var self = this. But you should remember that this self variable could be accessed only in the scope where is was declared or in a closure.
Then,
Field.prototype = {
init: function() {
console.log('co from field ' + self.cellsObserver);
}
}
First of all, here you just override the previos instruction (Field.prototype = Object.create(Level.prototype);). If you want to extend the Field.prototype object, you could do in the Object.create call in second argument, or just by accessing a property like that: Field.prototype.init = function(){...}.
Second. The self variable could contain anything when the init function will be executed. Just use this for the current object here.
Third. Let's try to guess what will happen when this.cellsObserver get evaluated inside this init function.
The this object is referring to the Field instance, and there is no cellsObserver property there, so we move to the Field.prototype object, which is defined above ({ init: function () {...}}), there is no cellsObserver either, so we move to the Object.prototype object, which is null. Ok, our lookup is failed, this.cellsObserver is undefined.
What would be it look like if the Field.prototype = Object.create(Level.prototype) wasn't been overridden by the following code? The this object will refer to the Field instance as early. The Field.prototype is referring to the object which is copy of the Level.prototype object, and there is no cellsObserver here either. So, we look to the Object.prototype, and that's it. There is no cellsObserver in any objects except in the instances on Level class, which isn't referenced in any way in the Field instances.
You can play with that here: http://www.objectplayground.com/ by pasting this code:
var Level = function() {
this.cellsObserver = new CellsObserver();
this.fieldObj = new Field();
}
var Field = function() {
this.init();
};
Field.prototype = Object.create(Level.prototype);
Field.prototype.init = function() {};
this.field = new Field();
You are overriding the Field.prototype. Just assign to Field.prototype.init.
According to http://js4py.readthedocs.org/en/latest/object-tree.html,
All JavaScript objects are part of an inheritance tree. Each object in
the tree has a parent object, which is also called the prototype
object (of the child).
I was playing around to make sure I understand it correctly. Shouldn't the following print "lakdas" since myOtherObj inherits the field x from its parent myObj? Why does it instead log undefined?
var myObj = { x:"lakdas" };
var myOtherObj = { y:"lkjaas" };
myOtherObj.prototype = myObj;
console.log(myOtherObj.x); /* Should print "lakdas", right? */
You can't change an object's prototype by assigning to a prototype property. In many engines you can't change the prototype at all after the object is created. You can set the prototype at object creation time:
var myObj = { x:"lakdas" };
var myOtherObj = Object.create(myObj); // sets prototype
myOtherObj.y = "lkjaas";
console.log(myOtherObj.x); // prints "lakdas"
Functions have a prototype property - when you use a function as a constructor, the object stored in the function's prototype property becomes the prototype of the constructed object:
var myObj = { x:"lakdas" };
function foo() {
this.y = "lkjaas";
}
foo.prototype = myObj;
var myOtherObj = new foo();
console.log(myOtherObj.x); // prints "lakdas"
My understanding is all objects of the same type will share the same prototype. So change to the prototype will reflect on every objects. But it seems not the case for property of value type. How is this kind of property stored?
function Person() {
}
Person.prototype.name = "John";
var p1 = new Person();
p1.name = "Luke";
var p2 = new Person();
p2.name = "Mary";
console.log(p1.name); // Luke instead of Mary
console.log(p2.name); // Mary
In case I want to implement a object count of the same type. What's the best way to do it? In other OO language, you normally just use a static member to do it.
Prototype property access is asymmetric.
When you get a property - if the object does not have it, it will fetch it from the prototype. This is specified as:
Let proto be the value of the [[Prototype]] internal property of O.
If proto is null, return undefined.
Return the result of calling the [[GetProperty]] internal method of proto with argument P.
When you set a property - you always set it on the object and not the prototype. As specified here.
To illutstrate:
var proto = {x:4};
var child = Object.create(proto); // create object with prototype set to `proto`
child.x; // 4, fetched from prototype
child.x = 10;
child.x; // 10, fetched from child
proto.x; // 4, setting on child did not change the prototype
Object.getPrototypeOf(child).x = 6; // you can get around it, and set on the proto.
You can read more about it, and why it works this way in Steve Yegge's excellent "the universal design pattern".
When you try to retrieve a property, the object is interrogated to see if it has its own defined. If it doesn't, its constructor's prototype is checked. This happens all the way up the prototype chain until a value is found.
prototype chain explanation
Here's an example.
// Person constructor.
var Person = function (name) {
if (name) {
this.name = name;
}
};
// method to print the name in the console
Person.prototype.sayName = function () {
console.log(this.name);
}
// create two people with names
var person1 = new Person('Nicholas');
var person2 = new Person('Greg');
person1.sayName();
person2.sayName();
// =========================================
// This dude has no name.
var person3 = new Person();
person3.sayName();
// Add a name to the prototype.
// This name is available to all Person instances if they
// don't define their own.
Person.prototype.name = 'Dick';
// These two have their own names.
person1.sayName();
person2.sayName();
// This guy doesn't have his own name, so he
// uses the one from the prototype.
person3.sayName();
I was lead to this question because for some reason I was having a problem setting a value on an object variable to false.
I had
var myObject{
checkValid = false,
self.getCheckValid = function(){
return checkValid;
}
self.setCheckValid = function(mode){
checkValid = mode;
}
}
objectVariable = new myObject;
when I ran objectVarible.setCheckValid(true), I would get the true value. But when I ran objectVariable.setCheckValid(false) the whole app would error out (except I'm developing in mobile and couldn't see the actual error returned).
But then I was wondering, if I can't set the mode to false, can I just re-initiate the entire object by calling objectVariable = new myObject; again. This will overwrite the old object with the new object and get me back to the initialized state, which is really what I'm looking for.
Is there a reason not to do this? Or is one method better than the other?
Any reason why I couldn't just set the checkValid to false?
The syntax for creating an object uses : instead of = to create a property. There is also no need to use .self to access the properties. Also when assigning the object to a variable you should use the syntax var myObject = {/**properties**/};
var myObject = {
checkValid:false,
getCheckValid: function(){
return this.checkValid;
},
setCheckValid: function(mode){
this.checkValid = mode;
}
};
Working Example: http://jsfiddle.net/PSYSM/
The accessors you have placed on the object are unnecessary, you have direct access to the checkValid property without the accessors.
var myObject = {
checkValid:false
};
alert(myObject.checkValid);
myObject.checkValid = true;
alert(myObject.checkValid);
Working Example: http://jsfiddle.net/JtfaJ/
Regarding using new with MyObject, this is not possible since you have declared an object literal. Only one instance of this object will exist, therefore you cannot create instances of the object. If you want to create instances you will need to create a object constructor. This can be done as follows:
function MyObject(){
this.checkValid = false;
}
var myObject1 = new MyObject();
myObject1.checkValid = true;
alert(myObject1.checkValid);
var myObject2 = new MyObject();
alert(myObject2.checkValid);
Working Example: http://jsfiddle.net/PzhUV/