Maison >interface Web >js tutoriel >Une brève analyse de l'héritage JavaScript et de la chaîne de prototypes

Une brève analyse de l'héritage JavaScript et de la chaîne de prototypes

WBOY
WBOYavant
2022-02-15 17:44:332116parcourir

Cet article vous apporte des connaissances sur l'héritage et la chaîne de prototypes en javascript, y compris les problèmes liés aux constructeurs, aux prototypes et au sucre de syntaxe de classe. J'espère qu'il sera utile à tout le monde.

Une brève analyse de l'héritage JavaScript et de la chaîne de prototypes

Une brève analyse de l'héritage et de la chaîne de prototypes de JavaScript

1. Introduction

L'héritage et la chaîne de prototypes de JavaScript sont les parties rares et difficiles à comprendre que j'ai rencontrées dans le processus d'apprentissage du front-end . Ici, je vais vous expliquer que j'ai enregistré tout ce que je sais et appris. J'espère que cela pourra apporter un peu d'aide aux frères qui ont encore des difficultés dans ce domaine. J'apprécie également vos critiques et corrections.

2. Constructeur

2.1 Membres d'instance et membres statiques du constructeur

Le constructeur se compose à la fois de membres d'instance et de membres statiques, où les membres d'instance sont des membres ajoutés via le mot-clé this à l'intérieur de la fonction ; être accessible via l'objet instancié après l'instanciation de l'objet ; tandis que les membres statiques sont des membres ajoutés à la fonction elle-même et ne sont accessibles que via le constructeur.

//创造一个构造函数let Father = function(name,age){
    //实例成员
    this.name = name;
    this.age = age;
    this.method = "我是一个实例成员";}
    //静态成员Father.like = "mother";
    //检验实例对象是否能够被构造函数直接访问console.log(Father.method);
    //undefinedconsole.log(Father.like);
    //mother
    //实例化一个对象let father = new Father("小王",27);
    //检验静态对象是否能够被实例化对象访问console.log(father.name);
    //小王console.log(father.age);
    //27console.log(father.like);
    //undefined

2.2 Le processus d'instanciation d'un objet

Le mot-clé new peut être utilisé pour implémenter un objet instancié via le constructeur, alors que se passe-t-il pendant le processus d'instanciation spécifique ? Il peut être grossièrement divisé en les étapes suivantes :

(1) Créer un objet vide fils {}

(2) Préparer un prototype de connexion en chaîne pour fils son.__proto__ = Father.prototypeson.__proto__ = Father.prototype

(3) 重新绑定this,使构造函数的this指向新对象 Father.call(this)

(4) 为新对象属性赋值 son.name

(5) 返回this return this,此时的新对象就拥有了构造函数的方法和属性了

一个小问题:所有实例化对象的方法都是共享的吗?

构造函数的方法分为两种,第一种为在函数内部直接定义的方法,第二种为通过原型添加的方法;

//函数内部直接定义的方法let Father = function(){
    this.read = function(){
        console.log("我是内部定义的read方法!");
    }}//通过Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes添加的方法Father.prototype.look = function(){
    console.log("我是通过Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes定义的look方法!");}
    //实例化对象进行检验let father1 = new Father();let father2 = new Father();
    father1.read();
    //我是内部定义的read方法!father2.read();
    //我是内部定义的read方法!console.log(father1.read === father2.read);
    //falsefather1.look();
    //我是通过Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes定义的look方法!father2.look();
    //我是通过Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes定义的look方法!console.log(father1.look === father2.look);
    /true

可以发现,函数内部直接定义的方法在每实例化一个新的对象以后,都会给这个方法分配一个新的内存空间,而通过原型添加的方法便会共享一个空间。

一个小问题:所有实例化对象的属性都是共享的吗?

不存在内存空间的问题,判断时看其值是否相同;

let Father = function(name){
    this.name = name;}let father1 = new Father("小王");
    let father2 = new Father("小红");
    console.log(father1.name === father2.name);
    //falselet father1 = new Father("小王");
    let father2 = new Father("小王");
    console.log(father1.name === father2.name);
    //true

因此我们可以总结一下定义构造函数的基本规则,即公共属性定义到构造函数里面,公共方法我们放到原型对象身上。

三、原型

3.1 什么是原型

Father.prototype 就是原型,它是一个对象,也可以称为原型对象。

3.2 原型的作用是什么

原型的作用,就是共享方法。

我们通过 Father.prototype.method 可以共享方法,不会反应开辟空间存储方法。

3.3 原型中的this指向哪儿

