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.
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.
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
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.prototype
son.__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
因此我们可以总结一下定义构造函数的基本规则,即公共属性定义到构造函数里面,公共方法我们放到原型对象身上。
Father.prototype 就是原型,它是一个对象,也可以称为原型对象。
原型的作用,就是共享方法。
我们通过 Father.prototype.method
可以共享方法,不会反应开辟空间存储方法。
原型中this的指向是实例。
Une brève analyse de lhéritage JavaScript et de la chaîne de prototypes本人感觉是一个对于初学者或者说是部分前端菜鸡(例如本人)来说特别难以理解的东西,为了让下面的部分更容易理解,这里强行先记住以下几点:
__proto__
是每个对象都有的属性,prototype是每个函数特有的方法;__proto__
属性都会指向自身构造函数的prototype;Function.__proto__
=== Function.prototype;Object.prototype.__proto__
=== null 也就是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。
对象可以使用构造函数prototype原型对象的属性和方法,就是因为对象有__proto__
原型的存在每个对象都有__proto__
Father.call(this)
(4) Attribuez des valeurs aux nouvelles propriétés de l'objet son.name
( 5) Renvoie ceci renvoie ceci
A ce moment, le nouvel objet aura les méthodes et propriétés du constructeur
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 //验证上述说法中的第二条
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 viaFather.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 : 🎜__proto__
est un attribut de chaque objet, le prototype est une méthode unique à chaque fonction __proto__
pointera vers le prototype de son propre constructeur ; Function.__proto__ code> === Function.prototype;
Object.prototype.__proto__
=== null est la fin de la chaîne de prototypes ;__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;
//定义一个父类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: ƒ}
有两种添加方法,第一种为上面的写法,直接通过 构造函数.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: ƒ}
对于以前了解过面向对象编程的程序员来讲,上述关于继承的写法属实让人有些难以接受,因此在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!