Aprendiendo JavaScript, ¿cómo no puedes heredar prototipos?

herencia prototípica


Antes de ES6, JavaScript no tenía el concepto de clase, por lo que debe usar otros métodos para lograr la herencia, es decir, la herencia prototípica. (Recordatorio amistoso, si no sabe qué es un objeto prototipo, prototipo, etc., se recomienda averiguarlo primero (puede leer mi otro blog para comprender a fondo contenido es muy antipático)

Todos sabemos que cada objeto en JavaScript tiene un atributo [[Prototipo]] (llamado __proto__ en los navegadores), que apunta a su objeto prototipo, por lo que la forma más fácil de implementar la herencia es asignar directamente el punto [[Prototipo]] de un objeto a otro objeto

//方法1:直接指定对象的 __proto__ 属性(强烈不推荐)

//创建 Person 对象,具有 eat 和 run 的方法
var Person = {
    
    
    eat: function () {
    
    
        console.log(this.name + " 在吃饭");
    },

    run: function () {
    
    
        console.log(this.name + " 在跑步");
    }
}

//创建 Mike 对象,设置基本属性,具有 doHomework 的方法
var Mike = {
    
    
    name: "Mike",
    age: 15,
    grade: "8 年级",

    doHomework: function () {
    
    
        console.log(this.name + " 正在写 " + this.grade + "的作业");
    }
}

//我们让 Person 变为 Mike 的原型对象,注意只有支持 ES6 的浏览器才能这么写
Mike.__proto__ = Person;
Mike.eat();
Mike.run();
Mike.doHomework();

Resultados de la operación de la consola:

41

De hecho, es posible lograr la "herencia", pero no lo recomiendo, no solo por las restricciones del navegador, sino que el uso directo de __proto__ para modificar el objeto prototipo de un objeto puede causar problemas inesperados, por lo que el método anterior simplemente diviértase.


Si has leído el blog que escribí sobre objetos prototipo y cadenas de prototipos, debes saber que las funciones también se pueden usar para crear objetos en JavaScript.Veamos la segunda forma de escribir:

//Person 函数(作为构造函数),注意首字母大写
function Person(obj) {
    
    
}

//对 Person 函数的原型对象添加 eat 和 run 方法(我就不说明为什么这么写了)
Person.prototype.eat = function () {
    
    
    console.log(this.name + " 在吃饭");
}

Person.prototype.run = function () {
    
    
    console.log(this.name + " 在跑步");
}

//Teenager 函数(作为构造函数),设置 name、age、grade 属性
function Teenager(obj) {
    
    
    this.name = obj.name;
    this.age = obj.age;
    this.grade = obj.grade;
}

/* 重点来了,我们将 Teenager 函数的原型对象指向 Person 函数产生的实例对象,
   这个实例对象并没有任何的属性和方法,但是它的原型对象,也就是 Object,拥有 eat 和 run 方法
   毕竟我们一开始是使用 Person.prototype.方法名 的方式!*/
Teenager.prototype = new Person();

//然后再在 Teenager 的新原型对象上添加 doHomeWork 方法(所以实际上 Teenager 的原型对象只有这一个方法,其他的都在 Object 上)
Teenager.prototype.doHomeWork = function () {
    
    
    console.log(this.name + " 正在写 " + this.grade + "的作业");
}

//创建实例对象
var Mike = new Teenager({
    
    name: "Mike", age: 15, grade: "8 年级"});
Mike.eat();
Mike.run();
Mike.doHomeWork();

Resultados de la operación de la consola:

42


La "herencia" también se realiza. Usamos Teenager.prototype = new Person() para hacer que el objeto de instancia generado por la función Person se convierta en el objeto prototipo de Teenager, pero tenga en cuenta que este objeto prototipo no tiene un constructor. Después de todo, es es una instancia Entonces, esto en realidad no cumple con la definición de la cadena prototipo.


Entonces, ¿hay alguna manera de resolver este problema? Sí, sigamos actualizando el código (aquí también me refiero al tutorial de JavaScript del Sr. Liao Xuefeng):

//这回我们把 name 和 age 抽象到 Person 函数中
function Person(obj) {
    
    
    this.name = obj.name;
    this.age = obj.age;
}

//一样的步骤,不重复说明了
Person.prototype.eat = function () {
    
    
    console.log(this.name + " 在吃饭");
}

Person.prototype.run = function () {
    
    
    console.log(this.name + " 在跑步");
}

//请注意!新的点来了
function Teenager(obj) {
    
    
    //这句话的意思是调用 Person 函数,并且改变后续 this 的绑定,让 this 和实例对象(就是 = 左边的对象)绑定在一起
    Person.call(this, obj);
    this.grade = obj.grade;
}

//下面四句话才是重中之重!我们的思路是想要找到一个中介,作为 Teenager 和 Person 的桥梁,即达到继承的目的,又不破坏它们的原型对象和构造函数
//1、首先定义一个空函数
function F(){
    
    }

/* 2、然后将这个函数的原型对象指向 Person 函数的原型对象。这句话我们好好理解一下,Person 的原型对象除了有 eat 和 run 方法,
别忘了还有构造函数,那么当我们下次使用 new F() 的时候,本质上就是使用 Person.prototype.constructor(就是 Person()) */
F.prototype = Person.prototype;

//3、将 Teenager 的原型指向 F,而 F 又指向 Person,桥梁已经搭好了
Teenager.prototype = new F();

/* 4、最后将 Teenager 的原型对象的构造函数重新修改为 Teenager,
否则 Teenager.prototype.constructor === Person.prototype.constructor */
Teenager.prototype.constructor = Teenager;

//5、最后在 Teenager 的原型对象上定义方法
Teenager.prototype.doHomework = function () {
    
    
    console.log(this.name + " 正在写 " + this.grade + "的作业");
}

let Mike = new Teenager({
    
    name: "Mike", age: 15, grade: "8 年级"});
Mike.eat();
Mike.run();
Mike.doHomework();

Los resultados de salida de la consola (se cumplen todos los requisitos, esta es la herencia real del prototipo):

43



Eso es todo para la herencia de prototipos de JavaScript. Es realmente confuso. Cuando lo lea, debe comprender la relación entre funciones, objetos, objetos prototipo y constructores.

Supongo que te gusta

Origin blog.csdn.net/qq_52174675/article/details/122663494
Recomendado
Clasificación