举例:
<script>
function Students(){
//这就是一个构造函数
}
//new一个实例对象
var stu=new Students();
</script>
1.构造函数:就是在script标签里面声明的那个函数Students.
2.原型对象:在声明了一个函数之后,浏览器会自动按照一定的规则创建一个对象,这个对象就叫做原型对象。这个原型对象其实是储存在了内存当中.
3.在声明了一个函数Students后,这个构造函数(声明了的函数)中会有一个属性prototype,这个属性指向的就是这个构造函数对应的原型对象;原型对象中有一个属性constructor,这个属性指向的是这个构造函数(声明了的函数)。如图:
4.使用构造函数创建一个新的对象
就是var stu=new Students();
此时,stu就是那个构造函数Students创建出来的实例对象,这个stu对象中是没有prototype属性的,prototype属性只有在构造函数Students中有。但stu有一个__proto__属性,stu调用这个属性可以直接访问到构造函数Students的原型对象(即stu的__proto__属性指向的是构造函数的原型对象)。如图:
结论:
<script type="text/javascript">
function Students () {
}
// 可以使用Students.prototype 直接访问到原型对象
//给Students函数的原型对象中添加一个属性 name并且值是 "张三"
Students.prototype.name = "张三";
Students.prototype.age = 20;
var stu = new Students();
/*
访问stu对象的属性name,虽然在stu对象中我们并没有明确的添加属性name,但是stu的__proto__属性指向的原型中有name属性,所以这个地方可以访问到属性name的值。
注意:这个时候不能通过stu对象删除原型对象中的name属性,只能删除在stu中的属性。
*/
alert(stu.name); // 张三 从Students的原型对象中找到的
var stu1 = new Students();
alert(stu1.name); // 张三 也是从Students的原型对象中找到的
alert(stu.name === stu1.name); // true
stu.name = "李四";
alert(stu.name); //李四 直接在stu中添加了一个新的属性name,然后在stu中就无法再访问到原型中的属性
alert(stu1.name); // 张三 由于stu1中没有name属性,则对stu1来说仍然是访问的原型中的属性。
</script>
(1).从上面的代码中可以看到,创建stu对象虽然使用的是Students构造函数,但是对象创建出来之后,这个stu对象其实已经与Students构造函数没有任何关系了,stu对象的__proto__属性指向的是Students构造函数的原型对象。
(2).如果使用new Students()创建多个对象stu1、stu2、stu3,则多个对象都会同时指向Students构造函数的原型对象。
(3).我们可以手动给这个原型对象添加属性和方法,那么stu1,stu2,stu3…这些对象就会共享这些在原型中添加的属性和方法。
(4).原型链:如果我们访问stu中的一个属性name,如果在stu对象中找到,则直接返回。如果stu对象中没有找到,则直接去stu对象的__proto__属性指向的原型对象中查找,如果查找到则返回。(如果原型中也没有找到,则继续向上找原型的原型)。
(5).如果通过stu对象添加了一个属性name,则stu对象来说就屏蔽了原型中的属性name,在stu中就没有办法访问到原型的属性name了。
(6).通过stu对象只能读取原型中的属性name的值,而不能修改原型中的属性name的值。 stu.name = “李四”; 并不是修改了原型中的值,而是在stu对象中给添加了一个属性name。