原型中this的指向是实例。

四、Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes

Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes本人感觉是一个对于初学者或者说是部分前端菜鸡(例如本人)来说特别难以理解的东西,为了让下面的部分更容易理解,这里强行先记住以下几点:

  1. __proto__是每个对象都有的属性,prototype是每个函数特有的方法;
  2. 每个对象的__proto__属性都会指向自身构造函数的prototype;
  3. constructor属性始终指向创建当前对象的构造函数;
  4. Function.__proto__ === Function.prototype;
  5. Object.prototype.__proto__ === null 也就是Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes的终点;

4.1 什么是Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes

原型与原型层层相链接的过程即为Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes。

4.2 Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes的应用

对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__原型的存在每个对象都有__proto__

(3 ) Reliez ceci pour que le this du constructeur pointe vers le nouvel objet Father.call(this)

(4) Attribuez des valeurs aux nouvelles propriétés de l'objet son.name

Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes( 5) Renvoie ceci renvoie ceci A ce moment, le nouvel objet aura les méthodes et propriétés du constructeur

Une petite question : toutes les méthodes d'instanciation sont-elles. objets partagés ?

Il existe deux façons de construire une fonction. La première est la méthode directement définie à l'intérieur de la fonction, et la seconde est la méthode ajoutée via le prototype

let Father = function(name){
    this.name = name;}let father = new Father("老王");console.log(father.__proto__ === Father.prototype);
    //true
    //验证上述说法中的第二条

On peut constater que la méthode est directement définie à l'intérieur de la fonction ; la fonction est dans chaque Après l'instanciation d'un nouvel objet, un nouvel espace mémoire sera alloué à cette méthode et les méthodes ajoutées via le prototype partageront le même espace.

Une petite question : les propriétés de tous les objets instanciés sont-elles partagées ?

Il n'y a pas de problème d'espace mémoire. Lors du jugement, voyez si les valeurs sont les mêmes ;

function Star(name) {
	this.name = name;
	//(1)首先看obj对象身上是否有dance方法,如果有,则执行对象身上的方法
	this.dance = function () {
		console.log(this.name + '1');
	}}//(2)如果没有dance方法,就去构造函数原型对象prototype身上去查找dance这个方法。Star.prototype.dance = function () {
	console.log(this.name + '2');};
	//(3)如果再没有dance方法,就去Object原型对象prototype身上去查找dance这个方法。Object.prototype.dance = function () {
	console.log(this.name + '3');};
	//(4)如果再没有,则会报错。let obj = new Star('小红');obj.dance();

Nous pouvons donc résumer les règles de base pour définir les constructeurs, c'est-à-dire que

les attributs publics sont définis dans le constructeur et les méthodes publiques sont placées sur l'objet prototype.

