JS(JavaScript)中的原型和原型链总结———例题详解(附源码)
何为原型及原型链?
什么是原型?
在JS中每个构造器(函数)都一个属性叫prototype,它叫原型,也是个对象,我们叫这个对象为原型对象;而每个对象中有一个属性叫__proto__,它叫隐式原型,
什么是原型链?
是一个对象的查找机制,比如查找对象arr中的toString方法,会先在自己的私有属性中找,如果没有,就沿着__proto__去原型对象中找,如果还没有,就继续沿着__proto__去它原型对象中的原型对象中找,直到找到Object中的原型对象(Object原型对象中的__proto__指向null),如果还没找到,那么结果就是undefined;
什么是作用域链?
和原型链如出一辙,是一个EC(执行上下文)中数据的查找机制,现在自己EC中找数据,如果没有就去父函数所对应的上下文中找,如果还没有,就去父函数的父函数的EC中找,知道找到EC(G),如果还是没有,那么就报错;
- 下图为原型与原型对象的详细分析图:
-
原型练习题1(详细过程)
- 代码执行过程详解;
80行代码先创建一个Fn构造器; 84行代码,对Fn的原型对象增加一个方法say(是一个函数);
87行代码创建一个新的Fn的原型对象,此时Fn构造器prototype将指向新的原型对象;
88行代码,new了一个新的对象f1,有自己的私有属性a=1; 89行代码,给新的原型对象增加一个b方法(也是一个函数);
92行代码,打印出f1.a,就是打印出f1对象中的a变量,f1对象有a为1,就打印出来1;
93行代码,执行f1.say()函数,先在对象f1中找say函数,没有,然后沿着__proto__去它的原型对象中找如果还没有就一直沿着__proto__往上一级的原型对象中找,此时在Fn构造器原来的原型对象中找到say函数,此时执行say函数,say函数中的this指向f1对象中的a变量,函数执行后,f1对象中的a变量变为2;
94行代码,打印出f1.a,为2;
95行代码,执行f1.b()函数,先在对象f1中找b函数,没有,然后沿着__proto__去它的原型对象中找如果还没有就一直沿着__proto__往上一级的原型对象中找,此时在Fn构造器新的原型对象中找到b函数,此时执行b函数,b函数中的this指向f1对象中的a变量,函数执行后,f1对象中的a变量变为3;
96行代码,打印出f1.a,为3;
★★★★★如果构造器new了一个新的原型对象(Fn.prototype),此时这个新的原型对象的__proto__还指向原来的Fn的原型对象;但是还有一种情况,如果对构造器的prototype属性进行了修改而不是新建,此时修改后的Fn原型对象的__proto__就是指向Object构造器的原型对象,也就相当于将原来的Fn原型对象覆盖掉了;★★★★★
-
原型练习题2
- 103行代码,把原有的Fn函数当做了对象,此时内部的__proto__指向的是函数Fn的构造器(Function构造器)的原型对象,而它的原型对象里面没有自己设置的方法;
- 在下面111行代码执行时,先去Fn对象找有没有sum()方法,如果没有就沿着__proto__去原型对象中找,然而,Function构造器的原型对象中没有sum()方法,所以出现报错,//Fn.sum is not a function
-
原型练习题3
- 131行代码,分别new了 三个对象,对于C1,因为没有实参,在执行if语句时候直接跳出,所以没有私有属性,对于C2,因为没有实参,所以拿到的数据为undefined,但是属性名还是name,所以有私有属性(name:undefined),对于C3,因为没有实参,所以形参name为undefined,在构造器中使用了||(或)操作,此时undefined不能确定name,所以私有属性name为join;三个对象的公有属性都为name:tom;
- 在执行alert时,先找自己的私有属性,如果没有就去找公有属性,所以输出为:Tomundefinedjoin
- alert中的 + 此时作用是字符串拼接;