Javavscript change sub-class property on instantiation - javascript

if I have
myClass.prototype.subClass=
{
foo:false
}
when I create a new instance on an object how can I set foo to a different value each time, so how do I refer to that sub-class here
var newObj = new myclass();

Objects and arrays are not something which should be added to the prototype unless you want to share them with all instances.
As soon as you want properties of these objects to be different for each instances, you have to assign the object in the constructor (or in any other function) to the specific instance:
this.subClass = {
foo: true
// potentially other properties
};
That said, there might be cases were having a "default" object in the prototype might be reasonable, but you should not write to it.
Assigning the object in the constructor instead does not duplicate code and allows you to change it for each instance individually.
Update:
If you don't want to change the original constructor, you can either just add a new function to the prototype and call it whenever you instantiate an object:
MyClass.prototype.init = function() {
this.subClass = {
//...
};
};
and
var obj = new MyClass();
obj.init();
Or you really create a new constructor function:
function MySubClass() {
MyClass.apply(this, arguments);
// now create that object for each instance
this.subClass = {
foo: someValue
};
}
inherits(MySubClass, MyClass);
where inherits is defined as:
function inherits(Child, Parent) {
var Tmp_ = function() {};
Tmp_.prototype = Parent.prototype;
Child.prototype = new Tmp_();
Child.prototype.constructor = Child;
}
Then you will use MySubClass instead of MyClass to create the instances.

I think you missunderstand how prototype inheritence works because this question is a bit odd. But you should be able to access the foo property like any other:
newObj.subClass.foo = newValue

Related

How to set the constructor of an Object without changing to a new Object?

In this related question, the answer for setting a constructor is like so:
function OldClass() {
alert("old class with incomplete constructor")
}
function ChangedClass(){
alert('new class with same prototype and more complete constructor');
}
ChangedClass.prototype = OldClass.prototype;
var theClassIWant = new ChangedClass();
This is not really setting the constructor, it's making a new object and inheriting the prototype. How can I set the constructor of an Object without changing to a new Object? Is it possible?
P.S. I want something like this:
//non working code
var Foo = function() {}
Foo.prototype.constructor = function(bar_val) {
this.bar = bar_val;
}
var fez = new Foo("cat")
console.log(fez.bar); // outputs: cat;
constructor is a property of the constructor function's prototype, which points to the function itself by default.
When you modify Foo.prototype.constructor, this property points to another function. However, the constructor function Foo remains. So when you create an object, you are still instantiate the constructor function Foo, not the one Foo.prototype.constructor points to.
This is why your code doesn't work. Then let's talk why we need to change the constructor and how to.
In ES5 and before, we take advantage of prototype to simulate a class inheritance mechanism. Which looks like this:
// parent class
function Person(name) {
this.name = name
}
// define parent method
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent properties
this.job = 'Coding'
this.major = major
}
// inherits properties and methods from parent prototype
Coder.prototype = new Person()
// define child method
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
// instantiate a child object
var me = new Coder('Leo', 'JavaScript')
console.log(me) // {name: "Leo", job: "Coding", major: "JavaScript"}
Everything looks perfect, but there a problem:
console.log(me.constructor) // Person
What? Isn't me constructed with Coder? Why?
Go back to the first line of this answer, read it again: constructor is a property of the constructor function's prototype.
Originally Coder.prototype.constructor is Coder itself. But with this line: Coder.prototype = new Person(), it got changed. Coder.prototype.constructor now equals Person.prototype.constructor, which is Person.
Well, some would say, try instanceof. Yes, that works:
me instanceof Coder // true
But it's also true for Person, because Coder is a sub class of it:
me instanceof Person // true
This doesn't make sense so we need to fix the constructor problem. That's why we use Coder.prototype.constructor = Coder after Coder.prototype = new Person(), to get back the original constructor.
Full code looks like this:
// parent class
function Person(name) {
this.name = name
}
Person.prototype.say = function() {
console.log(this.name)
}
// child class
function Coder(name, major) {
Person.call(this, name) // inherits parent class
this.job = 'Coding'
this.major = major
}
Coder.prototype = new Person() // inherits parent's prototype
Coder.prototype.constructor = Coder // get back constructor
Coder.prototype.work = function() {
console.log('I write ' + this.major)
}
myClass = {
constructor: function(text){
console.log(text);
}
}
let ob = Object.create(myClass);
ob.constructor("old constructor "); //Output: old constructor
myClass.constructor = function(){
console.log("new constructor ")
}
ob.constructor(); //Output: new constructor
You can do this with every property or function of a class.
Watch this Video here. It explains it perfectly.

