构造函数、原型及原型链

1,118 阅读3分钟

什么是构造函数?

构造函数本身就是一个函数,与普通函数没有任何区别,不过为了规范一般将其首字母大写。构造函数和普通函数的区别在于,构造函数用于使用new操作符生成实例,普通函数用来调用以实现某种功能。

什么是原型?

每个函数都有一个prototype属性,prototype属性中的constructor属性又指向函数自身。

什么是原型链?

引用高程3的描述:每个构造函数都有一个原型对象,原型对象都包含一个指向构造函数的指针,而实例都包含一个指向原型 对象的内部指针。那么,假如我们让原型对象等于另一个类型的实例,结果会怎么样呢?显然,此时的 原型对象将包含一个指向另一个原型的指针,相应地,另一个原型中也包含着一个指向另一个构造函数 的指针。假如另一个原型又是另一个类型的实例,那么上述关系依然成立,如此层层递进,就构成了实 例与原型的链条。这就是所谓原型链的基本概念。

如果你还没理解构造函数和原型的关系,看完对于上面这段话,很可能更加晕了,所以下面我将用我的理解来描述构造函数和实例之间的关系,以及原型链到底是什么。

function Person(name){
  this.name = name;
};
let xm = new Person('小明');
xm.__proto__ === Person.prototype  // true 
xm.__proto__.constructor === Person  // true
Person.prototype.constructor === Person  // true

Person为构造函数,xm是通过new Person()得到的实例,其对应关系如下图:


而如果我们这里的Person.prototype同时又是另一个foo构造函数的实例呢?Person.prototype可以从foo.prototype继承属性和方法,xm又可以从Person.prototype继承属性和方法,由此得出以下结论:

每个对象都拥有一个原型对象,通过__proto__指针指向上一个原型 ,并从中继承方法和属性,同时原型对象也可能拥有原型,这样一层一层查找,最后指向Object.prototype,接着Object.prototype.__proto__ = null,对象之间的这种关系就是原型链。

那么如上代码的原型链关系图如下:

 

那如果加上Function对象又是什么样的呢?上图:


上图有一个让人疑惑的点就是为什么Function.__proto__ === Function.prototype?

我比较认同的一种观点是:Function作为一个内置对象,是运行前就存在的东西,所以不会存在说Function自己创建自己,而同Function一起被创建的还有Function.prototype和Object.prototype,并通过__proto__将两者联系起来,而为了和其他对象保持一致性,将Function.__proto__指向Function.prototype。

总结:

Object是所有对象的祖先,所有对象都可以通过__proto__找到Ojbect.prototype;

Function是所有函数的祖先,所有函数都可以通过__proto__找到Function.prototype;

每一个实例通过__proto__指向构造函数的原型,而构造函数的原型又通过__proto__指向构造函数的原型的原型,如此一层一层链接的关系,就是原型链。

如果有错误或者不严谨的地方,请给予指正,十分感谢!