I would like to know how this extend function works in Backbone.js. And please help me with internally what exactly it is doing.
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent constructor.
if (protoProps && _.has(protoProps, "constructor")) {
child = protoProps.constructor;
} else {
child = function() {
return parent.apply(this, arguments);
};
}
// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function and add the prototype properties.
child.prototype = _.create(parent.prototype, protoProps);
child.prototype.constructor = child;
// Set a convenience property in case the parent's prototype is needed
// later.
child.__super__ = parent.prototype;
return child;
};
here why the parent is added to child variable?
extend takes two params protoProps and staticProps. protoProps are properties that will be assigned to the Class prototype so that when you create an instance of the object the object will have that property as part of its prototype chain1. staticProps are props that are not available to objects created from the Class (using new), but are accessible from the class itself, for example, by calling CatClass.defaultMeow.
var extend = function(protoProps, staticProps) {
var parent = this;
var child;
In the discussion below parent is the what we will call the Base Class, the class which prototype we want to extend to the child, which here we will call the Extended Class.
// The constructor function for the new subclass is either defined by you
// (the "constructor" property in your `extend` definition), or defaulted
// by us to simply call the parent constructor.
if (protoProps && _.has(protoProps, "constructor")) {
child = protoProps.constructor;
if protoProps is a function, or has a constructor property (this is the property that is invoked (as a method) whenever you call new on a Class).
} else {
child = function() {
return parent.apply(this, arguments);
};
}
If not, the Extended Class will use the parent's constructor (when you call new it will invoke the parent's constructor method).
// Add static properties to the constructor function, if supplied.
_.extend(child, parent, staticProps);
_.extend(target, src1,...,srcN) an UnderscoreJS method does a shallow copy of the source objects' properties to the target object. Here were copying all of the parents (static) properties and all the properties pass in to the staticProp object (if supplied) to the new Extended Class.
// Set the prototype chain to inherit from `parent`, without calling
// `parent`'s constructor function and add the prototype properties.
child.prototype = _.create(parent.prototype, protoProps);
This is probably the most important function of the Backbone.extend routine: this is where the Extended Class "inherits" the base Class' prototype chain. For example, if AnimalClass.prototype.walk is a method in the prototype chain for AnimalClass, _.create(parent.prototype, protoProps) will create a new Class with the the walk method in this new Class prototype chain, as well as all the protoProps passed in. This is, in essence, the _extended prototype chain` and it gets assigned to the Extended Class, as it's prototype.
child.prototype.constructor = child;
This is line is confusing at first since we saw in conditional statement above that the Extended Class was already assigned a constructor. Well, it did, but in the last statement, when we did _.create(...) we overwrote the Extended Class' constructor with the Base Class' constructor! Now we're reassigning it.
// Set a convenience property in case the parent's prototype is needed
// later.
child.__super__ = parent.prototype;
Like the comment says, the Extended Class has access to the Base Class in the ***static property* __super__. It's a convenience property that is accessed from the Extended Class object itself. In our previous example, then, if aCatClass is extended from AnimalClass, then the following is true: CatClass.__super__ === AnimalClass.
return child;
};
Related
I have a simple inheritance issue in JavaScript where a Child class inherits from a Parent class. However, in using Object#create to establish the inheritance, it seems that it must come before instantiation of the Child class:
function Child() {}
function Parent() {}
Parent.prototype.sayhello = function () {
console.log("hello world");
}
// Apparently, this must precede instantiation:
// Child.prototype = Object.create(Parent.prototype); //works, console logs "hello world"
var c = new Child();
// We get a TypeError: c.sayhello is not a function
Child.prototype = Object.create(Parent.prototype);
c.sayhello(); //TypeError: c.sayhello is not a function
My thinking was that even if Child.prototype = Object.create(Parent.prototype); came after the instantiation, we are still setting the Child class's prototype to point to the Parent's prototype, so when sayhello is called, the prototypal chain is searched until the method is found. Why doesn't this work? I must be misunderstanding something fundamental.
When you write new Child(), the returned object is linked (via __proto__) to the current value of Child.prototype.
When you assign a new object to Child.prototype after that, that does not affect the existing instance (which still points to the old prototype object).
When you declare var c = new Child() you are constructing a new Child object. A prototype has not yet been declared for this constructor when the c object is made, so its prototype is undefined and remains undefined. It does not update when you declare prototype properties of the Constructor after the fact. That c object remains frozen with regard to its prototype as it has already been made.
Remember that Javascript is pseudoclassical. Everything is an object, there are no real classes.
I am learning the js prototype, and I am wondering if there are any differences between the following two segment?
Segment1:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
}
Subtype.prototype = new SuperType();
Segment2:
function SuperType(){
this.color=["blue","yellow"];
}
function SubType(){
SuperType.call(this);
}
and if the above two does the same thing, then why some codes bother to do this:
function SubType(){
SuperType.call(this);
}
SubType.prototype=new SuperType();
Yes, there are differences.
In Segment 1, the subclass SubType does not call the constructor of SuperType so it never gets executed. Segment 1 is not a correct general purpose way to inherit from another object.
In Segment 2, the subclass SubType does call the constructor of SuperType so the statement this.color=["blue","yellow"]; gets executed, but the prototype is not set appropriately so any prototype items that SuperType might have had are not inherited. Segment 2 is not a correct general purpose way to inherit from another object.
Segment 1 would work properly if there was no code in the SuperType constructor (not the case in your example). As you show it, because the SuperType() constructor is not called, this.color would only be in the prototype and thus the same array would be shared by all instances which is generally NOT what you want. Calling the constructor properly would give every instance it's own copy of this.color, not a shared copy.
Segment 2 would work properly if nothing was added to the SuperType prototype and there are no constructor arguments for SuperType (happens to be the case in your example, but not a good general practice).
Neither is a good general purpose way of doing things.
Your last option is the proper general purpose way to do things because it both inherits from the prototype AND it executes the constructor of the inherited object.
The most general purpose way also passes any constructor arguments to the inherited object using .apply(this, arguments) like this and initializes its own prototype and sets it's constructor property.
// define base object constructor
function SuperType(){
this.color=["blue","yellow"];
}
// define base object methods on the prototype
SuperType.prototype.foo = function() {};
// ---------------------------------------------------------------------------
// define object that wants to inherit from the SuperType object
function SubType() {
// call base object constructor with all arguments that might have been passed
SuperType.apply(this, arguments);
}
// set prototype for this object to point to base object
// so we inherit any items set on the base object's prototype
SubType.prototype = new SuperType();
// reset constructor to point to this object not to SuperType
SubType.prototype.constructor = SubType;
// define any methods of this object by adding them to the prototype
SubType.prototype.myMethod = function() {};
If you are willing to only support IE9 and above, then you should change this line:
SubType.prototype = new SuperType();
to this:
SubType.prototype = Object.create(SuperType.prototype);
This avoids calling the SuperType() constructor in order to just get an object to use for the prototype. In most cases this really doesn't matter, but in cases where the constructor has side effects outside of just initializing it's own properties, it can matter.
In segment 1 the prototype gets set correctly but the constructor function of SuperType never gets called.
At the start of segment 2 the constructor function of the SuperType gets called but the prototype is not set.
The last example is correct because it sets up the prototype correctly as well as calls the SuperType's constructor function.
function SuperType() {
// Do some stuff.
}
function SubType() {
SuperType.apply(this, arguments);
}
SubType.prototype = new SuperType();
you should not set prototype inheritance with
SubType.prototype=new SuperType ();
because there can be problems.
if you do that like this, the prototype of SubType would also inherit the property color as own property of the SubType prototype, because the constructor is worked through. Every new instance of subType has then a reference to the color property in the prototype and is not an own property of the instance itself, this is finally not what you want because you only want to inherit the prototype. the luck is that after calling the super constructer every instance gets an own color property , but the color property is still also defined in the prototype. there is no need
so to really inherit only the prototype you should use Object.create or do a workaround like this.
function SuperType()
{
if (SuperType.doNotConstruct) return;
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
SuperType.doNotConstruct=true;
SubType.prototype = new SuperType();
SuperType.doNotConstruct=false;
SubType.prototype.constructor=SubType;
second way - better way - because no if Statement in the constructor is needed
function SuperType()
{
this.color=["blue","yellow"];
}
function SubType()
{
SuperType.call (this);
}
var CLASS=function () {}
CLASS.prototype=SuperType.prototype;
SubType.prototype=new CLASS ();
SubType.prototype.constructor=SubType;
#blake try the following - this will show a problem when people forget to call the super constructor and do inheritation with ...prototype=new constructor
function SuperType()
{
this.color=["blue","yellow"];
}
SuperType.prototype.addColor=function (name)
{
this.color.push ("red");
}
function SubType () {}
SubType.prototype=new SuperType ();
var a=new SubType ();
var b=new SubType ();
a.addColor ("red");
console.log (a.color);
console.log (b.color);
If I have the following:
function Constructor1(data){
...
...
...};
function Constructor2(data){
Constructor1.prototype.constructor.call(this, data);
...
...
...
}
Constructor2.prototype = new Constructor1();
Then how can I later determine the difference between how they were constructed? I know I can do if (testObject instanceof Constructor2) but if I have a LOT of inherited objects I don't want to do that test for everything. Is there any way to get the string 'Constructor2' returned somehow? (Or whatever the first constructor function called) is?
You can call the parent like this: Parent.call(this,args).
You should not create an instance of Parent to set the prototype part of the inheritance in Child.
If you set the prototype without destroying the prototype.constructor in Child you can use the name property of the constructor function:
function Parent(args){
};
function Child(args){
Parent.call(this,args);
};
console.log(Child.prototype.constructor.name);//=Child
//overwrithing Child.prototype so also Child.prototype.constructor
Child.prototype=Object.create(Parent.prototype);
console.log(Child.prototype.constructor.name);//=Parent, needs to be fixed
Child.prototype.constructor=Child;//fixed
var c = new Child();
console.log(c.constructor.name);//=Child
The name property of Function isn't standard so no guarantee about it's behavior:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name
You may want to check using the function itself: (this.constructor===Parent)
More on constructor functions and prototype here.
I am learning javascript and got puzzled. An example over here which has example as below:-
// define the Person Class
function Person() {}
Person.prototype.walk = function(){
alert ('I am walking!');
};
Person.prototype.sayHello = function(){
alert ('hello');
};
// define the Student class
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
// inherit Person
Student.prototype = new Person(); //<---- Confusion
// correct the constructor pointer because it points to Person
Student.prototype.constructor = Student;
// replace the sayHello method
Student.prototype.sayHello = function(){
alert('hi, I am a student');
}
// add sayGoodBye method
Student.prototype.sayGoodBye = function(){
alert('goodBye');
}
var student1 = new Student();
student1.sayHello();
student1.walk();
student1.sayGoodBye();
// check inheritance
alert(student1 instanceof Person); // true
alert(student1 instanceof Student); // true
Now, I am confused (<----) in these two lines. When I say Person.call(this);, this is simply stating to Inherit properties of Person class... Right?
Then what is this doing?
// inherit Person
Student.prototype = new Person(); //<---- Confusion
As per my knowledge, .prototype also inherits all properties?
To explain it, first let's remember how constructor functions work in JavaScript:
function Guide(a) {
this.a = a;
}
Guide.prototype.q = "Life, the Universe, and Everything";
var g = new Guide(42);
console.log(g.q); // "Life, the Universe, and Everything"
console.log(g.a); // 42
When we do new Guide(42), the new operator creates a new object and assigns it a prototype using the Guide.prototype property. Then new calls Guide, passing in that new object as this. Guide uses this to add properties to the new object that aren't on its prototype. Then the new expression completes and its result is the new object that it created.
When we look at g.q, since the g object doesn't have its own property called q, the JavaScript engine looks at g's prototype, which (again) it got assigned when it was created. That prototype has a q property, and so the engine uses its value.
In contrast, when we look at g.a, the g object has its own property called a, and so the value is used directly.
With that foundation in place, let's look at Student and Parent:
function Student() {
// Call the parent constructor
Person.call(this);// <---- Confusion
}
When we call new Student(), within the call to Student, this is (again) the new object created by the new operator, which has Student.prototype as its underlying prototype. But the Parent function hasn't had a chance to do anything with this new object. So what that line does is give Parent a chance to do whatever it needs to do to new objects that it can't do via the prototype, like our Guide function earlier assigning to this.a. In technical terms, Parent.call(this); calls the Parent function, ensuring that this within the call to Parent is the value passed into call (which is, in this case, the this of the call to Student — e.g., the new object). If you're familiar with class-based languages, this is like doing super(); (that's Java, but you get the idea) in a derived constructor: It gives the base constructor a chance to initialize the object.
// inherit Person
Student.prototype = new Person(); //<---- Confusion
Since Student is supposed to inherit from Person, what that code is doing is creating the prototype that will be assigned to objects created via new Student. The object it's creating is a Person object.
FWIW, that code isn't quite implementing the construction chain correctly (it's calling Person more often than it should [both when creating Student.prototype and when Student is called], and failing to set constructor).
The more correct way to create Student's prototype property, if we're going to call Parent from within Student, looks like this:
function derive(child, parent) {
function ctor() { this.constructor = child; }
ctor.prototype = parent.prototype;
child.prototype = new ctor();
}
derive(Student, Parent);
That way, we get a prototype based on Parent.prototype but without calling Parent. It's an either-or: Either call Parent to create Student.prototype, or call Parent within Student, but don't do both. When building hierarchies with constructor functions, typically you want to call the parent from the child constructor, rather than when creating the child prototype. When using direct object inheritance (without constructor functions), of course you do it the other way.
If you're interested in inheritance in JavaScript, I've written a helper script called Lineage you might want to look at, and in particular even if you don't use Lineage, this discussion on its wiki page may be useful for understanding inheritance hierarchies.
Considering the simplistic scenario:
function Base() {}
function Child() {}
Child.prototype = new Base;
I wonder why would an instance of Child have constructor property set to Base and not to Child?
It's all tied to how inheritance works in JavaScript. Check this link for a detailed explanation (basically, constructor is just another property of the prototype).
Edit: Also, if you want 'real' prototypical inheritance, you have to use some sort of clone function, eg
function clone(obj) {
if(typeof obj !== 'undefined') {
arguments.callee.prototype = Object(obj);
return new arguments.callee;
}
}
Then, you can do things like this
function Base() {}
function Sub() {}
Sub.prototype = clone(Base.prototype);
var obj = new Sub;
and you'll still get true two times on
document.writeln(obj instanceof Sub);
document.writeln(obj instanceof Base);
The difference to your solution is that Base() won't be called and Sub.prototype will only inherit the properties of Base.prototype - and not the ones set in the constructor.
function Base() {}
//Base.prototype.constructor === Base
function Child() {}
//Child.prototype.constructor === Child;
var b = new Base;
//b.constructor = Base;
Child.prototype = b;
//Child.prototype.constructor === Base
basically, any property of the prototype becomes a property of the instance, including "constructor"
when you reassign the whole prototype property to a new object, you're replacing the old constructor property with the new one.
if you don't want this to happen, you have to assign properties to the prototype object one by one, instead of assigning the whole prototype property to a new object at once. Or replace the old constructor property afterward.
Much better idea: don't rely on the constructor property for anything important.