当前位置: 首页 > 后端技术 > Node.js

忘记也没关系!再学JavaScript原型链

时间:2023-04-03 16:29:55 Node.js

1.原型的概念首先提出一个问题:在全局作用域定义一个函数会污染全局作用域的命名空间(下一个同名函数会被覆盖),而且很不安全(别人一起写的时候,他们也可以写一个同名的函数)。该怎么办?-将这些函数放入原型对象中。那么什么是原型对象呢?对于我们创建的每一个函数,解析器都会给函数添加一个属性prototype,这个属性对应一个对象,就是prototype对象。如果函数将原型作为普通函数调用,则没有任何意义。当以构造函数的形式调用函数时,它创建的对象将包含一个隐式属性,该属性指向构造函数的原型对象。在实例中,我们可以通过__proto__访问这个属性。同一个类对应的原型对象是一样的,原型对象相当于一个公共区域。同一个类的所有实例都可以访问这个原型对象,所以我们可以将对象的共有的东西统一设置到原型对象中。示例:functionperson(){}varper1=newperson();varper2=newperson();console.log(per1.__proto__==per2.__proto__);//输出为真所以同一个构造函数的实例共享一个原型对象。在原型对象中设置属性:例子:functionperson(){}varper2=newperson();person.prototype.a=123;console.log(per2.a);//输出123per2是person的一个实例,所以可以访问person对象下的Prototype函数。上面的person.prototype.a=123;就是给person构造函数的原型函数设置a属性。二、原型链1、原型链图:在实例原型链中,先写一段代码(然后用代码验证关系)/注:下面对象的原型函数与创建的原型函数不同通过它//在Object创建的原型链中创建一个函数/Object.prototype.print=function(){console.log("我在Object下的原型对象中");};/在原型中创建一个函数对象/对象的对象。__proto__.print3=function(){console.log('我在Object的原型对象中');}/创建一个Fun构造函数,这个Fun其实就是全局的下一个普通函数/functionFun(x,y){this.x=x;this.y=y;}/在Fun创建的原型函数下创建一个函数/Fun.prototype.print2=function(){console.log('Fun类下的原型对象');}/使用Fun构造函数来创建属于类Fun/vara=newFun(1,2)的a实例;2.理清原型链相关语法示例中prototypechain(图中使用foo,我们这里定义的是fun)使用构造函数创建实例,并与实例一起创建原型函数。该类下只有一个原型函数,1类的实例共享一个原型函数。实例使用实例对象.__proto__访问原型函数进行读写。Constructor(Object和Fun使用object.prototype访问自己创建的原型函数)Fun和Object的关系/注意:这里的代码是继承上面的代码,同下面/console.log(Fun===Object);//false,Fun和Object是两个不同的构造函数console.log(Fun.__proto__===Object.__proto__);//true,它们共享一个原型对象console.log(Fun.__proto__.print3());//在Object的原型对象中,Fun和Object处于同一层级,共享一个原型链。Fun和Object他们对应的原型对象;//输出{print3:[Function(anonymous)]}console.log(Object.__proto__.__proto__);//输出[Object:nullprototype]{print:[Function(anonymous)]}console.log(Object.__proto__.__proto__.__proto__);//null的输出表示Object和Fun上有一个共享的原型对象,原型对象上也有一个空原型对象,然后就是Fun和Object创建的空原型对象关系console.log(Fun.prototype==Object.prototype);//falseconsole.log(Fun.prototype.constructor==Fun);//trueconsole.log(Object.prototype.constructor==Object);//trueconsole.log(Fun.prototype.constructor.__proto__==Object.__proto__);//true表示这两个构造函数创建的原型对象不一样。而构造器下的原型对象的构造器就是它自己,这就证明了a和Fun的关系Object);//我在Object的原型对象中console.log(a.print3());//a.print3不是函数console.log(a.__proto__.constructor==Fun);//trueconsole.log(a.__proto__.constructor==a.constructor);//trueconsole.log(a.constructor==Fun);//trueconsole.log(a.constructor==Fun.prototype);//falseconsole.log(a.__proto__==Fun.prototype);//trueconsole.log(a.print());//我在console.log(a.print2())中创建的原型对象Object;//原型对象Fun类中创建console.log(Function.__proto__==Fun.__proto__);//true可以看出a和Fun是实例和构造函数的关系,a访问不到object.__proto__a和Objectconsole.log(a.constructor.__proto__==Object.__proto__);//true这里代码是用来划关系的,其实本质还没有说完,请稍后阅读!3.再次遍历原型链。在这里,标出原型链的序号(注意函数下的表达式和函数的区别)。先自己分析一下。如果你看懂了,就跳过下面的内容,直接离开吧。编号1:Foo构造函数的实例f1,其原型对象为构造函数Foo下的原型对象,即f1.__proto__==Foo.prototype,Foo下的原型对象也是Foo构造函数创建的实例,所以它和f1是同一级别的,构造函数也是一样的。第2:如果有对象,就有原型对象(不是死循环,直到对象的原型),在构造函数Foo下创建的原型对象的原型对象指向object.prototype,原型Foo实例共享的对象是Foo.prototype,每个主要构造函数的构造函数下的原型对象的原型对象是object下的原型对象。序号3:这印证了序号2介绍的第一句话,object.prototype是终端,object是大长老。第4:这里是最重要的部分,因为这里出现了function的构造函数,这里先不说了,留给5,Object构造函数的实例o1的原型对象是object.prototype,object的构造函数是功能。No.5:大胆下结论,所有构造函数(constructor)之父是函数。object是function的实例,function是最特殊的,object的原型对象就是function下的原型对象,function.prototype.__proto__就是object.prototype。还有就是理解Function.__proto__==Function.prototype的关键:function是关键字,Function是引用类型。使用函数创建的变量是一个指针,指向的对象是一个函数对象。下面有三种函数声明方式,//第一种:functiona(){};//第二种:vara=function(){};//第三种:vara=newFunction();6:Function.prototype.__proto__==Object.prototype,就像序号2介绍中提到的各大构造函数的构造函数下的原型对象的原型对象,就是object下的原型对象。感谢阅读,如果您有更好的理解,欢迎留言!