Inheritance of variable doesn't work

If I use prototypical inheritance in Javascript, the methods are available in subclasses but the members from parent are shared. Why is this?
For e.g., I am extending 2 data structure classes from my store.
function Store() {
this._store = [];
this._index = -1;
}
Store.prototype.addData = function (val) {
this._index++;
this._store[this._index] = val;
};
Store.prototype.toString = function() {
return "Store: [" + this._store + "]";
};
// inherits from Store
function DS1() {
}
DS1.prototype = new Store();
DS1.prototype.constructor = DS1;
Now if I use 2 instances of DS1, they are using the same store data. Why is that?
var ds1 = new DS1();
ds1.addData(2);
console.log(ds1.toString()); // Prints 2
var ds2 = new DS1();
ds2.addData(3);
console.log(ds2.toString()); // Prints 3
console.log(ds1.toString()); // Prints 3 and NOT 2.
This is one reason why use of new is discouraged for use with prototype. The problem is that a new unique _data array is created only when your Store constructor runs. Your Store constructor only runs one time, ever, in DS1.prototype = new Store(); This means that allnew DS1() instances share the same _data array.
Here's an relevant example adapted from a different answer of mine. Suppose each Store has a pseudo-unique, random id property:
var Store = function() {
// each Store instance has a random id
this.id = Math.random();
}
Store.prototype.addData = function() { /* ... */ }
Then, you want DS1 to inherit from Store:
var DS1 = function() {
this.something = 5;
}
DS1.prototype = new Store(); // this is bad
var ds1 = new DS1();
console.log(ds1.id);
var ds2 = new DS1();
console.log(ds2.id); // same as ds1!
Bad news -- DS1 instances all share the same id now! DS1.prototype.id is set once, ever, on the line DS1.prototype = new Store();, and that's where all DS1 instances get their id from.
Instead, you want to run the Store constructor code each time you run the DS1 constructor code, instead of just once when your set up the DS1 prototype:
var DS1 = function() {
Store.call(this); // set parent constructor properties on `this` new DS1 obj
//...
}
// DS1 prototype inherits from Store prototype, not Store instance
DS1.prototype = Object.create(Store.prototype);
This is because in Javascript object are not copied by value but only by reference.Now, the prototypes of children (here ds1, ds2) and parents point to same object, when a child modifies the prototype, the parents get the changes and so do the siblings. Inheritance in javascript can be achieve by creating empty function F() setting its prototype to prototype of parent constructor as below.
function extend(Child, Parent) {
var F = function () {};
F.prototype = Parent.prototype;
Child.prototype = new F();
Child.prototype.constructor = Child;
Child.uber = Parent.prototype;
}
This way you can inherit by simply using extend(ds1, Store); Inheritance and prototype chain
Add Store.call(this) to your DS1 "class". After that you can start assigning values for your DS1 specific properties inside the constructor.
As it was said in comments, all childs uses the same object as a prototype. That is how prototypical inheritance works.
The prototype object in such kind of inheritance stands as a spare storage of methods and variables for child objects.
When you call/get a var from d1 or d2 it looks if they have addData. They haven't. Then js looks into __prototype. Hey, new Store is there! Does it have a addData? Yes! Calling it...
It's important, that new Store is called once, so a created object stands for all childs of your parent.

