Prototype and Inheritance in Javascript

Generally speaking, an object in javascript is a pointer to a prototype and a list of its own properties . JavaScript uses the concept of copy-on-write when creating objects.
Only the constructor has the prototype property , and the prototype chain inheritance is to create a new pointer to the prototype property of the constructor.
The prototype property is special because of the traversal mechanism when reading properties in JavaScript. Essentially it's just an ordinary pointer.
 
Constructors include:
1.Object
2.Function
3.Array
4.Date
5.String
Let's take some examples
 

 

  1. //Each function has a default property prototype, and the constructor of this prototype points to this function by default
  2. //Note that Person.constructor is not equal to Person.prototype.constructor. The Function instance has its own constructor property
  3. functionPerson(name){
  4. this.name = name;
  5. };
  6. Person.prototype.getName =function(){
  7. returnthis.name;
  8. };
  9. var p =newPerson("ZhangSan");
  10. console.log(Person.prototype.constructor===Person);// true
  11. console . log ( p . constructor === Person ); // true , this is because p itself does not contain the constructor property, so Person.prototype.constructor is actually called here

 

 

run it »

Our purpose is to express
1. Indicate that Person inherits from Animal
2. Indicate that p2 is an instance of Person 
Let's modify the point of the prototype property so that Person can get the methods in the prototype property in Animal. That is, Person inherits from Animal (people are beasts)  
 

 

  1. functionPerson(name){
  2. this.name = name;
  3. };
  4. Person.prototype.getName =function(){
  5. returnthis.name;
  6. };
  7. var p1 =newPerson("ZhangSan");
  8. console.log(p.constructor===Person);// true
  9. console.log(Person.prototype.constructor===Person);// true
  10.  
  11. functionAnimal(){}
  12. Person.prototype =newAnimal();//之所以不采用Person.prototype = Animal.prototype,是因为new 还有其他功能,最后总结。
  13. var p2 =newPerson("ZhangSan");
  14. //(p2 -> Person.prototype -> Animal.prototype, 所以p2.constructor其实就是Animal.prototype.constructor)
  15. console.log(p2.constructor===Person);// 输出为false ,但我们的本意是要这里为true的,表明p2是Person的实例。此时目的1达到了,目的2没达到。

运行一下 »

但如果我们这么修正

 

Person.prototype = new Animal();
Person.prototype.constructor = Person; 
这时p2.consturctor是对了,指向的是Person,表示p2是Person类的实例,但是新问题出现了。此时目的2达到了,目的1没达到。
目的1和目的2此时互相矛盾,是因为此时prototype表达了矛盾的两个意思,
1表示父类是谁
2作为自己实例的原型来复制 
因此我们不能直接使用prototype属性来表示父类是谁,而是用getPrototypeOf()方法来知道父类是谁。 
 

 

  1. Person.prototype =newAnimal();
  2. Person.prototype.constructor=Person
  3. var p2 =newPerson("ZhangSan");
  4. p2.constructor//显示 function Person() {}
  5. Object.getPrototypeOf(Person.prototype).constructor//显示 function Animal() {}

 

 
就把这两个概念给分开了 ,其实通过使用 hasOwnProperty()方法,什么时候访问的是实例属性,什么时候访问的是原型属性就一清二楚了

new做了哪些事情?

当代码var p = new Person()执行时,new 做了如下几件事情:

创建一个空白对象

创建一个指向Person.prototype的指针

将这个对象通过this关键字传递到构造函数中并执行构造函数。

具体点来说,在下面这段代码中,

 

  1. Person.prototype.getName =function(){}
如果我们通过

 

 

 

  1. var person =newPerson();
  2.  
  3. 其实类似于
  4.  
  5. var person =newObject();
  6.  
  7. person.getName =Person.prototype.getName;

 

 

因此通过person.getName()调用方法时,this指向的是这个新创建的对象,而不是prototype对象。

 这其实在给现有函数加上新功能的情况下会用到,我们可以这么扩展现有的方法:

 

 

  1. //function myFunc 的写法基本上等于 var myFunc = new Function();
  2.  
  3. function myFunc (){
  4. }
  5.  
  6. myFunc =function(func){
  7.   //可以在这里做点其他事情
  8. returnfunction(){
  9.      //可以在这里做点其他事情
  10. return func.apply(this,arguments);
  11. }
  12. }(myFunc)

 

 

 也可以在Function.prototype方法里直接通过this来访问上面代码的myFunc所指向的对象

 

 

  1. function myFunc (){
  2. }
  3.  
  4. if(!Function.prototype.extend){
  5. Function.prototype.extend =function(){
  6. var func =this;
  7.  
  8. returnfunction(){
  9. func.apply(this,arguments);
  10. }
  11. }
  12. };
  13.  
  14. var myFunc = myFunc.extend();

 

 

总结一下

如果采用Person.prototype  = Animal.prototype来表示Person继承自Animal, instanceof方法也同样会显示p也是Animal的实例,返回为true.

之所以不采用此方法,是因为下面两个原因:

1.new 创建了一个新对象,这样就避免了设置Person.prototype.constructor = Person 的时候也会导致Animal.prototype.constructor的值变为Person,而是动态给这个新创建的对象一个constructor实例属性。这样实例上的属性constructor就覆盖了Animal.prototype.constructor,这样Person.prototype.constructor和Animal.prototype.contructor就分开了。

2.Animal自身的this对象的属性没办法传递给Person

但是像下面这样直接调用构造函数又可能失败,或者产生其他影响。

 

  1. Person.prototype =newAnimal();

 

 为了避免这种情况,所以我们引入了一个中间函数。所以正确的做法应该是

 

 

  1. Person.prototype =(funtion(){
  2.  
  3.   function F(){};
  4.  
  5.   F.prototype =Animal.prototype
  6.  
  7.   returnnew F();
  8.  
  9. })()

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326987628&siteId=291194637