下面这张图大家应该很很熟悉了,各位大佬讲原型及原型链的时候是大部分都会用到下面这张图片的
我想以自己的方式来讲述一遍,一是帮助我自己更好的复习,二是希望能够帮助到想要复习或者学习原型的同学

[[prototype]],这个原型就是隐式原型__proto__,而构造函数因为其本身就是 一个对象,所以它有一个隐式原型,但是构造函数又是一个函数,所以他有一个特殊的属性显式原型prototype,大家也可以看到constructor这个属性,默认情况下,函数对象上都会有一个constructor属性,里面存放着是函数的原型对象
function Foo() 他是一个构造函数Foo的原型对象上f1这个实例化Foo的对象,因为是对象,所以它只有一个__proto__隐式原型的Foo的原型对象上的,这是为什么呢?new这个操作 到底干了些什么,这应该是一道经典的面试题吧{}this指向该空象,然后将构造函数的显式原型赋予给这个对象的隐式原型上去 __proto__=prototypef1的隐式原型是指向了Foo的显式原型的吧,是不是很容易理解呢
Object的原型对象的,小伙伴看到这里会不会很懵? 觉得为啥就是指向Object的原型对象呢?new Object会有点陌生,因为大家创建对象的时候,往往都是通过创建一个字面量来申明一个对象的const obj={},实际上这个操作就是等于new Object().所以看到了new Object()大家有没有明白什么呢???Object是一个构造函数,那么他的显式原型就是指向Object.Prototype了,即原型对象,那么在实例化Object的时候,就会做我上面讲的new操作符操作了,所以那个Foo.prototype的隐式原型指向那个Object.prototype是不是理解了呢???
Foo的隐式原型上,函数的隐式原型是谁给的呢? 上文讲到,隐式原型是在实例化的时候,构造函数所赋予的,那么谁会是Foo的构造函数呢?Function,实例化了Function所得到的Foo,所以Foo的隐式原型是指向了Function的显式原型Function.prototype的它便是 Function和Object构造函数,他们两个有点特殊,所以单独拿出来讲讲
Object这个构造函数Object的显式原型是指向了Object.prototype,这一点大家肯定都没有问题Object.prototype的隐式原型是指向了null,这说明了一个什么问题,隐式原型是在实例化的时候才会被赋予的,但是他是为空,所以我们可以得到一个结论,就是在JS中,顶层原型是Object.prototype,????Object.prototype是站在最顶峰的辣个男人Object的隐式原型是指向哪的,会发现它的隐式原型是指向函数的显式原型的,说明Object这个构造函数是通过Function这个构造函数所实例化得到的Function这个构造函数的显式原型和隐式原型Function.prototype,这点没问题Function.prototype 嗯? 嗯? 好怪,不行,我再看一眼??Function是通过实例化自己得到的吗?Function.prototype的隐式原型指向了Object.prototype说明了函数的原型对象是通过实例化Object所得到的
我出几道练习题,大家自己练习一下,看看自己掌握的怎么样
/** 1.普通对象 * 2.构造函数 * 3.Function * 4.Object **/function Foo(name) { this.name = name;}const obj = {};const obj2 = { name: "给他一个新的原型",}const foo = new Foo("czx");console.log(foo.__proto__ === Foo.prototype);console.log(obj.__proto__ === Object.prototype)console.log(Foo.prototype === Foo.__proto__);console.log(Foo.__proto__ === Function.prototype);console.log(Function.prototype === Function.__proto__); console.log(Function.prototype.__proto__ === Object.prototype);console.log(Object.__proto__ === Function.prototype);console.log(Object.prototype.__proto__);Foo.prototype = obj2;console.log(Foo.prototype.__proto__ === Object.prototype)console.log(foo.__proto__ === Foo.prototype);大家一定要自己写完后再来看答案啊,这样印象才深刻
console.log(foo.__proto__ === Foo.prototype);//trueconsole.log(obj.__proto__ === Object.prototype)//trueconsole.log(Foo.prototype === Foo.__proto__);//falseconsole.log(Foo.__proto__ === Function.prototype);//trueconsole.log(Function.prototype === Function.__proto__); //trueconsole.log(Function.prototype.__proto__ === Object.prototype);//trueconsole.log(Object.__proto__ === Function.prototype);//true;console.log(Object.prototype.__proto__);//nullFoo.prototype = obj2;console.log(Foo.prototype.__proto__ === Object.prototype)//true;console.log(foo.__proto__ === Foo.prototype);//false只要理解了上面我讲的原型,原型链自然而然就会了
function Foo(name, age) { this.name = name; this.age = age;}const bar = { say: () => { console.log("执行说话"); }, age2: 32,}Foo.prototype = bar;const foo = new Foo("Spirit", 18)foo.say();console.log(foo.age2)var A = function () { };A.prototype.n = 1;var b = new A(); A.prototype = { n: 2, m: 3} var c = new A();console.log(b.n);console.log(b.m);console.log(c.n);console.log(c.m);?????? 大家可以想下这道题的输出结果是什么,这道题也是很考察大家对原型链的理解的,接下来我就会开始讲解了
A 是一个构造函数,它有显式原型和隐式原型A在显式原型上添加了一个属性n,其值为1new操作熟不熟悉,这时候有b.__proto__===A.prototypec.__proto__===A.prototype 只不过这个显式原型不再是之前的了b.n是输出1的,因为是加在了最开始A的显式原型上面,所以是能取到值的b.m是取不到值的,因为这个m是后面更换了A的显式原型所加上的值,此时的b是取不到的c.n输出为2,因为更换后的显式原型上面是有n 是2c.m输出为3,同理new操作做了什么,让你来判断到底实例化之后是赋予了哪个显式原型,下面的代码是带注解版的var A = function () { };A.prototype.n = 1; //显示原型上加了一个 n属性 值为1var b = new A(); //实例化了的b __proto__===A.prototypeA.prototype = { n: 2, m: 3} //A的显式原型被替换掉了var c = new A(); //实例化的c 的__proto__===A更换后的显式原型console.log(b.n); //1console.log(b.m); //undefinedconsole.log(c.n);//2console.log(c.m);//3var F = function () { };Object.prototype.a = function () { console.log('a');};Function.prototype.b = function () { console.log('b');}var f = new F(); f.a(); f.b(); F.a();F.b();??这道题是我认为比较难的一道题,大家可以好好想下这道题的输出到底是什么,接下来我会开始讲解这道题
F是一个构造函数,它拥有显式原型和隐式原型F.prototype.__proto__===Object.prototypeF.__proto__===Function.prototypeObject.prototype上加上了一个函数aFunction.prototype加上了一个函数bf,这个时候他有隐式原型f.__proto__===F.prototypef.a()首先它的隐式原型是等于构造函数的显式原型的,而F.prototype.__proto__是等于Object.prototype,也就是说f是可以沿着这条原型链一路往上找到,最后是可以找到这个a函数的,所以可以输出af.b()我们可以想下,沿着原型链我们可以找到这个函数b嘛,并不可以,对不对??,所以这里会报错,说不存在这么一个函数F.a()我们来看下这个构造函数是有显式原型和隐式原型的,所以我们看回刚开始的那个解释,它是能找到Object.prototype和Function.prototype的,所以能够输出aF.b()也是同理,所以输出bvar F = function () { }; //构造函数 //他有隐式原型和显式原型 此时他的隐式原型__proto__===Function.prototype.__proto__===Object.prototypeObject.prototype.a = function () { //Object.prototype是顶层原型 console.log('a');};Function.prototype.b = function () { console.log('b');}var f = new F(); //实例化了的f 此时是一个对象 只有隐式原型 __proto__ 所以此时有 __proto__===F.prototype //?????? F.prototype是一个对象,是Object所实例化得到的 所以F.prototype.__proto__===Object.prototypef.a(); //af.b(); //报错 没有这个函数F.a(); //aF.b();//b本文来自博客园,作者:CodeSpirit,转载请注明原文链接:https://www.cnblogs.com/codespirit-zx/p/16037819.html