构造函数创建一个对象
让我们首先使用构造函数创建一个对象:
函数Person(){ } var Person=new Person();person.name=' Kevinconsole . log(person . name)//Kevin在这个例子中,person是一个构造函数,我们用new创建了一个实例对象Person。
很简单,让我们言归正传:
原型
每个函数都有一个原型属性,这是我们在各种示例中经常看到的原型,例如:
注释中写了函数Person() {}//但是要注意://prototype是函数所具有的属性。person . prototype . name=' Kevin ';var Person 1=new Person();var Person 2=new Person();console . log(person 1 . name)//kevnoiole . log(person 2 . name)//Kevin这个函数的原型属性到底指向什么?是这个功能的原型吗?
实际上,函数的prototype属性指向一个对象,该对象是通过调用构造函数创建的实例的原型,即本例中person1和person2的原型。
那么原型是什么呢?您可以理解,每个JavaScript对象(除了null)在创建时都会与另一个对象相关联。这个对象就是我们所说的原型,每个对象都将从原型“继承”它的属性。
让我们用一个图表来显示构造函数和实例原型之间的关系:
在这个图中,我们使用Object.prototype来表示实例的原型。
那么我们如何表达实例和实例原型之间的关系,即人和人之间的关系呢?这时,我们就来谈谈第二个属性:
__原型_ _
这是每个JavaScript对象的属性(除了null),称为__proto__,它指向对象的原型。
为了证明这一点,我们可以输入火狐或谷歌:
函数Person(){ } var Person=new Person();console.log(person。_ _ proto _ _===person . prototype);//true因此我们更新了以下关系图:
既然实例对象和构造函数都可以指向原型,那么原型有指向构造函数或实例的属性吗?
构造器
没有实例指向,因为一个构造函数可以生成多个实例,但是原型确实指向构造函数。这是关于第三个属性:构造函数,每个原型都有一个指向关联构造函数的构造函数属性。
为了测试这一点,我们可以尝试:
function Person(){ } console . log(Person===Person . prototype . constructor);//true,因此更新下一个关系图:
综上所述,我们得出结论:
函数Person(){ } var Person=new Person();Console.log (person。_ _ proto _ _==person . prototype)//true console . log(person . prototype . constructor==person)//true//顺便学一个ES5方法。可以得到对象的prototype console . log(object . get prototype of(person)==person . prototype)//true,了解构造函数、实例原型和实例之间的关系。接下来,让我们谈谈实例和原型之间的关系:
示例和原型
当读取一个实例的属性时,如果没有找到,它将在与该对象关联的原型中寻找该属性;如果没有找到,它将寻找原型的原型,直到找到顶层。
例如:
函数Person(){ } Person . prototype . name=' Kevin ';var Person=new Person();人名='黛西';console . log(person . name)//Daisydelete person . name;console . log(person . name)//Kevin在本例中,我们向实例对象person添加了name属性。当我们打印人名时,结果是黛西。
然而,当我们删除人的名字属性时,我们读person.name如果我们不能从person对象中找到名字属性,我们将从person的原型,即person中查找它。__proto__,即Person.prototype幸运的是,我们找到了name属性,结果是Kevin。
但是如果我们还没有找到呢?原型的原型是什么?
原型的原型
前面,我们已经说过原型也是一个对象,既然它是一个对象,我们就可以用最原始的方式创造它,那就是:
var obj=新对象();obj . name=' Kevin ' console . log(obj . name)//Kevin
因此,原型对象由对象构造器生成。结合前面的语句,实例的__proto__指向构造函数的原型,因此我们更新了以下关系图:
原型链
对象的原型呢。原型?
Null,不要相信我们可以打印:
console . log(object . prototype . _ _ proto _ _===null)//true
因此,当您找到属性时,您可以通过找到对象原型来停止搜索.
最后一张图是
顺带一提,图中相关原型组成的链结构就是原型链,也就是蓝线。
补充
最后,补充三点你可能没有注意到的地方:
构造器
第一个是构造函数属性。让我们举个例子:
函数Person(){ } var Person=new Person();console . log(Person . constructor===Person);//true获取person.constructor时,没有person的构造函数属性。如果无法读取构造函数属性,将从person的原型中读取,即Person.prototype,它恰好在原型中具有此属性,因此:
person . constructor===person . prototype . constructor _ _ proto _ _
第二个是__proto__。大多数浏览器支持这种非标准方法来访问原型。然而,它并不存在于Person.prototype中,事实上,它来自Object.prototype,与其说它是一个属性,不如说它是一个getter/setter。使用obj时。__proto__,可以理解为返回object.getprot。
真的是继承吗?
最后,关于继承,我们之前说过“每个对象都会从原型‘继承’属性”。事实上,继承是一个非常令人困惑的说法,引用于《你不知道的JavaScript》:
继承就是复制操作。但是,默认情况下,JavaScript不会复制对象的属性。相反,JavaScript只在两个对象之间创建关联,这样一个对象可以通过委托访问另一个对象的属性和功能。因此,委托比继承更准确。
以上就是本文的全部内容。希望对大家的学习有帮助,支持我们。