当前位置: 首页 > Web前端 > JavaScript

JavaScript原型与原型链

时间:2023-03-27 12:32:54 JavaScript

1.prototype在JavaScript中,每个函数都有一个prototype属性,它指向函数的原型对象。例如:复制代码functionPerson(age){this.age=age}Person.prototype.name='kavin'varperson1=newPerson()varperson2=newPerson()console.log(person1.name)//kavinconsole.log(person2.name)//kavin复制代码在上面的例子中,函数的原型指向一个对象,这个对象就是调用构造函数时创建的实例的原型,即人1和人2。原型的概念:当每个javascript对象(null除外)被创建时,都会关联另一个对象。这个对象就是我们所说的原型,每个对象都会“继承”原型的属性。让我们用一张图来表示构造函数和实例原型之间的关系:2.__proto__这是每个对象(除了null)都会有的一个属性,叫做__proto__,这个属性会指向对象的原型。functionPerson(){}varperson=newPerson();console.log(person.__proto__===Person.prototype);//真与关系图:补充说明:大部分浏览器都支持这种非标准的方法访问原型,但是在Person.prototype中是不存在的。实际上,它来自Object.prototype。它与其说是一个属性,不如说是一个getter/setter。使用obj.__proto__时,可以理解为返回了Object.getPrototypeOf(obj)。三、constructor每个原型都有一个constructor属性,指向关联的构造函数。functionPerson(){}console.log(Person===Person.prototype.constructor)//true所以更新关系图:复制代码functionPerson(){}varperson=newPerson();console.log(person.__proto__==Person.prototype)//trueconsole.log(Person.prototype.constructor==Person)//true//顺便学一个ES5的方法,可以得到对象的原型console.log(Object.getPrototypeOf(person)===Person.prototype)//真正的复制代码补充说明:functionPerson(){}varperson=newPerson();console.log(person.constructor===Person);//获取person时为真。在构造构造器的时候,人里面其实是没有constructor属性的。当constructor属性无法读取时,会从person的原型中读取,即Person.prototype,恰好存在于prototype中,所以:person.constructor===Person.prototype.constructor4.实例而Prototype在读取一个实例的属性时,如果找不到,就会去查找与该对象关联的原型中的属性。如果找不到,它会寻找原型的原型,并找到最上面的。前端训练复制代码functionPerson(){}Person.prototype.name='Kevin';varperson=newPerson();person.name='Daisy';console.log(person.name)//Daisydeleteperson.name;console.log(person.name)//Kevin复制了代码在这个例子中,我们给实例对象person添加了name属性。当我们打印person.name时,结果自然是Daisy。但是当我们删除person的name属性,读取person.name,如果person对象中没有找到name属性,就会从person的原型中查找,也就是person.__proto__,也就是Person.prototype。幸运的是,我们找到了name属性,原来是Kevin。但是,如果还没有找到呢?原型的原型是什么?5.原型的原型前面我们已经说过,原型也是一个对象。既然是对象,那么我们可以用最原始的方式来创建,即:varobj=newObject();obj.name='Kevin'console.log(obj.name)//其实Kevin的原型对象是通过Object构造函数生成的。结合我们之前说的,实例的proto指向构造函数的原型,那么更新一下关系图:6.原型链简单回顾一下构造函数、原型、实例的关系:每个构造函数都有一个原型对象,原型对象包含一个指向构造函数的指针,实例包含一个指向原型对象的内部指针。那么如果我们让原型对象等于另一个类型的实例会发生什么呢?显然,此时的原型对象会包含一个指向另一个原型的指针,相应地,另一个原型也会包含一个指向另一个构造函数的指针。如果另一个原型是另一个类型的实例,那么上述关系仍然成立。这样的渐进层形成了实例和原型链。这就是所谓原型链的基本概念。——摘自《javascript高级程序设计》其实简单来说就是上面说的四五流程。继上面五点之后,Object.prototype的原型呢?console.log(Object.prototype.__proto__===null)//true指的是阮一峰老师的《undefined与null的区别》:null的意思是“没有对象”,也就是那里应该没有值。所以Object.prototype.__proto__的值为null,Object.prototype没有原型,其实表达了一个意思。所以在搜索属性的时候,如果找到了Object.prototype,就可以停止搜索了。最后一张关系图也可以这样更新:图中相互关联的原型组成的链式结构就是原型链,也就是蓝线。