原型和原型链详解
一、JS函数的四种含义:
首先执行一段代码:
function Fun() {};
var fun1= new Fun(); console.log(fun1 instanceof Fun);
//其执行结果为true;说明JavaScript里面确实存在着类与对象(fun1为对象,Fun为类)。
fun1.prototype //undefined;
Fun.prototype //Object{...};
我们可以得到一些结论:
结论一:函数的两个身份一个是函数一个是类,可以利用函数来创建这个函数所对应这个类的对象。
结论二:可以通过看是否拥有prototype属性判断是类还是对象;
再去执行这段代码:我们知道new 的过程有三件事:1.申请空间,2.初始化(js不存在,仅仅申请空间),3.构造方法
function Fun () {
this.mem = 10;
console.log(this);
}
var fun1 = new Fun;
执行结果如下:
可以看到this的内容已经被输出了,则可以的到一下结论:
结论三:任何一个函数,作为类new一下,该函数该类的构造方法就是该函数本身;
结论四:函数其本身就是一个对象(可以从图中看出是Object{...};
还有一个额外的结论:
console.log("Fun.prototype.constructor === Fun", Fun.prototype.constructor === Fun);//结果为true
console.log("fun1.__proto__.constructor === Fun", fun1.__proto__.constructor === Fun);
结论:实例对象有隐含的属性__proto__中的constructor,指向它构造函数(Fun)即函数本身。
最后函数四种含义概括为:函数、对象、类、构造。
二、原型和原型链
(小编在里面说的原型即代码里的prototype,原型链即<prototype>或者__proto__);
执行这段代码:
function Point (row, col) {
this.setRow = function (row) {
this.row = row ? row : 1;
}
this.setCol = function (col) {
this.col = col ? col : 1;
}
this.getRow = function () {
return this.row;
}
this.getCol = function () {
return this.col;
}
this.toString = function () {
return this.row + "," + this.col;
}
this.setRow(row);
this.setCol(col);
}
var point1 = new Point(2, 3);
console.log("point1 : ", point1);
console.log("Point : ", Point);
console.log("point1 instanceof Point : ", point1 instanceof Point);
console.log("point1.__proto__ : ", point1.__proto__);
console.log("Point.prototype : ", Point.prototype);
console.log("point1.__proto__ === Point.prototype : ", point1.__proto__ === Point.prototype);
结果如下:
point1是Point的一个实例对象:其包含一个<protoType>属性,从黑框可以看出,其就是其隐藏的__proto__属性。我们把这个属性称为原型链,而仅仅只有类才拥有绿色框所显示的prototype属性:我们称之为原型。而从图黑框中我们可以看出,原型链应该指向原型而非类本身。原型链说明的是它的类型身份,即例如:A instanceof B 与否。
总结这张图我们可以知道如下结论:
- 对象拥有原型链而类(函数,对象)拥有原型链<prototype>和原型prototype;
- 原型链说明的是这个对象的类型身份(通俗来讲就是它的爸爸是哪个);
- 原型链应该指向的是原型对象而非类本身。
至此,我们可以得到这样一个图:
console.log("Function:", Function);
console.log("Function.prototype === Point.__proto__:", Function.prototype === Point.__proto__);
console.log("Point instanceof Function:", Point instanceof Function);
console.log("Function.prototype === Function.__proto__:", Function.prototype === Function.__proto__);
console.log("Function instanceof Function:", Function instanceof Function);
再去执行这段代码:执行结果为:
- Function是系统给的一个类,我们从上面蓝色框看到Point类的原型链指向的是Function的原型对象,也就是说,Function是Point的父类。
- 从绿色框看出,Function的原型链指向的是Function自己的原型对象,也就是说Function的父类就是自己。
- 我们可以看到每个类都有一个原型,我们常说的原型对象应该是它的一个实例级原型实例(原型对象)。它们都有原型链(<property>),应该指向的是统一类型即,此时均指向Object类的原型对象。即但我们看到红色框就是Function的原型对象,黑色框就是它们应该都有的原型对象的原型链。
此时我们得到的关系图如下
接下来,就让我们去探究一下这个<prototype> : Object{...};
console.log("Object:", Object);
console.log("Object.__proto__ === Function.prototype:", Object.__proto__ === Function.prototype);
console.log("Object.prototype.__proto__ === Object.prototype:", Object.prototype.__proto__ === Object.prototype);
console.log("Object.prototype.__proto__:", Object.prototype.__proto__);
console.log("Object instanceof Function:", Object instanceof Function);
console.log("Object instanceof Object:", Object instanceof Object);
console.log("Function instanceof Object:", Function instanceof Object);
从紫色框可以看出Object类的原型链指向Function的原型对象,但是此时我们的Object类的原型对象的原型链指向哪里呢,是否指向自己的原型对象呢? 从蓝色框的可以看出它的原型对象的原型链并不指向自己的的原型。
此时我们才真正知道它并没有指向了,是尽头。
此时我们得到如图:
此时我们终于看清了他们之间的关系,是不是有一些些的神奇呢,当时小编感受是:当我们追溯到根源时,要么什么都没有(Null)要么就是一个圈,进得去出不来。(Function 和Object)。
下面,发现画的太丑了,找了一张更为清晰的图: