Contenu :
Plusieurs modes de création d'objets et le processus de création
Compréhension du prototype de chaîne de prototypes, et prototype
et Plusieurs implémentations de la relation __proto__
([[Prototype]]
)
héritage
a. Processus de création d'un constructeur
function Test() {// }
Lors de la création d'une fonction, un attribut de prototype sera créé pour Test par défaut, Test.prototype
Contient un pointeur pointant vers Object.prototype
le prototype aura un constructeur par défaut, et d'autres méthodes dans Test.prototype.constructor = Test
prototype Hérité de Objet
// 调用构造函数创建实例 var instance = new Test()
L'instance ici contient un pointeur vers le constructeur Le prototype de la fonction, (le pointeur ici s'appelle __proto__
en chrome, qui est également égal à [[Prototype]]
)
b.
D'après ce qui précède, nous pouvons savoir que les propriétés du prototype créées par défaut n'ont qu'un constructeur et des propriétés héritées de l'objet. Le mode prototype consiste à ajouter des propriétés et des méthodes au prototype
Test.prototype.getName = ()=> { alert('name') }
À ce stade, l'instance d'instance est Nous avons la méthode getName, car le pointeur d'instance pointe vers Test.prototype
instance.__proto__ === Test.prototype
comme indiqué dans la figure ci-dessous
Ici, nous pouvons savoir que l'instance d'instance et le constructeur sont liés via le prototype prototype
.
c. Mode combinaison
Nous utilisons le plus ce mode. C'est en fait une autre façon d'écrire le mode prototype, avec juste une petite différence
function Test() {} Test.prototype = { getName() { alert('name') } }
Nous l'utilisons souvent directement. En réécrivant la méthode prototype, nous savons d'après ce qui précède que le prototype aura son propre attribut constructeur pointant vers le constructeur lui-même par défaut, alors que se passe-t-il après la réécriture ?
Test.prototype.constructor === Object // 而并不等于Test了// 因为重写以后相当于利用字面量方式创建一个实例对象,这个实例的构造函数是指向Object本身的
Bien sûr, nous pouvons également attribuer le constructeur manuellement
Test.prototype = { constructor: Test, getName() { alert('name') } }
Ensuite, il y aura à nouveau des questionsconstructor
A quoi ça sert de le faire ? Je pense que le sens du mot constructeur est simplement d'identifier le constructeur auquel appartient le prototype.
Lorsqu'un certain attribut doit être obtenu, il sera d'abord recherché à partir de l'instance. Sinon, il sera recherché en fonction du prototype pointé par le pointeur, puis vers le haut jusqu'au pointeur de l'instance <. 🎜> pointe vers null et la recherche s'arrêtera. Par exemple : __proto__
// 1 读取nameinstance.name // 2 instance.__proto__ === Test.prototypeTest.prototype.name // 3 Test.prototype.__proto__ === Object.prototypeObject.prototype.name // 4Object.prototype.__proto__ === null
. delete
est un constructeur, et leurs pointeurs de prototype pointent vers Array, Date, Function, String
Ils sont comme les Object.prototype
que j'ai définis ici, mais ils sont natifs. Test
Faire pointer le prototype par le pointeur d'une instance Object.getPrototypeOf()
Object.getPrototypeOf(instance) === Test.prototype
Déterminer si un attribut existe dans l'instance ou dans le prototype, comme indiqué dans la figure : hasOwnProperty
opérateur, que l'attribut soit énumérable ou non in
'name' in instance // true 'getName' in instance // true
// 一种就是使用hasOwnProperty判断在实例中 // 另一种判断在原型中 instance.hasOwnProperty('getName') === false && 'getName' in instance === true
opération Le symbole est le même, mais seules les propriétés énumérables seront répertoriées. Le bug dans la version ie8 est que peu importe si la propriété est énumérable ou non, for ... in
name是在实例中定义的,getName是在原型中定义的
Object.keys()
则不一样,它返回一个对象上所有可枚举的属性,仅仅是该实例中的
Object.keys(instance)// ["name"]
e.总结
以上讨论了构造函数,原型和实例的关系:
每个构造函数都有原型对象
每个原型对象都有一个constructor
指针指向构造函数
每个实例都有一个__proto__
指针指向原型
其实是一个道理,这里我们不难想到,将Child.prototype指向parent实例,就是利用原型实现的继承,而为了每个实例都拥有各自的colors和name,也就是基础属性,在Child的构造函数中call调用了Parent的构造函数,相当于每次实例化的时候都初始化一遍colors和name,而不是所有实例共享原型链中的colors和name。
继承的实质是利用构造函数的原型 = 某个构造函数的实例,以此来形成原型链。例如
// 定义父类function Parent() {}Parent.prototype.getName = ()=> { console.log('parent') }// 实例化父类let parent = new Parent()// 定义子类function Child() {} Child.prototype = parent // 实例化子类let child = new Child() child.getName() // parent// 此时 child.constructor === parent.constructor === Parent
a.最经典的继承模式
function Parent(name) {this.name = namethis.colors = ['red'] } Parent.prototype.getName = function() {console.log(this.name) }// 实例化父类let parent = new Parent()function Child(age, name) { Parent.call(this, name)this.age = age } Child.prototype = parent // 实例化子类let child = new Child(1, 'aaa') child.getName() // parent
这里会让我想到ES6中的class继承
class Parent { constructor(name) {this.name = namethis.colors = ['red'] } getName() { console.log(this.name) } }class Child extends Parent { constructor(age, name) {super(name) } } let child = new Child(1, 'aaa') child.getName() // parent
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!