今天要介绍在JavaScript中会看到的「两种原型」,这两种原型都叫做prototype,但他们却有完全不同的意思。
第一种的prototype为「原型关係」,一个物件为是另一个物件的原型,如以下例子:
//宣告一个物件var objA = { name:'A',};//让objB继承他var objB = Object.create(objA,{name:{value:'B'}});//objB的原型为objAObject.getPrototypeOf(objB) === objA; //会回传true//使用isPrototypeOf检查objA.isPrototypeOf(objB); //会回传true
此时objB的内容会是:
他的__photo__属性会有继承而来的特性,但如果我们将这个属性指定成其他物件:
//宣告另一个物件var objC = { name:'C',};//把objB的__proto__指向objCobjB.__proto__ = objC;//再去检查会发现objB的prototype已经由objA变成objC了Object.getPrototypeOf(objB) === objC; //会回传true//使用isPrototypeOf检查objC.isPrototypeOf(objB); //会回传true
此时objB的内容会是如下:
第二种为特性的prototype值,每个建构器都会有一个prototype的特性,他的值是一个物件,而透过这个建构器产生的实体原型都会指向这个建构器的prototype,如以下例子:
//建立一个空functionfunction func(){};//把func当做建构器来创造一个实体物件var obj = new func();//obj这个实体物件的原型会指向建构器的prototype特性Object.getPrototypeOf(obj) === func.prototype; //会回传true//接着使用isPrototypeOf检查func.prototype.isPrototypeOf(obj); //会回传true//然后藉由建构器产生的实体物件会有constructor属性,所以接着来判断obj.constructor == func; //回传trueobj instanceof func; //回传true
来看看obj的内容如何:
他在__proto__中的constructor指向建构器本身,上一篇我们知道constructor属性可以修改,这一次我们来修改__proto__看看:
//新增一个新建构器function func1(){};//把obj的__proto__属性指向新建构器的prototype属性obj.__proto__ = func1.prototype;//这时候obj的原型就会从func完全变成func1了obj.constructor == func; //就不等于原本的建构器了,会回传falseobj.constructor == func1; //会回传true//接着使用instanceof、isPrototypeOf及Object.getPrototypeOf检查obj instanceof func1; //回传truefunc1.prototype.isPrototypeOf(obj); //会回传trueObject.getPrototypeOf(obj) === func1.prototype; //会回传true
这些例子真的越试越搞混,不过可以看到不论试用何种方式去做原型的继承或指定,最后都会存在物件中的__proto__属性中,所以只要改变了该属性就算是建构器的实体constructor特性也会跟着改变!!
那既然使用__proto__就可以更改原型,那他又和prototype有什么关係呢?我们可以把他理解成prototype是属于父母身上的基因,而他在做继承这个动作的时候会把prototype中的基因放进孩子中的__proto__里面,让他也拥有相同的基因存在,不过JS的物件继承真的是一个很难釐清的部分,说不定以后更了解了会再回来更新这篇文章,如果有说明错误或不明白的地方,麻烦再留言告知我,我会尽速改正!!