3. Prototype 🎜🎜🎜3.1 Qu'est-ce qu'un prototype 🎜🎜Père.prototype est un prototype C'est un objet et peut aussi être appelé un objet prototype. 🎜🎜3.2 Quel est le rôle du prototype ?🎜🎜Le rôle du prototype est de partager des méthodes. 🎜🎜Nous pouvons partager des méthodes via Father.prototype.method, ce qui ne reflétera pas la méthode de stockage de l'espace. 🎜🎜3.3 Où cela dans le prototype pointe-t-il vers l'instance ? 🎜🎜🎜4. Chaîne prototype 🎜🎜🎜 Je pense que la chaîne prototype est quelque chose de particulièrement difficile à comprendre pour les débutants ou certains noobs du front-end (comme moi). Afin de rendre les parties suivantes plus faciles à comprendre, voici). est un premier forcé Rappelez-vous les points suivants : 🎜
  1. __proto__ est un attribut de chaque objet, le prototype est une méthode unique à chaque fonction
  2. Chaque objet Le L'attribut __proto__ pointera vers le prototype de son propre constructeur ;
  3. L'attribut constructeur pointe toujours vers le constructeur qui a créé l'objet actuel ;
  4. Function.__proto__ code> === Function.prototype;
  5. Object.prototype.__proto__ === null est la fin de la chaîne de prototypes ;
  6. 🎜4.1 Qu'est-ce que c'est la chaîne de prototypes🎜🎜Le processus de liaison des prototypes aux prototypes couche par couche est la chaîne de prototypes. 🎜🎜4.2 Application de la chaîne de prototypes🎜🎜Les objets peuvent utiliser les attributs et les méthodes de l'objet prototype du constructeur car l'objet a __proto__ et chaque objet a __proto__ L'existence de prototypes 🎜
    function Star(name) {
    	this.name = name;}Star.prototype = {
        dance:function(){
        	console.log("重定义prototype");
    	}}Star.prototype.constructor = Star;
    🎜4.3 Diagramme de chaîne prototype🎜🎜🎜🎜🎜Combiné avec les premiers points, cela ne devrait pas être un gros problème de comprendre l'image ci-dessus. La partie encerclée sur l'image est l'épouvantable chaîne prototype. 🎜🎜4.4 Comment rechercher la chaîne de prototypes🎜
    //定义一个父类function Father(name) {
    	this.name = name;}Father.prototype.dance = function () {
    	console.log('I am dancing');};//定义一个子类function Son(name, age) {
    	Father.call(this, name);
    	this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () {
    	console.log('I am singing');};
    	let son = new Son('小红', 100);
    	//此时父类也被影响了console.log(Father.prototype) 
    	//{dance: ƒ, sing: ƒ, constructor: ƒ}
    🎜(1) Vérifiez d'abord s'il existe une méthode dance sur l'objet obj. Si c'est le cas, exécutez la méthode sur l'objet. 🎜🎜(2) S'il n'y a pas de méthode de danse, accédez au prototype d'objet prototype du constructeur pour trouver la méthode de danse. 🎜🎜(3) S'il n'y a pas de méthode de danse, rendez-vous dans le prototype d'objet Objet prototype pour trouver la méthode de danse. 🎜🎜(4) S'il n'y en a plus, une erreur sera signalée. 🎜
    一个小问题:在原型上添加方法需要注意的地方

    有两种添加方法,第一种为上面的写法,直接通过 构造函数.prototype.方法名 进行添加;第二种为重定义构造函数的prototype,但是此种情况会丢失掉原有的constructor构造器,所以一定要再连接回去,例子如下:

    function Star(name) {
    	this.name = name;}Star.prototype = {
        dance:function(){
        	console.log("重定义prototype");
    	}}Star.prototype.constructor = Star;

    另外,类似于Array、String这些内置的类是不能这么处理的。

    五、继承

    这里就长话短说,首先我们要明确继承需要继承哪些东西,在前文中我们提到了定义构造函数的基本规则,即**公共属性定义到构造函数里面,公共方法我们放到原型对象身上。**我们所需要继承的东西也不外乎就这二者,公共属性的继承可以通过call()或者apply()进行this的指向定义,而公共方法可以通过原型对象的赋值进行处理,因此我们很容易想到如下的方法:

    //定义一个父类function Father(name) {
    	this.name = name;}Father.prototype.dance = function () {
    	console.log('I am dancing');};//定义一个子类function Son(name, age) {
    	Father.call(this, name);
    	this.age = age;}//通过赋值的方法连接Son.prototype = Father.prototype;//为子类添加方法Son.prototype.sing = function () {
    	console.log('I am singing');};
    	let son = new Son('小红', 100);
    	//此时父类也被影响了console.log(Father.prototype) 
    	//{dance: ƒ, sing: ƒ, constructor: ƒ}

    很显然,当我们只想修改子类里面的方法时,显然上述方法不太合适;因此 我们可以尝试new一个新的父类出来,代码如下:

    function Father(name) {
    	this.name = name;}Father.prototype.dance = function () {
    	console.log('I am dancing');};function Son(name, age) {
    	Father.call(this, name);
    	this.age = age;}Son.prototype = new Father();Son.prototype.sing = function () {
    	console.log('I am singing');};let son = new Son('小红', 100);console.log(Father.prototype) 
    	//{dance: ƒ, constructor: ƒ}

    六、class语法糖

    对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在es6里面新增了一个语法糖来更方便更便捷地书写继承,这里就直接上代码了;

    class Father {
    	constructor(name) {
    		this.name = name;
    	}
    	dance() {
    		console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在跳舞");
    	}}class Son extends Father {
    	constructor(name, age) {
    		super(name);
    		this.age = age;
    	}
    	sing() {
    		console.log("我是" + this.name + ",我今年" + this.age + "岁," + "我在唱歌");
    	}}let obj = new Son('小红', 19);
    	obj.sing();obj.dance();

    分析一下上面代码,首先一个类(构造函数)里面依旧为两部分,即公共属性和公共方法,constructor() 里面存放了该构造函数的公共属性,后面接着的便是公共方法,extends 关键字表示继承的是哪个类,super() 便是将里面父类里面相应的公共属性拿出来,这样看下来便可以将代码规整许多。

    相关推荐:javascript学习教程

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!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer