最近在复习原型,感觉有很多要重点对待的,对面向对象的理解很有帮助。遂记。
我的理解:
原型的主要作用:共享数据,节省空间!
一、为什么要用原型?
例如:有一个构造函数 Person :
function Person(name) {
this.name = name;
this.eat= function () {
console.log("eat");
}
}
var per1 = new Person( 'zs' );
对于这个构造函数的实例对象 per1 来说,可以调用方法 eat 。由此看来是没有任何问题。但由于函数也是对象,会在内存中单独开辟一个空间,因此,当实例对象多的时候,就会出现内存空间被很多重复的函数占用。
如:有100个 Person 的实例对象,那么在内存空间里就会有100个eat方法占用的空间,这些方法分别指向不同的实例对象。但是他们的执行结果却都是一样的。这就造成了内存空间的浪费!
为解决这个问题,我们需要一个共享的空间,在里面存放一些公共的方法,属性,这就是原型。
二、什么是原型?
1、对于构造函数Person 来说,他有一个prototype的属性,prototype是一个对象,他叫显式原型。
prototype是给程序员使用的,是标准的属性,且只有函数有这个属性。
在prototype中有默认的几个属性,如constructor构造器等
2、对于一个实例对象per1来说,他有一个__proto__的属性,__proto__是一个对象,他叫隐式原型。
__proto__是给浏览器使用的,不是标准的属性,且IE8不支持。
当我们在构造函数的 prototype 中添加属性或者方法的时候,其实例对象均可以使用这些属性或者方法且不会单独的开辟空间。这就完成了数据的共享!
如代码:
function Person(name) {
this.name = name;
}
Person.prototype.eat = function () {
console.log("eat");
}
var per1 = new Person( 'zs' );
对于实例对象per1来说,他有一个属性name,且有一个方法 eat ,由于eat方法是写在其构造函数的原型里面的,因此他在实例化的时候,不会单独为eat再开一个空间,而是直接使用eat方法。
这样如果有100个实例对象的话,大家使用的都是同一个eat方法,不会单独为eat开辟空间,大大节省了内存空间。
那么,为什么 实例对象per1可以调用写在构造函数(person) 的 prototype 中的 方法或者 属性呢?
因为Person 创建了per1,因此,per1中的 __proto__ 指向了 Person中的prototype,所以prototype中的属性和方法,per1都可以通过__proto__调用。
即使用per1.__proto__.eat();就可以调用了,通常情况下我们省略__proto__不写---> 写 per1.eat() 即可
三、原型中的this指向?
原型中的this指向 为 调用这个方法的实例对象。就是哪个实例对象调用这个方法,this就指向哪个实例对象!
四、原型的指向可以改变吗?
原型是一个构造函数中的一个属性,同时他也是一个对象!对象中存放的是地址,他指向一块内存空间。在这个内存空间中存放着公共的属性和方法。
例如:
1 function Person(name) {
2 this.name = name;
3 }
4
5 Person.prototype.eat = function () {
6 console.log("eat");
7 }
8
9 Person.prototype = {
10 sayHi : function () {
11 console.log("Hello");
12 }
13 }
我们可以看到在代码的第5行时,我们在构造函数的原型中添加了一个方法,而当第9行的时候,我们重新声明一个对象,并把对象给了原型,且新的对象里面有一个方法sayHi。
当我们再次调用eat的时候,会发现无法调用,因为eat 在以前指向的那块内存空间里面,而原型指向已经发生了改变,不再指向之前的那块空间了,现在指向的是有sayHi的那块内存空间。
因此原型的指向是可以改变的。
五、原型链是什么?
在了解原型链之前。我们要知道,任何对象中都有__proto__属性,其指向某个构造函数的prototype对象。
构造函数的prototype属性,也是对象,因此他也有__proto__属性。
而我们知道,实例对象的__proto__指向的是其构造函数的 prototype对象。那么,我们是不是可以推出--->prototype对象因为有__proto__属性,所以,他也是一个实例对象,其__proto__属性的指向为某个构造函数的prototype对象。同样某个构造函数的prototype对象也有__proto__属性,他也有指向的prototype对象,因此就会形成一条原型链!
如图: