前言在了解原型和原型链之前,我们先了解一些概念,构造函数,原型,__proto__。构造函数判断数据类型在上一篇文章:JavaScript常见数据类型检查与验证中提到了构造函数的属性。constructor构造函数返回对创建实例对象的构造函数的引用。该属性的值是对函数本身的引用,而不是包含函数名的字符串具体用法:constructor.prototype.constructor()functionconstructorFn(){this.name="11";}console.log(constructorFn.构造函数);//Functionleta=newconstructorFn();console.log(a.constructor);//?constructorFn(){this.name="11";}prototypeconsole.log(Object.prototype);↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓构造函数:?对象()hasOwnProperty:?hasOwnProperty())valueOf:?valueOf()__defineGetter__:?__defineGetter__()__defineSetter__:?__defineSetter__()__lookupGetter__:?__lookupGetter__()__lookupSetter__:?__lookupSetter__()__proto__:(...)获取__proto__:?__proto__()设置__proto__:__()}在js中,每一个函数或方法都有一个特殊的和默认的该属性称为原型(prototype),它是一个对象,这个对象包含了一些属性和这个方法自带的方法原型链protofunctionconstructorFun(){}constructorFun.prototype.testName="constructorFun";letnewFun=newconstructorFun();//newFunconsole.log(newFun);console.log(newFun.testName);//通过__proto__查找输出:constructorFunconsole.log(newFun.constructor);//?constructorFun(){}console.log(newFun.__proto__);//{testName:'constructorFun',constructor:?}console.log(newFun.prototype);//undefinedconsole.log(newFun.prototype.__proto__);//Errorincreatedhook:"TypeError:Cannotreadproperty'__proto__'ofundefined"通过上面的代码,我们可以看到原型对象包含一个__proto__属性,这个属性是原型链的关键。newFun在使用new运算符时,继承了constructorInconstructorFun,testName,同时通过newFun.__proto__我们可以知道,当newFun没有自己的名字时,它会通过__proto__继续往上查找,直到找到相关属性成立。如果不存在,则在JavaScript中为undefined只有一种结构:对象。每个实例对象(object)都有一个私有属性(称为proto)指向其构造函数(prototype)的原型对象。原型对象也有自己的原型对象(__proto__),层层叠叠直到一个对象的原型对象为空。根据定义,null没有原型,充当此原型链中的最后一环。(断言来自MDNhttps://developer.mozilla.org/)FindnullprocedureconstructorfromprototypechainfunctionconstructorFun(){}constructorFun.prototype.testName="constructorFun";letnewFun=newconstructorFun();//newFunconsole.log(newFun);console.log(newFun.testName);//通过__proto__查找输出:constructorFunconsole.log(newFun.constructor);//?constructorFun(){}console.log(newFun.__proto__);//{testName:'constructorFun',constructor:?}console.log(newFun.prototype);//undefinedconsole.log(newFun.prototype.__proto__);//createdhook报错:"TypeError:Cannotreadproperty'__proto__'ofundefined"使用new操作符实例化的方法没有自己的原型对象,通过__proto__可以查到构造函数的属性和方法,如以及构造函数。实例化方法可以通过constructor属性获取构造函数本身//constructorFunconsole.log(constructorFun.constructor);//?Function(){[本地代码]}console.log(constructorFun.__proto__===Function.prototype);//trueconsole.log(constructorFun.prototype);//{testName:'constructorFun',constructor:?}testName:"constructorFun"constructor:?constructorFun()[[Prototype]]...}console.log(constructorFun.prototype.constructor);//?constructorFun(){}console.log(constructorFun.prototype.__proto__===Object.prototype);//trueconstructorconstructorFunpropertyconstructorisFunction,查找原型链时,构造函数Function的__proto__→Function的原型prtotypeconstructorFun的原型对象的__proto__是对象的原型//?Function(){[本地代码]}console.log(Function.__proto__);//?(){[本地代码]}console.log(Function.prototype);//?(){[本地代码]}console.log(Function.prototype.constructor);//?Function(){[本地代码]}console.log(Function.prototype.__proto__===Object.prototype);//true//Objectconsole.log(Object.constructor);//?Function(){[本地代码]}console.log(Object.__proto__);//?(){[本地代码]}console.log(Object.prototype);//构造函数:?,__defineGetter__:?,__defineSetter__:?,hasOwnProperty:?,__lookupGetter__:?,...console.log(Object.prototype.constructor);//?Object(){[本地代码]}console.log(Object.prototype.__proto__);//null字面量创建对象letparent={name:1}//parentconsole.log(parent.constructor);//?Object(){[本地代码]}console.log(parent.__proto__);//{构造函数:?,__defineGetter__:?,__defineSetter__:?,hasOwnProperty:?,__lookupGetter__:?,...}console.log(parent.prototype);//未定义//console.log(parent.prototype.__proto__);//创建钩子时出错:“TypeError:无法读取未定义的属性‘__proto__’”//Objectconsole.log(Object.constructor);//?Function(){[本地代码]}console.log(Object.__proto__);//?(){[本地代码]}console.log(Object.prototype);//{constructor:?,__defineGetter__:?,__defineSetter__:?,hasOwnProperty:?,__lookupGetter__:?,…}console.log(Object.prototype.constructor);//?Object(){[本地代码]}console.log(Object.prototype.__proto__);//null通过上面的代码搜索,我们可以得出对应的关系图总结:原型原型和原型链搜索__proto__,构造函数构成原型链。通过这些属性和方法,可以逐层查找,直到null构造函数的实例化方法。可以通过原型链的形式查找对应的属性(前提是该属性存在)。这里的知识点还包括newinstance的过程,使用原型链和prototype的继承知识,我们可以封装构造方法,还有一些插件,我们在阅读框架源码或者插件源码的时候,可以看原型和构造函数相关的代码原型和原型链的知识,概念上不太好理解或者说有点晦涩难懂。可以尝试写一些实例化的对象和方法,如果涉及到面向对象编程或者用的比较多,可以在原型上和开发过程中找到方法,加深理解。类似于数组和Function构造函数,我们可以通过继承的方式在原型链上扩展一些常用的utils方法。以上就是js中原型和原型链概念的简单介绍。分析,有问题请留言,后续文章会整理补充。文章博客地址:javaScript原型及原型链源码地址码云https://gitee.com/lewyon/vue-notegithubhttps://github.com/akari16/vue-note欢迎关注公众号:程序员布欧,部分文章不易更新,转载请注明出处和作者。