defining method with prototype property and without prototype difference

please clarify the difference b/w this two codes
function Person(gender) {
this.gender = gender;
alert('Person instantiated');
}
Person.prototype.sayHello = function()
{
alert ('hello');
};
var person1 = new Person('Male');
var person2 = new Person('Female');
// call the Person sayHello method.
person1.sayHello()
and the second one is below where function define inside funciton (without prototype property)
function Animal(gender) {
this.gender = gender;
alert('animal instantiated');
this.sayToodle = function()
{
alert ('GOOOOOOO!!');
};
}
var Animal1 = new Animal('Male');
var Animal2 = new Animal('Female');
Animal1.sayToodle();
my more simple question are:
what is the difference?
define method inside or out side of a function. what is the effect?
if both same then which is the fine way to define this.
and what does prototype do?
Can we not define method of a obj out side of its function(CLASS)???
Defining a member inside the constructor (such as: this.name) gives only that instance of the object access to that member.
Defining a member inside the prototype allows all instances to "share" that property.
A way that helped me understand this was to define an array (or any other member that is not a method) inside the prototype, like so:
function Animal() {}
Animal.prototype = {
kids: [],
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten','another kitten','yet another kitten');
// cat.kids === ['kitten','another kitten','yet another kitten'];
// giraffe.kids === ['kitten','another kitten','yet another kitten'];
If you notice, the giraffe's kids were set (as kittens). Why is this? Because in this case, .giveBirth() accesses the prototype's kids array, which is shared by all instances.
What if we don't want to share the members, because the members are unique? You can do like so:
function Animal() {
this.kids = [];
}
Animal.prototype = {
giveBirth: function() {
for(var i = 0; i < arguments.length; i++) {
this.kids.push(arguments[0]);
}
}
}
var cat = new Animal();
var giraffe = new Animal();
cat.giveBirth('kitten');
// cat.kids === ['kitten']
// giraffe.kids == undefined
giraffe.giveBirth('baby giraffe');
// cat.kids === ['kitten']
// giraffe.kids === ['baby giraffe']
As you pointed out in the comments, part of how you decide to define the properties plays into memory usage; another part plays into what members you want to be "shared" across all instances.
To get a little more insight into prototypes (through understanding how new works), see What is the 'new' keyword in JavaScript?, on StackOverflow.
Here's a quote from there:
After a lot of searching, I have finally found out exactly what the
new keyword does, and it is 4 things:
It creates a new object. The type of this object, is simply object.
It sets this new object's internal, inaccessible, [[prototype]] property to be the constructor function's external, accessible,
prototype object.
It executes the constructor function, using the newly created object whenever this is mentioned.
It returns the newly created object, unless the constructor function returns a non-primitive value. In this case, that
non-primitive value will be returned.
Prototype members are shared among instances and members in the constructor function defined as this.something are instance specific.
When an instance need instance specific members (like Person.name) define it as this.name. When it can be shared (like a method sayName) define it on the prototype like: Person.prototype.sayName=function(){...
For more info on prototype and constructor functions you can check this answer.

use the JavaScript new keyword with variable length arguments array

I am building a function that allows an object to be extended by any other object
Object.prototype.extend = function(constructor, args) {
var proto = this;
while(proto.__proto__.constructor !== Object) {
proto = proto.__proto__
}
proto.__proto__ = new constructor(args)
console.log(this);
}
the method would be called like this:
function ChildModelConstructor(1,2,3) {
this.extend(ParentModel, arguments)
}
or
instanceOfChildModel.extend(ParentModel, [1,2,3])
the problem is if I call new like this:
new constructor(args)
the constructor of the parent object receives argument which is an arguments object or array.
What I would like is to be able to call
new constructor.apply(args)
or something similar, I am not trying to change the context of this new, apply is the only method of calling a method using an args object or an array that I am aware of.
Thanks for the help :)
Update, I found a better way
Here's a better approach to Inheritance I came up with, it avoids using the depreciated proto
There are several advantages to this method, over other inheritance schemes I've found. The biggest is that it does not merge multiple levels of the proto chain. Many schemes mix the childClass's proto methods with the parent classes instance variables, or worse, all methods and properties from the parents initialization directly into the main body of the childClass.
The drawbacks are, it is single inheritance, and you cannot change the inheritance of a single instance, since the prototype property belongs to the Constructor.
Function.prototype.inherit = function(parentClass) {
var newPrototype = Object.create(Object.create(parentClass.prototype));
for(key in this.prototype){
newPrototype[key] = this.prototype[key];
}
this.prototype = newPrototype;
this.prototype.constructor = this;
this.prototype.parentClass = parentClass;
this.prototype.initParent = function(args) {
var proto = Object.getPrototypeOf(Object.getPrototypeOf(this))
this.parentClass.apply(proto, args);
}
this.prototype.uber = function() {
return Object.getPrototypeOf(Object.getPrototypeOf(this));
}
}
and you can set up the inheritance like this:
function Model(n) {
this.initParent(arguments)
this.test = n*2;
}
Model.inherit(BaseClass);
Here is a slightly more detailed version in JSFiddle http://jsfiddle.net/michaelghayes/2rHgK/​​
This is untested, but I think it will work. Replace:
proto.__proto__ = new constructor(args)
With:
proto.__proto__ = {};
proto.__proto__.prototype = constructor.prototype;
constructor.apply(proto.__proto__, args);
Take note that __proto__ is deprecated.
its better not to attach things to the object prototype and just set up the inheritance manually:
Model function() {
//init parent first because of chromes hidden classes
ParentClass.apply(this, [].slice.call(arguments))
//new instance properties
this.something = 'something'
}
Model.prototype = Object.create(ParentClass.prototype, {
constructor: {value: Model}
})
//Prototype props
Model.prototype.whatever = function(){return 'whatever'}
this also allows you to modify args before initing the parent since your new class shouldn't be restricted to using the exact same args as its parent

When should you use "prototype" during object augmentation in javascript?

I'm confused about the notion of "prototype" in javascript.
When I'm defining an object both of the following seem to work:
myObject = {};
myObject.prototype.method1 = function() { ... };
myObject.prototype.method2 = function() { ... };
myObject.prototype.method3 = function() { ... };
and...
myObject = {};
myObject.method1 = function() { ... };
myObject.method2 = function() { ... };
myObject.method3 = function() { ... };
Could anyone shed some light on this? What exactly is the difference between these two ways of creating an object and why would I choose one over the other? (I have this feeling in my gut it's important...)
Thanks!
You should use the prototype property only on Constructor Functions, not in object instances, for example:
function Test () {}
Test.prototype.method1 = function () {/*...*/};
var obj = new Test();
The prototype property of constructor functions, is used by the new operator, when it creates our new object instance.
All native objects have a hidden link, that builds up the prototype chain.
This hidden link between objects is the [[Prototype]] internal property, and the new operator is the only one that can set it.
In the above example, the obj is associated internally with it's constructor prototype, the method1 is accessible from obj, but it doesn't exists physically on this object, that method exists on the Test.prototype object, and it's retrieved through the prototype chain, e.g.:
typeof obj.method1; // "function"
obj.hasOwnProperty('method1'); // false
obj.method1 === Test.prototype.method1; // true
On object instances, assigning a prototype property is meaningless, it will be taken just as any other property name:
var myObject = {};
myObject.prototype = "foo";
myObject.bar = "bar";
// myObject is simply {"prototype":"foo","bar":"bar"}
Second way adds methods only to this object. First way makes it available for other objects created with new with this "type".

Categories