引言:JS是一门面向对象的语言,JS中万物皆对象。所以对于原型和原型链的理解需要站在面向对象的视角去看待。
As we all know,对象的创建需要调用与之对应的构造函数。那么,在构造函数内部存在成员方法的前提下,如果使用该构造函数创建多个不同的实例化对象,会造成一个现象:这些对象的方法的代码相同,功能相同,但是互相之间地址不同,也即在每一次生成对象时都会开辟新的空间存放该方法,这会造成资源的浪费。这是构造函数创建对象的一个弊端,为解决这一问题,原型的概念应运而生。
原型
在构造函数中有一个属性,叫做prototype,这是一个对象,而这个prototype中存放的是构造函数定义的成员方法。而该构造函数的实例化的对象中,有一个与之关联的属性,叫__proto__,该属性的值就是与之对应的构造函数中prototype的地址,也即__proto__指向的就是构造函数中的prototype对象。
小结:实例化对象.__proto__===构造函数.prototype
而这就会造成这样的结果:当调用实例化对象的函数时,如果这个函数在该对象有定义,则调用该对象的函数;如果该对象没有定义该函数,则通过访问__proto__属性,寻找其构造函数中prototype对象里是否存在该函数,如果存在则调用该函数。所以,通过在构造函数的prototype对象中定义函数方法,就解决了前面提到的资源浪费的问题。下面通过代码演示:
function Dog(){
}
Dog.prototype.run=function(){
console.log("prototype-run")
}
dog1=new Dog();
dog1.run();//控制台输出:prototype-run
原型链
这里应该先知道,是凡对象,都有前面提到的__proto__属性。那么也就是说,构造函数的prototype这个对象,也有一个__proto__属性。而这个__proto__指向的是构造函数名为Object的prototype,并且这个Object构造函数的prototype对象的__proto__属性为null。这一整个追溯的过程就形成了一个链条,称之为原型链。
小结:实例化对象.__proto__===构造函数.prototype
构造函数.prototype.__proto__===Object.prototype
Object.prototype.__proto__==null