再讲一遍好了(
参考https://blog.csdn.net/cc18868876837/article/details/81211729
https://blog.csdn.net/lc237423551/article/details/80010100
)
Javascript中所有的对象都是Object的实例,并继承Object.prototype的属性和方法,也就是说,Object.prototype是所有对象的爸爸。
首先,我们需要牢记两点:①__proto__
和constructor
属性是对象所独有的;② prototype
属性是函数所独有的。但是由于JS中函数也是一种对象,所以函数也拥有__proto__
和constructor
属性,这点是致使我们产生困惑的很大原因之一。
首先盗个图先:--》
上图很复杂,先拆分一下
第一,这里我们仅留下__proto__属性,它是对象所独有的,可以看到__proto__属性都是由一个对象指向一个对象,即指向它们的原型对象(也可以理解为父对象),那么这个属性的作用是什么呢?它的作用就是当访问一个对象的属性时,如果该对象内部不存在这个属性,那么就会去它的__proto__属性所指向的那个对象(可以理解为父对象)里找,如果父对象也不存在这个属性,则继续往父对象的__proto__属性所指向的那个对象(可以理解为爷爷对象)里找,如果还没找到,则继续往上找….直到原型链顶端null(可以理解为原始人。。。),此时若还没找到,则返回undefined(可以理解为,再往上就已经不是“人”的范畴了,找不到了,到此为止),由以上这种通过__proto__属性来连接对象直到null的一条链即为我们所谓的原型链。
第二,接下来我们看prototype
属性
prototype属性,别忘了一点,就是我们前面提到要牢记的两点中的第二点,它是函数所独有的,它是从一个函数指向一个对象。它的含义是函数的原型对象,也就是这个函数(其实所有函数都可以作为构造函数)所创建的实例的原型对象,由此可知:f1.__proto__ === Foo.prototype,它们两个完全一样。那prototype属性的作用又是什么呢?它的作用就是包含可以由特定类型的所有实例共享的属性和方法,也就是让该函数所实例化的对象们都可以找到公用的属性和方法。
******************************下面的例子来一遍你就更懂了
<!doctype html> <html> <head> <meta charset="utf-8"> <meta name="description" content=""> <meta name="viewport" content="width=device-width, initial-scale=1"> <script> // es5里面的类 //1.最简单的类 // function Person(){ // this.name='张三'; // this.age=20; // } // var p=new Person(); // alert(p.name); //2、构造函数和原型链里面增加方法 // function Person(){ // this.name='张三'; /*属性*/ // this.age=20; // this.run=function(){ // alert(this.name+'在运动'); // } // } // //原型链上面的属性会被多个实例共享 构造函数不会 // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // var p=new Person(); // // alert(p.name); // // p.run(); // p.work(); //3类里面的静态方法 // function Person(){ // this.name='张三'; /*属性*/ // this.age=20; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.getInfo=function(){ // alert('我是静态方法'); // } // //原型链上面的属性会被多个实例共享 构造函数不会 // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // var p=new Person(); // p.work(); // //调用静态方法 // Person.getInfo(); // 4、es5里面的继承 对象冒充实现继承 // function Person(){ // this.name='张三'; /*属性*/ // this.age=20; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // //Web类 继承Person类 原型链+对象冒充的组合继承模式 // function Web(){ // Person.call(this); /*对象冒充实现继承*/ // } // var w=new Web(); // // w.run(); //对象冒充可以继承构造函数里面的属性和方法 // w.work(); //对象冒充可以继承构造函数里面的属性和方法 但是没法继承原型链上面的属性和方法 // 5、es5里面的继承 原型链实现继承 // function Person(){ // this.name='张三'; /*属性*/ // this.age=20; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // //Web类 继承Person类 原型链+对象冒充的组合继承模式 // function Web(){ // } // Web.prototype=new Person(); //原型链实现继承 // var w=new Web(); // //原型链实现继承:可以继承构造函数里面的属性和方法 也可以继承原型链上面的属性和方法 // //w.run(); // w.work(); // 6、 原型链实现继承的 问题? // function Person(name,age){ // this.name=name; /*属性*/ // this.age=age; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // var p=new Person('李四',20); // p.run(); // function Person(name,age){ // this.name=name; /*属性*/ // this.age=age; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // function Web(name,age){ // } // Web.prototype=new Person(); // var w=new Web('赵四',20); //实例化子类的时候没法给父类传参 // w.run(); // // var w1=new Web('王五',22); //7.原型链+对象冒充的组合继承模式 // function Person(name,age){ // this.name=name; /*属性*/ // this.age=age; // this.run=function(){ /*实例方法*/ // alert(this.name+'在运动'); // } // } // Person.prototype.sex="男"; // Person.prototype.work=function(){ // alert(this.name+'在工作'); // } // function Web(name,age){ // Person.call(this,name,age); //对象冒充继承 实例化子类可以给父类传参 // } // Web.prototype=new Person(); // var w=new Web('赵四',20); //实例化子类的时候没法给父类传参 // // w.run(); // w.work(); // // var w1=new Web('王五',22); //8、原型链+对象冒充继承的另一种方式 function Person(name,age){ this.name=name; /*属性*/ this.age=age; this.run=function(){ /*实例方法*/ alert(this.name+'在运动'); } } Person.prototype.sex="男"; Person.prototype.work=function(){ alert(this.name+'在工作'); } function Web(name,age){ Person.call(this,name,age); //对象冒充继承 可以继承构造函数里面的属性和方法、实例化子类可以给父类传参 } Web.prototype=Person.prototype; var w=new Web('赵四',20); //实例化子类的时候没法给父类传参 w.run(); // w.work(); // var w1=new Web('王五',22); </script> </head> <body> </body> </html>
**
跟到写一遍你就懂了